1*1031c584SApple OSS Distributions /*
2*1031c584SApple OSS Distributions * Copyright (c) 2019 Apple Inc. All rights reserved.
3*1031c584SApple OSS Distributions *
4*1031c584SApple OSS Distributions * @APPLE_LICENSE_HEADER_START@
5*1031c584SApple OSS Distributions *
6*1031c584SApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*1031c584SApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*1031c584SApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*1031c584SApple OSS Distributions * compliance with the License. Please obtain a copy of the License at
10*1031c584SApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this
11*1031c584SApple OSS Distributions * file.
12*1031c584SApple OSS Distributions *
13*1031c584SApple OSS Distributions * The Original Code and all software distributed under the License are
14*1031c584SApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15*1031c584SApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16*1031c584SApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17*1031c584SApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18*1031c584SApple OSS Distributions * Please see the License for the specific language governing rights and
19*1031c584SApple OSS Distributions * limitations under the License.
20*1031c584SApple OSS Distributions *
21*1031c584SApple OSS Distributions * @APPLE_LICENSE_HEADER_END@
22*1031c584SApple OSS Distributions */
23*1031c584SApple OSS Distributions
24*1031c584SApple OSS Distributions /*-
25*1031c584SApple OSS Distributions * Portions Copyright (c) 1992, 1993, 1995
26*1031c584SApple OSS Distributions * The Regents of the University of California. All rights reserved.
27*1031c584SApple OSS Distributions *
28*1031c584SApple OSS Distributions * This code is derived from software donated to Berkeley by
29*1031c584SApple OSS Distributions * Jan-Simon Pendry.
30*1031c584SApple OSS Distributions *
31*1031c584SApple OSS Distributions * Redistribution and use in source and binary forms, with or without
32*1031c584SApple OSS Distributions * modification, are permitted provided that the following conditions
33*1031c584SApple OSS Distributions * are met:
34*1031c584SApple OSS Distributions * 1. Redistributions of source code must retain the above copyright
35*1031c584SApple OSS Distributions * notice, this list of conditions and the following disclaimer.
36*1031c584SApple OSS Distributions * 2. Redistributions in binary form must reproduce the above copyright
37*1031c584SApple OSS Distributions * notice, this list of conditions and the following disclaimer in the
38*1031c584SApple OSS Distributions * documentation and/or other materials provided with the distribution.
39*1031c584SApple OSS Distributions * 4. Neither the name of the University nor the names of its contributors
40*1031c584SApple OSS Distributions * may be used to endorse or promote products derived from this software
41*1031c584SApple OSS Distributions * without specific prior written permission.
42*1031c584SApple OSS Distributions *
43*1031c584SApple OSS Distributions * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44*1031c584SApple OSS Distributions * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45*1031c584SApple OSS Distributions * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46*1031c584SApple OSS Distributions * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47*1031c584SApple OSS Distributions * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48*1031c584SApple OSS Distributions * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49*1031c584SApple OSS Distributions * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50*1031c584SApple OSS Distributions * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51*1031c584SApple OSS Distributions * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52*1031c584SApple OSS Distributions * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53*1031c584SApple OSS Distributions * SUCH DAMAGE.
54*1031c584SApple OSS Distributions *
55*1031c584SApple OSS Distributions * @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94
56*1031c584SApple OSS Distributions *
57*1031c584SApple OSS Distributions * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92
58*1031c584SApple OSS Distributions * $FreeBSD$
59*1031c584SApple OSS Distributions */
60*1031c584SApple OSS Distributions
61*1031c584SApple OSS Distributions #include <sys/param.h>
62*1031c584SApple OSS Distributions #include <sys/systm.h>
63*1031c584SApple OSS Distributions #include <sys/fcntl.h>
64*1031c584SApple OSS Distributions #include <sys/kernel.h>
65*1031c584SApple OSS Distributions #include <sys/lock.h>
66*1031c584SApple OSS Distributions #include <sys/malloc.h>
67*1031c584SApple OSS Distributions #include <sys/mount.h>
68*1031c584SApple OSS Distributions #include <sys/namei.h>
69*1031c584SApple OSS Distributions #include <sys/proc.h>
70*1031c584SApple OSS Distributions #include <sys/vnode.h>
71*1031c584SApple OSS Distributions #include <sys/vnode_internal.h>
72*1031c584SApple OSS Distributions #include <security/mac_internal.h>
73*1031c584SApple OSS Distributions #include <sys/kauth.h>
74*1031c584SApple OSS Distributions
75*1031c584SApple OSS Distributions #include <sys/param.h>
76*1031c584SApple OSS Distributions
77*1031c584SApple OSS Distributions #include <IOKit/IOBSD.h>
78*1031c584SApple OSS Distributions
79*1031c584SApple OSS Distributions #include "nullfs.h"
80*1031c584SApple OSS Distributions
81*1031c584SApple OSS Distributions #define NULLFS_ENTITLEMENT "com.apple.private.nullfs_allow"
82*1031c584SApple OSS Distributions
83*1031c584SApple OSS Distributions #define SIZEOF_MEMBER(type, member) (sizeof(((type *)0)->member))
84*1031c584SApple OSS Distributions #define MAX_MNT_FROM_LENGTH (SIZEOF_MEMBER(struct vfsstatfs, f_mntfromname))
85*1031c584SApple OSS Distributions
86*1031c584SApple OSS Distributions static int
nullfs_vfs_getlowerattr(mount_t mp,struct vfs_attr * vfap,vfs_context_t ctx)87*1031c584SApple OSS Distributions nullfs_vfs_getlowerattr(mount_t mp, struct vfs_attr * vfap, vfs_context_t ctx)
88*1031c584SApple OSS Distributions {
89*1031c584SApple OSS Distributions memset(vfap, 0, sizeof(*vfap));
90*1031c584SApple OSS Distributions VFSATTR_INIT(vfap);
91*1031c584SApple OSS Distributions VFSATTR_WANTED(vfap, f_bsize);
92*1031c584SApple OSS Distributions VFSATTR_WANTED(vfap, f_iosize);
93*1031c584SApple OSS Distributions VFSATTR_WANTED(vfap, f_blocks);
94*1031c584SApple OSS Distributions VFSATTR_WANTED(vfap, f_bfree);
95*1031c584SApple OSS Distributions VFSATTR_WANTED(vfap, f_bavail);
96*1031c584SApple OSS Distributions VFSATTR_WANTED(vfap, f_bused);
97*1031c584SApple OSS Distributions VFSATTR_WANTED(vfap, f_files);
98*1031c584SApple OSS Distributions VFSATTR_WANTED(vfap, f_ffree);
99*1031c584SApple OSS Distributions VFSATTR_WANTED(vfap, f_capabilities);
100*1031c584SApple OSS Distributions
101*1031c584SApple OSS Distributions return vfs_getattr(mp, vfap, ctx);
102*1031c584SApple OSS Distributions }
103*1031c584SApple OSS Distributions
104*1031c584SApple OSS Distributions /*
105*1031c584SApple OSS Distributions * Mount null layer
106*1031c584SApple OSS Distributions */
107*1031c584SApple OSS Distributions static int
nullfs_mount(struct mount * mp,__unused vnode_t devvp,user_addr_t user_data,vfs_context_t ctx)108*1031c584SApple OSS Distributions nullfs_mount(struct mount * mp, __unused vnode_t devvp, user_addr_t user_data, vfs_context_t ctx)
109*1031c584SApple OSS Distributions {
110*1031c584SApple OSS Distributions int error = 0;
111*1031c584SApple OSS Distributions struct vnode *lowerrootvp = NULL, *vp = NULL;
112*1031c584SApple OSS Distributions struct vfsstatfs * sp = NULL;
113*1031c584SApple OSS Distributions struct null_mount * xmp = NULL;
114*1031c584SApple OSS Distributions struct null_mount_conf conf = {0};
115*1031c584SApple OSS Distributions char path[MAXPATHLEN];
116*1031c584SApple OSS Distributions
117*1031c584SApple OSS Distributions size_t count;
118*1031c584SApple OSS Distributions struct vfs_attr vfa;
119*1031c584SApple OSS Distributions /* set defaults (arbitrary since this file system is readonly) */
120*1031c584SApple OSS Distributions uint32_t bsize = BLKDEV_IOSIZE;
121*1031c584SApple OSS Distributions size_t iosize = BLKDEV_IOSIZE;
122*1031c584SApple OSS Distributions uint64_t blocks = 4711 * 4711;
123*1031c584SApple OSS Distributions uint64_t bfree = 0;
124*1031c584SApple OSS Distributions uint64_t bavail = 0;
125*1031c584SApple OSS Distributions uint64_t bused = 4711;
126*1031c584SApple OSS Distributions uint64_t files = 4711;
127*1031c584SApple OSS Distributions uint64_t ffree = 0;
128*1031c584SApple OSS Distributions
129*1031c584SApple OSS Distributions kauth_cred_t cred = vfs_context_ucred(ctx);
130*1031c584SApple OSS Distributions
131*1031c584SApple OSS Distributions NULLFSDEBUG("nullfs_mount(mp = %p) %llx\n", (void *)mp, vfs_flags(mp));
132*1031c584SApple OSS Distributions
133*1031c584SApple OSS Distributions if (vfs_flags(mp) & MNT_ROOTFS) {
134*1031c584SApple OSS Distributions return EOPNOTSUPP;
135*1031c584SApple OSS Distributions }
136*1031c584SApple OSS Distributions
137*1031c584SApple OSS Distributions /*
138*1031c584SApple OSS Distributions * Update is a no-op
139*1031c584SApple OSS Distributions */
140*1031c584SApple OSS Distributions if (vfs_isupdate(mp)) {
141*1031c584SApple OSS Distributions return ENOTSUP;
142*1031c584SApple OSS Distributions }
143*1031c584SApple OSS Distributions
144*1031c584SApple OSS Distributions /* check entitlement */
145*1031c584SApple OSS Distributions if (!IOCurrentTaskHasEntitlement(NULLFS_ENTITLEMENT)) {
146*1031c584SApple OSS Distributions return EPERM;
147*1031c584SApple OSS Distributions }
148*1031c584SApple OSS Distributions
149*1031c584SApple OSS Distributions /*
150*1031c584SApple OSS Distributions * Get configuration
151*1031c584SApple OSS Distributions */
152*1031c584SApple OSS Distributions error = copyin(user_data, &conf, sizeof(conf));
153*1031c584SApple OSS Distributions if (error) {
154*1031c584SApple OSS Distributions NULLFSDEBUG("nullfs: error copying configuration form user %d\n", error);
155*1031c584SApple OSS Distributions goto error;
156*1031c584SApple OSS Distributions }
157*1031c584SApple OSS Distributions
158*1031c584SApple OSS Distributions /*
159*1031c584SApple OSS Distributions * Get argument
160*1031c584SApple OSS Distributions */
161*1031c584SApple OSS Distributions error = copyinstr(user_data + sizeof(conf), path, MAXPATHLEN - 1, &count);
162*1031c584SApple OSS Distributions if (error) {
163*1031c584SApple OSS Distributions NULLFSDEBUG("nullfs: error copying data form user %d\n", error);
164*1031c584SApple OSS Distributions goto error;
165*1031c584SApple OSS Distributions }
166*1031c584SApple OSS Distributions
167*1031c584SApple OSS Distributions /* This could happen if the system is configured for 32 bit inodes instead of
168*1031c584SApple OSS Distributions * 64 bit */
169*1031c584SApple OSS Distributions if (count > MAX_MNT_FROM_LENGTH) {
170*1031c584SApple OSS Distributions error = EINVAL;
171*1031c584SApple OSS Distributions NULLFSDEBUG("nullfs: path to translocate too large for this system %ld vs %ld\n", count, MAX_MNT_FROM_LENGTH);
172*1031c584SApple OSS Distributions goto error;
173*1031c584SApple OSS Distributions }
174*1031c584SApple OSS Distributions
175*1031c584SApple OSS Distributions error = vnode_lookup(path, 0, &lowerrootvp, ctx);
176*1031c584SApple OSS Distributions if (error) {
177*1031c584SApple OSS Distributions NULLFSDEBUG("lookup %s -> %d\n", path, error);
178*1031c584SApple OSS Distributions goto error;
179*1031c584SApple OSS Distributions }
180*1031c584SApple OSS Distributions
181*1031c584SApple OSS Distributions /* lowervrootvp has an iocount after vnode_lookup, drop that for a usecount.
182*1031c584SApple OSS Distributions * Keep this to signal what we want to keep around the thing we are mirroring.
183*1031c584SApple OSS Distributions * Drop it in unmount.*/
184*1031c584SApple OSS Distributions error = vnode_ref(lowerrootvp);
185*1031c584SApple OSS Distributions vnode_put(lowerrootvp);
186*1031c584SApple OSS Distributions if (error) {
187*1031c584SApple OSS Distributions // If vnode_ref failed, then null it out so it can't be used anymore in cleanup.
188*1031c584SApple OSS Distributions lowerrootvp = NULL;
189*1031c584SApple OSS Distributions goto error;
190*1031c584SApple OSS Distributions }
191*1031c584SApple OSS Distributions
192*1031c584SApple OSS Distributions NULLFSDEBUG("mount %s\n", path);
193*1031c584SApple OSS Distributions
194*1031c584SApple OSS Distributions xmp = kalloc_type(struct null_mount, Z_WAITOK | Z_ZERO | Z_NOFAIL);
195*1031c584SApple OSS Distributions
196*1031c584SApple OSS Distributions /*
197*1031c584SApple OSS Distributions * Grab the uid/gid of the caller, which may be used for unveil later
198*1031c584SApple OSS Distributions */
199*1031c584SApple OSS Distributions xmp->uid = kauth_cred_getuid(cred);
200*1031c584SApple OSS Distributions xmp->gid = kauth_cred_getgid(cred);
201*1031c584SApple OSS Distributions
202*1031c584SApple OSS Distributions /*
203*1031c584SApple OSS Distributions * Save reference to underlying FS
204*1031c584SApple OSS Distributions */
205*1031c584SApple OSS Distributions xmp->nullm_lowerrootvp = lowerrootvp;
206*1031c584SApple OSS Distributions xmp->nullm_lowerrootvid = vnode_vid(lowerrootvp);
207*1031c584SApple OSS Distributions
208*1031c584SApple OSS Distributions error = null_getnewvnode(mp, NULL, NULL, &vp, NULL, 1);
209*1031c584SApple OSS Distributions if (error) {
210*1031c584SApple OSS Distributions goto error;
211*1031c584SApple OSS Distributions }
212*1031c584SApple OSS Distributions
213*1031c584SApple OSS Distributions /* vp has an iocount on it from vnode_create. drop that for a usecount. This
214*1031c584SApple OSS Distributions * is our root vnode so we drop the ref in unmount
215*1031c584SApple OSS Distributions *
216*1031c584SApple OSS Distributions * Assuming for now that because we created this vnode and we aren't finished mounting we can get a ref*/
217*1031c584SApple OSS Distributions vnode_ref(vp);
218*1031c584SApple OSS Distributions vnode_put(vp);
219*1031c584SApple OSS Distributions
220*1031c584SApple OSS Distributions nullfs_init_lck(&xmp->nullm_lock);
221*1031c584SApple OSS Distributions
222*1031c584SApple OSS Distributions xmp->nullm_rootvp = vp;
223*1031c584SApple OSS Distributions
224*1031c584SApple OSS Distributions /* read the flags the user set, but then ignore some of them, we will only
225*1031c584SApple OSS Distributions * allow them if they are set on the lower file system */
226*1031c584SApple OSS Distributions uint64_t flags = vfs_flags(mp) & (~(MNT_IGNORE_OWNERSHIP | MNT_LOCAL));
227*1031c584SApple OSS Distributions uint64_t lowerflags = vfs_flags(vnode_mount(lowerrootvp)) & (MNT_LOCAL | MNT_QUARANTINE | MNT_IGNORE_OWNERSHIP | MNT_NOEXEC);
228*1031c584SApple OSS Distributions
229*1031c584SApple OSS Distributions if (lowerflags) {
230*1031c584SApple OSS Distributions flags |= lowerflags;
231*1031c584SApple OSS Distributions }
232*1031c584SApple OSS Distributions
233*1031c584SApple OSS Distributions /* force these flags */
234*1031c584SApple OSS Distributions flags |= (MNT_DONTBROWSE | MNT_MULTILABEL | MNT_NOSUID | MNT_RDONLY);
235*1031c584SApple OSS Distributions vfs_setflags(mp, flags);
236*1031c584SApple OSS Distributions
237*1031c584SApple OSS Distributions vfs_setfsprivate(mp, xmp);
238*1031c584SApple OSS Distributions vfs_getnewfsid(mp);
239*1031c584SApple OSS Distributions vfs_setlocklocal(mp);
240*1031c584SApple OSS Distributions
241*1031c584SApple OSS Distributions /* fill in the stat block */
242*1031c584SApple OSS Distributions sp = vfs_statfs(mp);
243*1031c584SApple OSS Distributions strlcpy(sp->f_mntfromname, path, MAX_MNT_FROM_LENGTH);
244*1031c584SApple OSS Distributions
245*1031c584SApple OSS Distributions sp->f_flags = flags;
246*1031c584SApple OSS Distributions
247*1031c584SApple OSS Distributions xmp->nullm_flags = NULLM_CASEINSENSITIVE; /* default to case insensitive */
248*1031c584SApple OSS Distributions
249*1031c584SApple OSS Distributions // Set the flags that are requested
250*1031c584SApple OSS Distributions xmp->nullm_flags |= conf.flags & NULLM_UNVEIL;
251*1031c584SApple OSS Distributions
252*1031c584SApple OSS Distributions error = nullfs_vfs_getlowerattr(vnode_mount(lowerrootvp), &vfa, ctx);
253*1031c584SApple OSS Distributions if (error == 0) {
254*1031c584SApple OSS Distributions if (VFSATTR_IS_SUPPORTED(&vfa, f_bsize)) {
255*1031c584SApple OSS Distributions bsize = vfa.f_bsize;
256*1031c584SApple OSS Distributions }
257*1031c584SApple OSS Distributions if (VFSATTR_IS_SUPPORTED(&vfa, f_iosize)) {
258*1031c584SApple OSS Distributions iosize = vfa.f_iosize;
259*1031c584SApple OSS Distributions }
260*1031c584SApple OSS Distributions if (VFSATTR_IS_SUPPORTED(&vfa, f_blocks)) {
261*1031c584SApple OSS Distributions blocks = vfa.f_blocks;
262*1031c584SApple OSS Distributions }
263*1031c584SApple OSS Distributions if (VFSATTR_IS_SUPPORTED(&vfa, f_bfree)) {
264*1031c584SApple OSS Distributions bfree = vfa.f_bfree;
265*1031c584SApple OSS Distributions }
266*1031c584SApple OSS Distributions if (VFSATTR_IS_SUPPORTED(&vfa, f_bavail)) {
267*1031c584SApple OSS Distributions bavail = vfa.f_bavail;
268*1031c584SApple OSS Distributions }
269*1031c584SApple OSS Distributions if (VFSATTR_IS_SUPPORTED(&vfa, f_bused)) {
270*1031c584SApple OSS Distributions bused = vfa.f_bused;
271*1031c584SApple OSS Distributions }
272*1031c584SApple OSS Distributions if (VFSATTR_IS_SUPPORTED(&vfa, f_files)) {
273*1031c584SApple OSS Distributions files = vfa.f_files;
274*1031c584SApple OSS Distributions }
275*1031c584SApple OSS Distributions if (VFSATTR_IS_SUPPORTED(&vfa, f_ffree)) {
276*1031c584SApple OSS Distributions ffree = vfa.f_ffree;
277*1031c584SApple OSS Distributions }
278*1031c584SApple OSS Distributions if (VFSATTR_IS_SUPPORTED(&vfa, f_capabilities)) {
279*1031c584SApple OSS Distributions if ((vfa.f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] & (VOL_CAP_FMT_CASE_SENSITIVE)) &&
280*1031c584SApple OSS Distributions (vfa.f_capabilities.valid[VOL_CAPABILITIES_FORMAT] & (VOL_CAP_FMT_CASE_SENSITIVE))) {
281*1031c584SApple OSS Distributions xmp->nullm_flags &= ~NULLM_CASEINSENSITIVE;
282*1031c584SApple OSS Distributions }
283*1031c584SApple OSS Distributions }
284*1031c584SApple OSS Distributions } else {
285*1031c584SApple OSS Distributions goto error;
286*1031c584SApple OSS Distributions }
287*1031c584SApple OSS Distributions
288*1031c584SApple OSS Distributions sp->f_bsize = bsize;
289*1031c584SApple OSS Distributions sp->f_iosize = iosize;
290*1031c584SApple OSS Distributions sp->f_blocks = blocks;
291*1031c584SApple OSS Distributions sp->f_bfree = bfree;
292*1031c584SApple OSS Distributions sp->f_bavail = bavail;
293*1031c584SApple OSS Distributions sp->f_bused = bused;
294*1031c584SApple OSS Distributions sp->f_files = files;
295*1031c584SApple OSS Distributions sp->f_ffree = ffree;
296*1031c584SApple OSS Distributions
297*1031c584SApple OSS Distributions /* Associate the mac label information from the mirrored filesystem with the
298*1031c584SApple OSS Distributions * mirror */
299*1031c584SApple OSS Distributions MAC_PERFORM(mount_label_associate, cred, vnode_mount(lowerrootvp), vfs_mntlabel(mp));
300*1031c584SApple OSS Distributions
301*1031c584SApple OSS Distributions NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n", sp->f_mntfromname, sp->f_mntonname);
302*1031c584SApple OSS Distributions return 0;
303*1031c584SApple OSS Distributions
304*1031c584SApple OSS Distributions error:
305*1031c584SApple OSS Distributions if (xmp) {
306*1031c584SApple OSS Distributions kfree_type(struct null_mount, xmp);
307*1031c584SApple OSS Distributions }
308*1031c584SApple OSS Distributions if (lowerrootvp) {
309*1031c584SApple OSS Distributions vnode_getwithref(lowerrootvp);
310*1031c584SApple OSS Distributions vnode_rele(lowerrootvp);
311*1031c584SApple OSS Distributions vnode_put(lowerrootvp);
312*1031c584SApple OSS Distributions }
313*1031c584SApple OSS Distributions if (vp) {
314*1031c584SApple OSS Distributions /* we made the root vnode but the mount is failed, so clean it up */
315*1031c584SApple OSS Distributions vnode_getwithref(vp);
316*1031c584SApple OSS Distributions vnode_rele(vp);
317*1031c584SApple OSS Distributions /* give vp back */
318*1031c584SApple OSS Distributions vnode_recycle(vp);
319*1031c584SApple OSS Distributions vnode_put(vp);
320*1031c584SApple OSS Distributions }
321*1031c584SApple OSS Distributions return error;
322*1031c584SApple OSS Distributions }
323*1031c584SApple OSS Distributions
324*1031c584SApple OSS Distributions /*
325*1031c584SApple OSS Distributions * Free reference to null layer
326*1031c584SApple OSS Distributions */
327*1031c584SApple OSS Distributions static int
nullfs_unmount(struct mount * mp,int mntflags,__unused vfs_context_t ctx)328*1031c584SApple OSS Distributions nullfs_unmount(struct mount * mp, int mntflags, __unused vfs_context_t ctx)
329*1031c584SApple OSS Distributions {
330*1031c584SApple OSS Distributions struct null_mount * mntdata;
331*1031c584SApple OSS Distributions struct vnode * vp;
332*1031c584SApple OSS Distributions int error, flags;
333*1031c584SApple OSS Distributions
334*1031c584SApple OSS Distributions NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp);
335*1031c584SApple OSS Distributions
336*1031c584SApple OSS Distributions /* check entitlement or superuser*/
337*1031c584SApple OSS Distributions if (!IOCurrentTaskHasEntitlement(NULLFS_ENTITLEMENT) &&
338*1031c584SApple OSS Distributions vfs_context_suser(ctx) != 0) {
339*1031c584SApple OSS Distributions return EPERM;
340*1031c584SApple OSS Distributions }
341*1031c584SApple OSS Distributions
342*1031c584SApple OSS Distributions if (mntflags & MNT_FORCE) {
343*1031c584SApple OSS Distributions flags = FORCECLOSE;
344*1031c584SApple OSS Distributions } else {
345*1031c584SApple OSS Distributions flags = 0;
346*1031c584SApple OSS Distributions }
347*1031c584SApple OSS Distributions
348*1031c584SApple OSS Distributions mntdata = MOUNTTONULLMOUNT(mp);
349*1031c584SApple OSS Distributions vp = mntdata->nullm_rootvp;
350*1031c584SApple OSS Distributions
351*1031c584SApple OSS Distributions // release our reference on the root before flushing.
352*1031c584SApple OSS Distributions // it will get pulled out of the mount structure by reclaim
353*1031c584SApple OSS Distributions vnode_getalways(vp);
354*1031c584SApple OSS Distributions
355*1031c584SApple OSS Distributions error = vflush(mp, vp, flags);
356*1031c584SApple OSS Distributions if (error) {
357*1031c584SApple OSS Distributions vnode_put(vp);
358*1031c584SApple OSS Distributions return error;
359*1031c584SApple OSS Distributions }
360*1031c584SApple OSS Distributions
361*1031c584SApple OSS Distributions if (vnode_isinuse(vp, 1) && flags == 0) {
362*1031c584SApple OSS Distributions vnode_put(vp);
363*1031c584SApple OSS Distributions return EBUSY;
364*1031c584SApple OSS Distributions }
365*1031c584SApple OSS Distributions
366*1031c584SApple OSS Distributions vnode_rele(vp); // Drop reference taken by nullfs_mount
367*1031c584SApple OSS Distributions vnode_put(vp); // Drop ref taken above
368*1031c584SApple OSS Distributions
369*1031c584SApple OSS Distributions //Force close to get rid of the last vnode
370*1031c584SApple OSS Distributions (void)vflush(mp, NULL, FORCECLOSE);
371*1031c584SApple OSS Distributions
372*1031c584SApple OSS Distributions /* no more vnodes, so tear down the mountpoint */
373*1031c584SApple OSS Distributions
374*1031c584SApple OSS Distributions lck_mtx_lock(&mntdata->nullm_lock);
375*1031c584SApple OSS Distributions
376*1031c584SApple OSS Distributions vfs_setfsprivate(mp, NULL);
377*1031c584SApple OSS Distributions
378*1031c584SApple OSS Distributions vnode_getalways(mntdata->nullm_lowerrootvp);
379*1031c584SApple OSS Distributions vnode_rele(mntdata->nullm_lowerrootvp);
380*1031c584SApple OSS Distributions vnode_put(mntdata->nullm_lowerrootvp);
381*1031c584SApple OSS Distributions
382*1031c584SApple OSS Distributions lck_mtx_unlock(&mntdata->nullm_lock);
383*1031c584SApple OSS Distributions
384*1031c584SApple OSS Distributions nullfs_destroy_lck(&mntdata->nullm_lock);
385*1031c584SApple OSS Distributions
386*1031c584SApple OSS Distributions kfree_type(struct null_mount, mntdata);
387*1031c584SApple OSS Distributions
388*1031c584SApple OSS Distributions uint64_t vflags = vfs_flags(mp);
389*1031c584SApple OSS Distributions vfs_setflags(mp, vflags & ~MNT_LOCAL);
390*1031c584SApple OSS Distributions
391*1031c584SApple OSS Distributions return 0;
392*1031c584SApple OSS Distributions }
393*1031c584SApple OSS Distributions
394*1031c584SApple OSS Distributions static int
nullfs_root(struct mount * mp,struct vnode ** vpp,__unused vfs_context_t ctx)395*1031c584SApple OSS Distributions nullfs_root(struct mount * mp, struct vnode ** vpp, __unused vfs_context_t ctx)
396*1031c584SApple OSS Distributions {
397*1031c584SApple OSS Distributions struct vnode * vp;
398*1031c584SApple OSS Distributions int error;
399*1031c584SApple OSS Distributions
400*1031c584SApple OSS Distributions NULLFSDEBUG("nullfs_root(mp = %p, vp = %p)\n", (void *)mp, (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp);
401*1031c584SApple OSS Distributions
402*1031c584SApple OSS Distributions /*
403*1031c584SApple OSS Distributions * Return locked reference to root.
404*1031c584SApple OSS Distributions */
405*1031c584SApple OSS Distributions vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
406*1031c584SApple OSS Distributions
407*1031c584SApple OSS Distributions error = vnode_get(vp);
408*1031c584SApple OSS Distributions if (error) {
409*1031c584SApple OSS Distributions return error;
410*1031c584SApple OSS Distributions }
411*1031c584SApple OSS Distributions
412*1031c584SApple OSS Distributions *vpp = vp;
413*1031c584SApple OSS Distributions return 0;
414*1031c584SApple OSS Distributions }
415*1031c584SApple OSS Distributions
416*1031c584SApple OSS Distributions static int
nullfs_vfs_getattr(struct mount * mp,struct vfs_attr * vfap,vfs_context_t ctx)417*1031c584SApple OSS Distributions nullfs_vfs_getattr(struct mount * mp, struct vfs_attr * vfap, vfs_context_t ctx)
418*1031c584SApple OSS Distributions {
419*1031c584SApple OSS Distributions struct vnode * coveredvp = NULL;
420*1031c584SApple OSS Distributions struct vfs_attr vfa;
421*1031c584SApple OSS Distributions struct null_mount * null_mp = MOUNTTONULLMOUNT(mp);
422*1031c584SApple OSS Distributions vol_capabilities_attr_t capabilities;
423*1031c584SApple OSS Distributions struct vfsstatfs * sp = vfs_statfs(mp);
424*1031c584SApple OSS Distributions vfs_context_t ectx = nullfs_get_patched_context(null_mp, ctx);
425*1031c584SApple OSS Distributions
426*1031c584SApple OSS Distributions struct timespec tzero = {.tv_sec = 0, .tv_nsec = 0};
427*1031c584SApple OSS Distributions
428*1031c584SApple OSS Distributions NULLFSDEBUG("%s\n", __FUNCTION__);
429*1031c584SApple OSS Distributions
430*1031c584SApple OSS Distributions /* Set default capabilities in case the lower file system is gone */
431*1031c584SApple OSS Distributions memset(&capabilities, 0, sizeof(capabilities));
432*1031c584SApple OSS Distributions capabilities.capabilities[VOL_CAPABILITIES_FORMAT] = VOL_CAP_FMT_FAST_STATFS | VOL_CAP_FMT_HIDDEN_FILES;
433*1031c584SApple OSS Distributions capabilities.valid[VOL_CAPABILITIES_FORMAT] = VOL_CAP_FMT_FAST_STATFS | VOL_CAP_FMT_HIDDEN_FILES;
434*1031c584SApple OSS Distributions
435*1031c584SApple OSS Distributions if (nullfs_vfs_getlowerattr(vnode_mount(null_mp->nullm_lowerrootvp), &vfa, ectx) == 0) {
436*1031c584SApple OSS Distributions if (VFSATTR_IS_SUPPORTED(&vfa, f_capabilities)) {
437*1031c584SApple OSS Distributions memcpy(&capabilities, &vfa.f_capabilities, sizeof(capabilities));
438*1031c584SApple OSS Distributions /* don't support vget */
439*1031c584SApple OSS Distributions capabilities.capabilities[VOL_CAPABILITIES_FORMAT] &= ~(VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_PATH_FROM_ID);
440*1031c584SApple OSS Distributions
441*1031c584SApple OSS Distributions capabilities.capabilities[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_HIDDEN_FILES; /* Always support UF_HIDDEN */
442*1031c584SApple OSS Distributions
443*1031c584SApple OSS Distributions capabilities.valid[VOL_CAPABILITIES_FORMAT] &= ~(VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_PATH_FROM_ID);
444*1031c584SApple OSS Distributions
445*1031c584SApple OSS Distributions capabilities.valid[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_HIDDEN_FILES; /* Always support UF_HIDDEN */
446*1031c584SApple OSS Distributions
447*1031c584SApple OSS Distributions /* dont' support interfaces that only make sense on a writable file system
448*1031c584SApple OSS Distributions * or one with specific vnops implemented */
449*1031c584SApple OSS Distributions capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] = 0;
450*1031c584SApple OSS Distributions
451*1031c584SApple OSS Distributions capabilities.valid[VOL_CAPABILITIES_INTERFACES] &=
452*1031c584SApple OSS Distributions ~(VOL_CAP_INT_SEARCHFS | VOL_CAP_INT_ATTRLIST | VOL_CAP_INT_READDIRATTR | VOL_CAP_INT_EXCHANGEDATA |
453*1031c584SApple OSS Distributions VOL_CAP_INT_COPYFILE | VOL_CAP_INT_ALLOCATE | VOL_CAP_INT_VOL_RENAME | VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK);
454*1031c584SApple OSS Distributions }
455*1031c584SApple OSS Distributions }
456*1031c584SApple OSS Distributions
457*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_create_time)) {
458*1031c584SApple OSS Distributions VFSATTR_RETURN(vfap, f_create_time, tzero);
459*1031c584SApple OSS Distributions }
460*1031c584SApple OSS Distributions
461*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_modify_time)) {
462*1031c584SApple OSS Distributions VFSATTR_RETURN(vfap, f_modify_time, tzero);
463*1031c584SApple OSS Distributions }
464*1031c584SApple OSS Distributions
465*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_access_time)) {
466*1031c584SApple OSS Distributions VFSATTR_RETURN(vfap, f_access_time, tzero);
467*1031c584SApple OSS Distributions }
468*1031c584SApple OSS Distributions
469*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_bsize)) {
470*1031c584SApple OSS Distributions VFSATTR_RETURN(vfap, f_bsize, sp->f_bsize);
471*1031c584SApple OSS Distributions }
472*1031c584SApple OSS Distributions
473*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_iosize)) {
474*1031c584SApple OSS Distributions VFSATTR_RETURN(vfap, f_iosize, sp->f_iosize);
475*1031c584SApple OSS Distributions }
476*1031c584SApple OSS Distributions
477*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_owner)) {
478*1031c584SApple OSS Distributions VFSATTR_RETURN(vfap, f_owner, 0);
479*1031c584SApple OSS Distributions }
480*1031c584SApple OSS Distributions
481*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_blocks)) {
482*1031c584SApple OSS Distributions VFSATTR_RETURN(vfap, f_blocks, sp->f_blocks);
483*1031c584SApple OSS Distributions }
484*1031c584SApple OSS Distributions
485*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_bfree)) {
486*1031c584SApple OSS Distributions VFSATTR_RETURN(vfap, f_bfree, sp->f_bfree);
487*1031c584SApple OSS Distributions }
488*1031c584SApple OSS Distributions
489*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_bavail)) {
490*1031c584SApple OSS Distributions VFSATTR_RETURN(vfap, f_bavail, sp->f_bavail);
491*1031c584SApple OSS Distributions }
492*1031c584SApple OSS Distributions
493*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_bused)) {
494*1031c584SApple OSS Distributions VFSATTR_RETURN(vfap, f_bused, sp->f_bused);
495*1031c584SApple OSS Distributions }
496*1031c584SApple OSS Distributions
497*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_files)) {
498*1031c584SApple OSS Distributions VFSATTR_RETURN(vfap, f_files, sp->f_files);
499*1031c584SApple OSS Distributions }
500*1031c584SApple OSS Distributions
501*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_ffree)) {
502*1031c584SApple OSS Distributions VFSATTR_RETURN(vfap, f_ffree, sp->f_ffree);
503*1031c584SApple OSS Distributions }
504*1031c584SApple OSS Distributions
505*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_fssubtype)) {
506*1031c584SApple OSS Distributions VFSATTR_RETURN(vfap, f_fssubtype, 0);
507*1031c584SApple OSS Distributions }
508*1031c584SApple OSS Distributions
509*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_capabilities)) {
510*1031c584SApple OSS Distributions memcpy(&vfap->f_capabilities, &capabilities, sizeof(vol_capabilities_attr_t));
511*1031c584SApple OSS Distributions
512*1031c584SApple OSS Distributions VFSATTR_SET_SUPPORTED(vfap, f_capabilities);
513*1031c584SApple OSS Distributions }
514*1031c584SApple OSS Distributions
515*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_attributes)) {
516*1031c584SApple OSS Distributions vol_attributes_attr_t * volattr = &vfap->f_attributes;
517*1031c584SApple OSS Distributions
518*1031c584SApple OSS Distributions volattr->validattr.commonattr = 0;
519*1031c584SApple OSS Distributions volattr->validattr.volattr = ATTR_VOL_NAME | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES;
520*1031c584SApple OSS Distributions volattr->validattr.dirattr = 0;
521*1031c584SApple OSS Distributions volattr->validattr.fileattr = 0;
522*1031c584SApple OSS Distributions volattr->validattr.forkattr = 0;
523*1031c584SApple OSS Distributions
524*1031c584SApple OSS Distributions volattr->nativeattr.commonattr = 0;
525*1031c584SApple OSS Distributions volattr->nativeattr.volattr = ATTR_VOL_NAME | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES;
526*1031c584SApple OSS Distributions volattr->nativeattr.dirattr = 0;
527*1031c584SApple OSS Distributions volattr->nativeattr.fileattr = 0;
528*1031c584SApple OSS Distributions volattr->nativeattr.forkattr = 0;
529*1031c584SApple OSS Distributions
530*1031c584SApple OSS Distributions VFSATTR_SET_SUPPORTED(vfap, f_attributes);
531*1031c584SApple OSS Distributions }
532*1031c584SApple OSS Distributions
533*1031c584SApple OSS Distributions if (VFSATTR_IS_ACTIVE(vfap, f_vol_name)) {
534*1031c584SApple OSS Distributions /* The name of the volume is the same as the directory we mounted on */
535*1031c584SApple OSS Distributions coveredvp = vfs_vnodecovered(mp);
536*1031c584SApple OSS Distributions if (coveredvp) {
537*1031c584SApple OSS Distributions const char * name = vnode_getname_printable(coveredvp);
538*1031c584SApple OSS Distributions strlcpy(vfap->f_vol_name, name, MAXPATHLEN);
539*1031c584SApple OSS Distributions vnode_putname_printable(name);
540*1031c584SApple OSS Distributions
541*1031c584SApple OSS Distributions VFSATTR_SET_SUPPORTED(vfap, f_vol_name);
542*1031c584SApple OSS Distributions vnode_put(coveredvp);
543*1031c584SApple OSS Distributions }
544*1031c584SApple OSS Distributions }
545*1031c584SApple OSS Distributions
546*1031c584SApple OSS Distributions nullfs_cleanup_patched_context(null_mp, ectx);
547*1031c584SApple OSS Distributions
548*1031c584SApple OSS Distributions return 0;
549*1031c584SApple OSS Distributions }
550*1031c584SApple OSS Distributions
551*1031c584SApple OSS Distributions static int
nullfs_sync(__unused struct mount * mp,__unused int waitfor,__unused vfs_context_t ctx)552*1031c584SApple OSS Distributions nullfs_sync(__unused struct mount * mp, __unused int waitfor, __unused vfs_context_t ctx)
553*1031c584SApple OSS Distributions {
554*1031c584SApple OSS Distributions /*
555*1031c584SApple OSS Distributions * XXX - Assumes no data cached at null layer.
556*1031c584SApple OSS Distributions */
557*1031c584SApple OSS Distributions return 0;
558*1031c584SApple OSS Distributions }
559*1031c584SApple OSS Distributions
560*1031c584SApple OSS Distributions
561*1031c584SApple OSS Distributions
562*1031c584SApple OSS Distributions static int
nullfs_vfs_start(__unused struct mount * mp,__unused int flags,__unused vfs_context_t ctx)563*1031c584SApple OSS Distributions nullfs_vfs_start(__unused struct mount * mp, __unused int flags, __unused vfs_context_t ctx)
564*1031c584SApple OSS Distributions {
565*1031c584SApple OSS Distributions NULLFSDEBUG("%s\n", __FUNCTION__);
566*1031c584SApple OSS Distributions return 0;
567*1031c584SApple OSS Distributions }
568*1031c584SApple OSS Distributions
569*1031c584SApple OSS Distributions extern const struct vnodeopv_desc nullfs_vnodeop_opv_desc;
570*1031c584SApple OSS Distributions
571*1031c584SApple OSS Distributions const struct vnodeopv_desc * nullfs_vnodeopv_descs[] = {
572*1031c584SApple OSS Distributions &nullfs_vnodeop_opv_desc,
573*1031c584SApple OSS Distributions };
574*1031c584SApple OSS Distributions
575*1031c584SApple OSS Distributions struct vfsops nullfs_vfsops = {
576*1031c584SApple OSS Distributions .vfs_mount = nullfs_mount,
577*1031c584SApple OSS Distributions .vfs_unmount = nullfs_unmount,
578*1031c584SApple OSS Distributions .vfs_start = nullfs_vfs_start,
579*1031c584SApple OSS Distributions .vfs_root = nullfs_root,
580*1031c584SApple OSS Distributions .vfs_getattr = nullfs_vfs_getattr,
581*1031c584SApple OSS Distributions .vfs_sync = nullfs_sync,
582*1031c584SApple OSS Distributions .vfs_init = nullfs_init,
583*1031c584SApple OSS Distributions .vfs_sysctl = NULL,
584*1031c584SApple OSS Distributions .vfs_setattr = NULL,
585*1031c584SApple OSS Distributions };
586