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