xref: /xnu-12377.41.6/bsd/miscfs/nullfs/null_vnops.c (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1*bbb1b6f9SApple OSS Distributions /*
2*bbb1b6f9SApple OSS Distributions  * Copyright (c) 2019 Apple Inc. All rights reserved.
3*bbb1b6f9SApple OSS Distributions  *
4*bbb1b6f9SApple OSS Distributions  * @APPLE_LICENSE_HEADER_START@
5*bbb1b6f9SApple OSS Distributions  *
6*bbb1b6f9SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*bbb1b6f9SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*bbb1b6f9SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*bbb1b6f9SApple OSS Distributions  * compliance with the License. Please obtain a copy of the License at
10*bbb1b6f9SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this
11*bbb1b6f9SApple OSS Distributions  * file.
12*bbb1b6f9SApple OSS Distributions  *
13*bbb1b6f9SApple OSS Distributions  * The Original Code and all software distributed under the License are
14*bbb1b6f9SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15*bbb1b6f9SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16*bbb1b6f9SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17*bbb1b6f9SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18*bbb1b6f9SApple OSS Distributions  * Please see the License for the specific language governing rights and
19*bbb1b6f9SApple OSS Distributions  * limitations under the License.
20*bbb1b6f9SApple OSS Distributions  *
21*bbb1b6f9SApple OSS Distributions  * @APPLE_LICENSE_HEADER_END@
22*bbb1b6f9SApple OSS Distributions  */
23*bbb1b6f9SApple OSS Distributions 
24*bbb1b6f9SApple OSS Distributions /*-
25*bbb1b6f9SApple OSS Distributions  * Portions Copyright (c) 1992, 1993
26*bbb1b6f9SApple OSS Distributions  *  The Regents of the University of California.  All rights reserved.
27*bbb1b6f9SApple OSS Distributions  *
28*bbb1b6f9SApple OSS Distributions  * This code is derived from software contributed to Berkeley by
29*bbb1b6f9SApple OSS Distributions  * John Heidemann of the UCLA Ficus project.
30*bbb1b6f9SApple OSS Distributions  *
31*bbb1b6f9SApple OSS Distributions  * Redistribution and use in source and binary forms, with or without
32*bbb1b6f9SApple OSS Distributions  * modification, are permitted provided that the following conditions
33*bbb1b6f9SApple OSS Distributions  * are met:
34*bbb1b6f9SApple OSS Distributions  * 1. Redistributions of source code must retain the above copyright
35*bbb1b6f9SApple OSS Distributions  *    notice, this list of conditions and the following disclaimer.
36*bbb1b6f9SApple OSS Distributions  * 2. Redistributions in binary form must reproduce the above copyright
37*bbb1b6f9SApple OSS Distributions  *    notice, this list of conditions and the following disclaimer in the
38*bbb1b6f9SApple OSS Distributions  *    documentation and/or other materials provided with the distribution.
39*bbb1b6f9SApple OSS Distributions  * 4. Neither the name of the University nor the names of its contributors
40*bbb1b6f9SApple OSS Distributions  *    may be used to endorse or promote products derived from this software
41*bbb1b6f9SApple OSS Distributions  *    without specific prior written permission.
42*bbb1b6f9SApple OSS Distributions  *
43*bbb1b6f9SApple OSS Distributions  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44*bbb1b6f9SApple OSS Distributions  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45*bbb1b6f9SApple OSS Distributions  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46*bbb1b6f9SApple OSS Distributions  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47*bbb1b6f9SApple OSS Distributions  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48*bbb1b6f9SApple OSS Distributions  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49*bbb1b6f9SApple OSS Distributions  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50*bbb1b6f9SApple OSS Distributions  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51*bbb1b6f9SApple OSS Distributions  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52*bbb1b6f9SApple OSS Distributions  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53*bbb1b6f9SApple OSS Distributions  * SUCH DAMAGE.
54*bbb1b6f9SApple OSS Distributions  *
55*bbb1b6f9SApple OSS Distributions  *  @(#)null_vnops.c    8.6 (Berkeley) 5/27/95
56*bbb1b6f9SApple OSS Distributions  *
57*bbb1b6f9SApple OSS Distributions  * Ancestors:
58*bbb1b6f9SApple OSS Distributions  *  @(#)lofs_vnops.c    1.2 (Berkeley) 6/18/92
59*bbb1b6f9SApple OSS Distributions  *  ...and...
60*bbb1b6f9SApple OSS Distributions  *  @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project
61*bbb1b6f9SApple OSS Distributions  *
62*bbb1b6f9SApple OSS Distributions  * $FreeBSD$
63*bbb1b6f9SApple OSS Distributions  */
64*bbb1b6f9SApple OSS Distributions 
65*bbb1b6f9SApple OSS Distributions #include <sys/param.h>
66*bbb1b6f9SApple OSS Distributions #include <sys/systm.h>
67*bbb1b6f9SApple OSS Distributions #include <sys/conf.h>
68*bbb1b6f9SApple OSS Distributions #include <sys/kernel.h>
69*bbb1b6f9SApple OSS Distributions #include <sys/lock.h>
70*bbb1b6f9SApple OSS Distributions #include <sys/malloc.h>
71*bbb1b6f9SApple OSS Distributions #include <sys/mount.h>
72*bbb1b6f9SApple OSS Distributions #include <sys/mount_internal.h>
73*bbb1b6f9SApple OSS Distributions #include <sys/namei.h>
74*bbb1b6f9SApple OSS Distributions #include <sys/sysctl.h>
75*bbb1b6f9SApple OSS Distributions #include <sys/vnode.h>
76*bbb1b6f9SApple OSS Distributions #include <sys/xattr.h>
77*bbb1b6f9SApple OSS Distributions #include <sys/ubc.h>
78*bbb1b6f9SApple OSS Distributions #include <sys/types.h>
79*bbb1b6f9SApple OSS Distributions #include <sys/dirent.h>
80*bbb1b6f9SApple OSS Distributions #include <sys/kauth.h>
81*bbb1b6f9SApple OSS Distributions 
82*bbb1b6f9SApple OSS Distributions #include "nullfs.h"
83*bbb1b6f9SApple OSS Distributions 
84*bbb1b6f9SApple OSS Distributions #define NULL_ROOT_INO 2
85*bbb1b6f9SApple OSS Distributions #define NULL_SECOND_INO 3
86*bbb1b6f9SApple OSS Distributions #define NULL_THIRD_INO 4
87*bbb1b6f9SApple OSS Distributions 
88*bbb1b6f9SApple OSS Distributions vop_t * nullfs_vnodeop_p = NULL;
89*bbb1b6f9SApple OSS Distributions 
90*bbb1b6f9SApple OSS Distributions /* the mountpoint lock should be held going into this function */
91*bbb1b6f9SApple OSS Distributions static int
nullfs_isspecialvp(struct vnode * vp)92*bbb1b6f9SApple OSS Distributions nullfs_isspecialvp(struct vnode * vp)
93*bbb1b6f9SApple OSS Distributions {
94*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp;
95*bbb1b6f9SApple OSS Distributions 
96*bbb1b6f9SApple OSS Distributions 	null_mp = MOUNTTONULLMOUNT(vnode_mount(vp));
97*bbb1b6f9SApple OSS Distributions 
98*bbb1b6f9SApple OSS Distributions 	/* only check for root and second here, third is special in a different way,
99*bbb1b6f9SApple OSS Distributions 	 * related only to lookup and readdir */
100*bbb1b6f9SApple OSS Distributions 	if (vp && (vp == null_mp->nullm_rootvp || vp == null_mp->nullm_secondvp)) {
101*bbb1b6f9SApple OSS Distributions 		return 1;
102*bbb1b6f9SApple OSS Distributions 	}
103*bbb1b6f9SApple OSS Distributions 	return 0;
104*bbb1b6f9SApple OSS Distributions }
105*bbb1b6f9SApple OSS Distributions 
106*bbb1b6f9SApple OSS Distributions /* helper function to handle locking where possible */
107*bbb1b6f9SApple OSS Distributions static int
nullfs_checkspecialvp(struct vnode * vp)108*bbb1b6f9SApple OSS Distributions nullfs_checkspecialvp(struct vnode* vp)
109*bbb1b6f9SApple OSS Distributions {
110*bbb1b6f9SApple OSS Distributions 	int result = 0;
111*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp;
112*bbb1b6f9SApple OSS Distributions 
113*bbb1b6f9SApple OSS Distributions 	null_mp = MOUNTTONULLMOUNT(vnode_mount(vp));
114*bbb1b6f9SApple OSS Distributions 
115*bbb1b6f9SApple OSS Distributions 	lck_mtx_lock(&null_mp->nullm_lock);
116*bbb1b6f9SApple OSS Distributions 	result = (nullfs_isspecialvp(vp));
117*bbb1b6f9SApple OSS Distributions 	lck_mtx_unlock(&null_mp->nullm_lock);
118*bbb1b6f9SApple OSS Distributions 
119*bbb1b6f9SApple OSS Distributions 	return result;
120*bbb1b6f9SApple OSS Distributions }
121*bbb1b6f9SApple OSS Distributions 
122*bbb1b6f9SApple OSS Distributions vfs_context_t
nullfs_get_patched_context(struct null_mount * null_mp,vfs_context_t ctx)123*bbb1b6f9SApple OSS Distributions nullfs_get_patched_context(struct null_mount * null_mp, vfs_context_t ctx)
124*bbb1b6f9SApple OSS Distributions {
125*bbb1b6f9SApple OSS Distributions 	struct vfs_context *ectx = ctx;
126*bbb1b6f9SApple OSS Distributions 	kauth_cred_t ucred;
127*bbb1b6f9SApple OSS Distributions 
128*bbb1b6f9SApple OSS Distributions 	if ((null_mp->nullm_flags & NULLM_UNVEIL) == NULLM_UNVEIL) {
129*bbb1b6f9SApple OSS Distributions 		ectx = vfs_context_create(ctx);
130*bbb1b6f9SApple OSS Distributions 		ucred = kauth_cred_derive(ectx->vc_ucred,
131*bbb1b6f9SApple OSS Distributions 		    ^bool (kauth_cred_t parent __unused, kauth_cred_t model) {
132*bbb1b6f9SApple OSS Distributions 			return kauth_cred_model_setuidgid(model,
133*bbb1b6f9SApple OSS Distributions 			null_mp->uid, null_mp->gid);
134*bbb1b6f9SApple OSS Distributions 		});
135*bbb1b6f9SApple OSS Distributions 		kauth_cred_unref(&ectx->vc_ucred);
136*bbb1b6f9SApple OSS Distributions 		ectx->vc_ucred = ucred;
137*bbb1b6f9SApple OSS Distributions 	}
138*bbb1b6f9SApple OSS Distributions 	return ectx;
139*bbb1b6f9SApple OSS Distributions }
140*bbb1b6f9SApple OSS Distributions 
141*bbb1b6f9SApple OSS Distributions void
nullfs_cleanup_patched_context(struct null_mount * null_mp,vfs_context_t ctx)142*bbb1b6f9SApple OSS Distributions nullfs_cleanup_patched_context(struct null_mount * null_mp, vfs_context_t ctx)
143*bbb1b6f9SApple OSS Distributions {
144*bbb1b6f9SApple OSS Distributions 	if ((null_mp->nullm_flags & NULLM_UNVEIL) == NULLM_UNVEIL) {
145*bbb1b6f9SApple OSS Distributions 		vfs_context_rele(ctx);
146*bbb1b6f9SApple OSS Distributions 	}
147*bbb1b6f9SApple OSS Distributions }
148*bbb1b6f9SApple OSS Distributions 
149*bbb1b6f9SApple OSS Distributions static int
nullfs_default(__unused struct vnop_generic_args * args)150*bbb1b6f9SApple OSS Distributions nullfs_default(__unused struct vnop_generic_args * args)
151*bbb1b6f9SApple OSS Distributions {
152*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s (default)\n", ((struct vnodeop_desc_fake *)args->a_desc)->vdesc_name);
153*bbb1b6f9SApple OSS Distributions 	return ENOTSUP;
154*bbb1b6f9SApple OSS Distributions }
155*bbb1b6f9SApple OSS Distributions 
156*bbb1b6f9SApple OSS Distributions static int
nullfs_special_getattr(struct vnop_getattr_args * args)157*bbb1b6f9SApple OSS Distributions nullfs_special_getattr(struct vnop_getattr_args * args)
158*bbb1b6f9SApple OSS Distributions {
159*bbb1b6f9SApple OSS Distributions 	mount_t mp                  = vnode_mount(args->a_vp);
160*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp = MOUNTTONULLMOUNT(mp);
161*bbb1b6f9SApple OSS Distributions 
162*bbb1b6f9SApple OSS Distributions 	ino_t ino = NULL_ROOT_INO;
163*bbb1b6f9SApple OSS Distributions 	struct vnode_attr covered_rootattr;
164*bbb1b6f9SApple OSS Distributions 	vnode_t checkvp = null_mp->nullm_lowerrootvp;
165*bbb1b6f9SApple OSS Distributions 	vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
166*bbb1b6f9SApple OSS Distributions 
167*bbb1b6f9SApple OSS Distributions 	VATTR_INIT(&covered_rootattr);
168*bbb1b6f9SApple OSS Distributions 	VATTR_WANTED(&covered_rootattr, va_uid);
169*bbb1b6f9SApple OSS Distributions 	VATTR_WANTED(&covered_rootattr, va_gid);
170*bbb1b6f9SApple OSS Distributions 	VATTR_WANTED(&covered_rootattr, va_create_time);
171*bbb1b6f9SApple OSS Distributions 	VATTR_WANTED(&covered_rootattr, va_modify_time);
172*bbb1b6f9SApple OSS Distributions 	VATTR_WANTED(&covered_rootattr, va_access_time);
173*bbb1b6f9SApple OSS Distributions 
174*bbb1b6f9SApple OSS Distributions 	/* prefer to get this from the lower root vp, but if not (i.e. forced unmount
175*bbb1b6f9SApple OSS Distributions 	 * of lower fs) try the mount point covered vnode */
176*bbb1b6f9SApple OSS Distributions 	if (vnode_getwithvid(checkvp, null_mp->nullm_lowerrootvid)) {
177*bbb1b6f9SApple OSS Distributions 		checkvp = vfs_vnodecovered(mp);
178*bbb1b6f9SApple OSS Distributions 		if (checkvp == NULL) {
179*bbb1b6f9SApple OSS Distributions 			nullfs_cleanup_patched_context(null_mp, ectx);
180*bbb1b6f9SApple OSS Distributions 			return EIO;
181*bbb1b6f9SApple OSS Distributions 		}
182*bbb1b6f9SApple OSS Distributions 	}
183*bbb1b6f9SApple OSS Distributions 
184*bbb1b6f9SApple OSS Distributions 	int error = vnode_getattr(checkvp, &covered_rootattr, ectx);
185*bbb1b6f9SApple OSS Distributions 
186*bbb1b6f9SApple OSS Distributions 	vnode_put(checkvp);
187*bbb1b6f9SApple OSS Distributions 	if (error) {
188*bbb1b6f9SApple OSS Distributions 		/* we should have been able to get attributes fore one of the two choices so
189*bbb1b6f9SApple OSS Distributions 		 * fail if we didn't */
190*bbb1b6f9SApple OSS Distributions 		nullfs_cleanup_patched_context(null_mp, ectx);
191*bbb1b6f9SApple OSS Distributions 		return error;
192*bbb1b6f9SApple OSS Distributions 	}
193*bbb1b6f9SApple OSS Distributions 
194*bbb1b6f9SApple OSS Distributions 	/* we got the attributes of the vnode we cover so plow ahead */
195*bbb1b6f9SApple OSS Distributions 	if (args->a_vp == null_mp->nullm_secondvp) {
196*bbb1b6f9SApple OSS Distributions 		ino = NULL_SECOND_INO;
197*bbb1b6f9SApple OSS Distributions 	}
198*bbb1b6f9SApple OSS Distributions 
199*bbb1b6f9SApple OSS Distributions 	VATTR_RETURN(args->a_vap, va_type, vnode_vtype(args->a_vp));
200*bbb1b6f9SApple OSS Distributions 	VATTR_RETURN(args->a_vap, va_rdev, 0);
201*bbb1b6f9SApple OSS Distributions 	VATTR_RETURN(args->a_vap, va_nlink, 3);      /* always just ., .., and the child */
202*bbb1b6f9SApple OSS Distributions 	VATTR_RETURN(args->a_vap, va_total_size, 0); // hoping this is ok
203*bbb1b6f9SApple OSS Distributions 
204*bbb1b6f9SApple OSS Distributions 	VATTR_RETURN(args->a_vap, va_data_size, 0); // hoping this is ok
205*bbb1b6f9SApple OSS Distributions 	VATTR_RETURN(args->a_vap, va_data_alloc, 0);
206*bbb1b6f9SApple OSS Distributions 	VATTR_RETURN(args->a_vap, va_iosize, vfs_statfs(mp)->f_iosize);
207*bbb1b6f9SApple OSS Distributions 	VATTR_RETURN(args->a_vap, va_fileid, ino);
208*bbb1b6f9SApple OSS Distributions 	VATTR_RETURN(args->a_vap, va_linkid, ino);
209*bbb1b6f9SApple OSS Distributions 	if (VATTR_IS_ACTIVE(args->a_vap, va_fsid)) {
210*bbb1b6f9SApple OSS Distributions 		VATTR_RETURN(args->a_vap, va_fsid, vfs_statfs(mp)->f_fsid.val[0]); // return the fsid of the mount point
211*bbb1b6f9SApple OSS Distributions 	}
212*bbb1b6f9SApple OSS Distributions 	if (VATTR_IS_ACTIVE(args->a_vap, va_fsid64)) {
213*bbb1b6f9SApple OSS Distributions 		VATTR_RETURN(args->a_vap, va_fsid64, vfs_statfs(mp)->f_fsid);
214*bbb1b6f9SApple OSS Distributions 	}
215*bbb1b6f9SApple OSS Distributions 	VATTR_RETURN(args->a_vap, va_filerev, 0);
216*bbb1b6f9SApple OSS Distributions 	VATTR_RETURN(args->a_vap, va_gen, 0);
217*bbb1b6f9SApple OSS Distributions 	VATTR_RETURN(args->a_vap, va_flags, UF_HIDDEN); /* mark our fake directories as hidden. People
218*bbb1b6f9SApple OSS Distributions 	                                                 *  shouldn't be enocouraged to poke around in them */
219*bbb1b6f9SApple OSS Distributions 
220*bbb1b6f9SApple OSS Distributions 	if (ino == NULL_SECOND_INO) {
221*bbb1b6f9SApple OSS Distributions 		VATTR_RETURN(args->a_vap, va_parentid, NULL_ROOT_INO); /* no parent at the root, so
222*bbb1b6f9SApple OSS Distributions 		                                                        *  the only other vnode that
223*bbb1b6f9SApple OSS Distributions 		                                                        *  goes through this path is
224*bbb1b6f9SApple OSS Distributions 		                                                        *  second and its parent is
225*bbb1b6f9SApple OSS Distributions 		                                                        *  1.*/
226*bbb1b6f9SApple OSS Distributions 	}
227*bbb1b6f9SApple OSS Distributions 
228*bbb1b6f9SApple OSS Distributions 	if (VATTR_IS_ACTIVE(args->a_vap, va_mode)) {
229*bbb1b6f9SApple OSS Distributions 		/* force dr_xr_xr_x */
230*bbb1b6f9SApple OSS Distributions 		VATTR_RETURN(args->a_vap, va_mode, S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
231*bbb1b6f9SApple OSS Distributions 	}
232*bbb1b6f9SApple OSS Distributions 	if (VATTR_IS_ACTIVE(args->a_vap, va_uid)) {
233*bbb1b6f9SApple OSS Distributions 		VATTR_RETURN(args->a_vap, va_uid, covered_rootattr.va_uid);
234*bbb1b6f9SApple OSS Distributions 	}
235*bbb1b6f9SApple OSS Distributions 	if (VATTR_IS_ACTIVE(args->a_vap, va_gid)) {
236*bbb1b6f9SApple OSS Distributions 		VATTR_RETURN(args->a_vap, va_gid, covered_rootattr.va_gid);
237*bbb1b6f9SApple OSS Distributions 	}
238*bbb1b6f9SApple OSS Distributions 
239*bbb1b6f9SApple OSS Distributions 	if (VATTR_IS_ACTIVE(args->a_vap, va_create_time)) {
240*bbb1b6f9SApple OSS Distributions 		VATTR_SET_SUPPORTED(args->a_vap, va_create_time);
241*bbb1b6f9SApple OSS Distributions 		args->a_vap->va_create_time.tv_sec  = covered_rootattr.va_create_time.tv_sec;
242*bbb1b6f9SApple OSS Distributions 		args->a_vap->va_create_time.tv_nsec = covered_rootattr.va_create_time.tv_nsec;
243*bbb1b6f9SApple OSS Distributions 	}
244*bbb1b6f9SApple OSS Distributions 	if (VATTR_IS_ACTIVE(args->a_vap, va_modify_time)) {
245*bbb1b6f9SApple OSS Distributions 		VATTR_SET_SUPPORTED(args->a_vap, va_modify_time);
246*bbb1b6f9SApple OSS Distributions 		args->a_vap->va_modify_time.tv_sec  = covered_rootattr.va_modify_time.tv_sec;
247*bbb1b6f9SApple OSS Distributions 		args->a_vap->va_modify_time.tv_nsec = covered_rootattr.va_modify_time.tv_nsec;
248*bbb1b6f9SApple OSS Distributions 	}
249*bbb1b6f9SApple OSS Distributions 	if (VATTR_IS_ACTIVE(args->a_vap, va_access_time)) {
250*bbb1b6f9SApple OSS Distributions 		VATTR_SET_SUPPORTED(args->a_vap, va_access_time);
251*bbb1b6f9SApple OSS Distributions 		args->a_vap->va_modify_time.tv_sec  = covered_rootattr.va_access_time.tv_sec;
252*bbb1b6f9SApple OSS Distributions 		args->a_vap->va_modify_time.tv_nsec = covered_rootattr.va_access_time.tv_nsec;
253*bbb1b6f9SApple OSS Distributions 	}
254*bbb1b6f9SApple OSS Distributions 
255*bbb1b6f9SApple OSS Distributions 	nullfs_cleanup_patched_context(null_mp, ectx);
256*bbb1b6f9SApple OSS Distributions 	return 0;
257*bbb1b6f9SApple OSS Distributions }
258*bbb1b6f9SApple OSS Distributions 
259*bbb1b6f9SApple OSS Distributions static int
nullfs_getattr(struct vnop_getattr_args * args)260*bbb1b6f9SApple OSS Distributions nullfs_getattr(struct vnop_getattr_args * args)
261*bbb1b6f9SApple OSS Distributions {
262*bbb1b6f9SApple OSS Distributions 	int error;
263*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(args->a_vp));
264*bbb1b6f9SApple OSS Distributions 	kauth_cred_t cred = vfs_context_ucred(args->a_context);
265*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
266*bbb1b6f9SApple OSS Distributions 
267*bbb1b6f9SApple OSS Distributions 	if (nullfs_checkspecialvp(args->a_vp)) {
268*bbb1b6f9SApple OSS Distributions 		error = nullfs_special_getattr(args);
269*bbb1b6f9SApple OSS Distributions 		return error;
270*bbb1b6f9SApple OSS Distributions 	}
271*bbb1b6f9SApple OSS Distributions 
272*bbb1b6f9SApple OSS Distributions 	/* this will return a different inode for third than read dir will */
273*bbb1b6f9SApple OSS Distributions 	struct vnode * lowervp = NULLVPTOLOWERVP(args->a_vp);
274*bbb1b6f9SApple OSS Distributions 	vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
275*bbb1b6f9SApple OSS Distributions 	error = vnode_getwithref(lowervp);
276*bbb1b6f9SApple OSS Distributions 
277*bbb1b6f9SApple OSS Distributions 	if (error == 0) {
278*bbb1b6f9SApple OSS Distributions 		error = VNOP_GETATTR(lowervp, args->a_vap, ectx);
279*bbb1b6f9SApple OSS Distributions 		vnode_put(lowervp);
280*bbb1b6f9SApple OSS Distributions 
281*bbb1b6f9SApple OSS Distributions 		if (error == 0) {
282*bbb1b6f9SApple OSS Distributions 			/* fix up fsid so it doesn't say the underlying fs*/
283*bbb1b6f9SApple OSS Distributions 			if (VATTR_IS_ACTIVE(args->a_vap, va_fsid)) {
284*bbb1b6f9SApple OSS Distributions 				VATTR_RETURN(args->a_vap, va_fsid, vfs_statfs(vnode_mount(args->a_vp))->f_fsid.val[0]);
285*bbb1b6f9SApple OSS Distributions 			}
286*bbb1b6f9SApple OSS Distributions 			if (VATTR_IS_ACTIVE(args->a_vap, va_fsid64)) {
287*bbb1b6f9SApple OSS Distributions 				VATTR_RETURN(args->a_vap, va_fsid64, vfs_statfs(vnode_mount(args->a_vp))->f_fsid);
288*bbb1b6f9SApple OSS Distributions 			}
289*bbb1b6f9SApple OSS Distributions 
290*bbb1b6f9SApple OSS Distributions 			/* Conjure up permissions */
291*bbb1b6f9SApple OSS Distributions 			if ((null_mp->nullm_flags & NULLM_UNVEIL) == NULLM_UNVEIL) {
292*bbb1b6f9SApple OSS Distributions 				if (VATTR_IS_ACTIVE(args->a_vap, va_mode)) {
293*bbb1b6f9SApple OSS Distributions 					mode_t mode = args->a_vap->va_mode; // We will take away permisions if we don't have them
294*bbb1b6f9SApple OSS Distributions 
295*bbb1b6f9SApple OSS Distributions 					// Check for authorizations
296*bbb1b6f9SApple OSS Distributions 					// If we can read:
297*bbb1b6f9SApple OSS Distributions 					if (vnode_authorize(lowervp, NULL, KAUTH_VNODE_GENERIC_READ_BITS, ectx) == 0) {
298*bbb1b6f9SApple OSS Distributions 						mode |= S_IRUSR;
299*bbb1b6f9SApple OSS Distributions 					} else {
300*bbb1b6f9SApple OSS Distributions 						mode &= ~S_IRUSR;
301*bbb1b6f9SApple OSS Distributions 					}
302*bbb1b6f9SApple OSS Distributions 
303*bbb1b6f9SApple OSS Distributions 					// Or execute
304*bbb1b6f9SApple OSS Distributions 					// Directories need an execute bit...
305*bbb1b6f9SApple OSS Distributions 					if (vnode_authorize(lowervp, NULL, KAUTH_VNODE_GENERIC_EXECUTE_BITS, ectx) == 0) {
306*bbb1b6f9SApple OSS Distributions 						mode |= S_IXUSR;
307*bbb1b6f9SApple OSS Distributions 					} else {
308*bbb1b6f9SApple OSS Distributions 						mode &= ~S_IXUSR;
309*bbb1b6f9SApple OSS Distributions 					}
310*bbb1b6f9SApple OSS Distributions 
311*bbb1b6f9SApple OSS Distributions 					NULLFSDEBUG("Settings bits to %d\n", mode);
312*bbb1b6f9SApple OSS Distributions 					VATTR_RETURN(args->a_vap, va_mode, mode);
313*bbb1b6f9SApple OSS Distributions 				}
314*bbb1b6f9SApple OSS Distributions 				if (VATTR_IS_ACTIVE(args->a_vap, va_uid)) {
315*bbb1b6f9SApple OSS Distributions 					VATTR_RETURN(args->a_vap, va_uid, kauth_cred_getuid(cred));
316*bbb1b6f9SApple OSS Distributions 				}
317*bbb1b6f9SApple OSS Distributions 				if (VATTR_IS_ACTIVE(args->a_vap, va_gid)) {
318*bbb1b6f9SApple OSS Distributions 					VATTR_RETURN(args->a_vap, va_gid, kauth_cred_getgid(cred));
319*bbb1b6f9SApple OSS Distributions 				}
320*bbb1b6f9SApple OSS Distributions 			}
321*bbb1b6f9SApple OSS Distributions 		}
322*bbb1b6f9SApple OSS Distributions 	}
323*bbb1b6f9SApple OSS Distributions 
324*bbb1b6f9SApple OSS Distributions 	nullfs_cleanup_patched_context(null_mp, ectx);
325*bbb1b6f9SApple OSS Distributions 	return error;
326*bbb1b6f9SApple OSS Distributions }
327*bbb1b6f9SApple OSS Distributions 
328*bbb1b6f9SApple OSS Distributions static int
nullfs_open(struct vnop_open_args * args)329*bbb1b6f9SApple OSS Distributions nullfs_open(struct vnop_open_args * args)
330*bbb1b6f9SApple OSS Distributions {
331*bbb1b6f9SApple OSS Distributions 	int error;
332*bbb1b6f9SApple OSS Distributions 	struct vnode *vp, *lvp;
333*bbb1b6f9SApple OSS Distributions 	mount_t mp                  = vnode_mount(args->a_vp);
334*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp = MOUNTTONULLMOUNT(mp);
335*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
336*bbb1b6f9SApple OSS Distributions 
337*bbb1b6f9SApple OSS Distributions 	if (nullfs_checkspecialvp(args->a_vp)) {
338*bbb1b6f9SApple OSS Distributions 		return 0; /* nothing extra needed */
339*bbb1b6f9SApple OSS Distributions 	}
340*bbb1b6f9SApple OSS Distributions 
341*bbb1b6f9SApple OSS Distributions 	vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
342*bbb1b6f9SApple OSS Distributions 	vp    = args->a_vp;
343*bbb1b6f9SApple OSS Distributions 	lvp   = NULLVPTOLOWERVP(vp);
344*bbb1b6f9SApple OSS Distributions 	error = vnode_getwithref(lvp);
345*bbb1b6f9SApple OSS Distributions 	if (error == 0) {
346*bbb1b6f9SApple OSS Distributions 		error = VNOP_OPEN(lvp, args->a_mode, ectx);
347*bbb1b6f9SApple OSS Distributions 		vnode_put(lvp);
348*bbb1b6f9SApple OSS Distributions 	}
349*bbb1b6f9SApple OSS Distributions 
350*bbb1b6f9SApple OSS Distributions 	nullfs_cleanup_patched_context(null_mp, ectx);
351*bbb1b6f9SApple OSS Distributions 	return error;
352*bbb1b6f9SApple OSS Distributions }
353*bbb1b6f9SApple OSS Distributions 
354*bbb1b6f9SApple OSS Distributions static int
nullfs_close(struct vnop_close_args * args)355*bbb1b6f9SApple OSS Distributions nullfs_close(struct vnop_close_args * args)
356*bbb1b6f9SApple OSS Distributions {
357*bbb1b6f9SApple OSS Distributions 	int error;
358*bbb1b6f9SApple OSS Distributions 	struct vnode *vp, *lvp;
359*bbb1b6f9SApple OSS Distributions 	mount_t mp                  = vnode_mount(args->a_vp);
360*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp = MOUNTTONULLMOUNT(mp);
361*bbb1b6f9SApple OSS Distributions 
362*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
363*bbb1b6f9SApple OSS Distributions 
364*bbb1b6f9SApple OSS Distributions 	if (nullfs_checkspecialvp(args->a_vp)) {
365*bbb1b6f9SApple OSS Distributions 		return 0; /* nothing extra needed */
366*bbb1b6f9SApple OSS Distributions 	}
367*bbb1b6f9SApple OSS Distributions 
368*bbb1b6f9SApple OSS Distributions 	vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
369*bbb1b6f9SApple OSS Distributions 	vp  = args->a_vp;
370*bbb1b6f9SApple OSS Distributions 	lvp = NULLVPTOLOWERVP(vp);
371*bbb1b6f9SApple OSS Distributions 
372*bbb1b6f9SApple OSS Distributions 	error = vnode_getwithref(lvp);
373*bbb1b6f9SApple OSS Distributions 	if (error == 0) {
374*bbb1b6f9SApple OSS Distributions 		error = VNOP_CLOSE(lvp, args->a_fflag, ectx);
375*bbb1b6f9SApple OSS Distributions 		vnode_put(lvp);
376*bbb1b6f9SApple OSS Distributions 	}
377*bbb1b6f9SApple OSS Distributions 
378*bbb1b6f9SApple OSS Distributions 	nullfs_cleanup_patched_context(null_mp, ectx);
379*bbb1b6f9SApple OSS Distributions 	return error;
380*bbb1b6f9SApple OSS Distributions }
381*bbb1b6f9SApple OSS Distributions 
382*bbb1b6f9SApple OSS Distributions /* get lvp's parent, if possible, even if it isn't set.
383*bbb1b6f9SApple OSS Distributions  *
384*bbb1b6f9SApple OSS Distributions  *  lvp is expected to have an iocount before and after this call.
385*bbb1b6f9SApple OSS Distributions  *
386*bbb1b6f9SApple OSS Distributions  *  if a dvpp is populated the returned vnode has an iocount. */
387*bbb1b6f9SApple OSS Distributions static int
null_get_lowerparent(vnode_t lvp,vnode_t * dvpp,vfs_context_t ctx)388*bbb1b6f9SApple OSS Distributions null_get_lowerparent(vnode_t lvp, vnode_t * dvpp, vfs_context_t ctx)
389*bbb1b6f9SApple OSS Distributions {
390*bbb1b6f9SApple OSS Distributions 	int error = 0;
391*bbb1b6f9SApple OSS Distributions 	struct vnode_attr va;
392*bbb1b6f9SApple OSS Distributions 	mount_t mp  = vnode_mount(lvp);
393*bbb1b6f9SApple OSS Distributions 	vnode_t dvp = vnode_parent(lvp);
394*bbb1b6f9SApple OSS Distributions 
395*bbb1b6f9SApple OSS Distributions 	if (dvp) {
396*bbb1b6f9SApple OSS Distributions 		error = vnode_get(dvp);
397*bbb1b6f9SApple OSS Distributions 		goto end;
398*bbb1b6f9SApple OSS Distributions 	}
399*bbb1b6f9SApple OSS Distributions 
400*bbb1b6f9SApple OSS Distributions 	error = ENOENT;
401*bbb1b6f9SApple OSS Distributions 	if (!(mp->mnt_kern_flag & MNTK_PATH_FROM_ID)) {
402*bbb1b6f9SApple OSS Distributions 		goto end;
403*bbb1b6f9SApple OSS Distributions 	}
404*bbb1b6f9SApple OSS Distributions 
405*bbb1b6f9SApple OSS Distributions 	VATTR_INIT(&va);
406*bbb1b6f9SApple OSS Distributions 	VATTR_WANTED(&va, va_parentid);
407*bbb1b6f9SApple OSS Distributions 
408*bbb1b6f9SApple OSS Distributions 	error = vnode_getattr(lvp, &va, ctx);
409*bbb1b6f9SApple OSS Distributions 
410*bbb1b6f9SApple OSS Distributions 	if (error || !VATTR_IS_SUPPORTED(&va, va_parentid)) {
411*bbb1b6f9SApple OSS Distributions 		if (!error) {
412*bbb1b6f9SApple OSS Distributions 			error = ENOTSUP;
413*bbb1b6f9SApple OSS Distributions 		}
414*bbb1b6f9SApple OSS Distributions 		goto end;
415*bbb1b6f9SApple OSS Distributions 	}
416*bbb1b6f9SApple OSS Distributions 
417*bbb1b6f9SApple OSS Distributions 	error = VFS_VGET(mp, (ino64_t)va.va_parentid, &dvp, ctx);
418*bbb1b6f9SApple OSS Distributions 
419*bbb1b6f9SApple OSS Distributions end:
420*bbb1b6f9SApple OSS Distributions 	if (error == 0) {
421*bbb1b6f9SApple OSS Distributions 		*dvpp = dvp;
422*bbb1b6f9SApple OSS Distributions 	}
423*bbb1b6f9SApple OSS Distributions 	return error;
424*bbb1b6f9SApple OSS Distributions }
425*bbb1b6f9SApple OSS Distributions 
426*bbb1b6f9SApple OSS Distributions /* the mountpoint lock should be held going into this function */
427*bbb1b6f9SApple OSS Distributions static int
null_special_lookup(struct vnop_lookup_args * ap)428*bbb1b6f9SApple OSS Distributions null_special_lookup(struct vnop_lookup_args * ap)
429*bbb1b6f9SApple OSS Distributions {
430*bbb1b6f9SApple OSS Distributions 	struct componentname * cnp  = ap->a_cnp;
431*bbb1b6f9SApple OSS Distributions 	struct vnode * dvp          = ap->a_dvp;
432*bbb1b6f9SApple OSS Distributions 	struct vnode * ldvp         = NULL;
433*bbb1b6f9SApple OSS Distributions 	struct vnode * lvp          = NULL;
434*bbb1b6f9SApple OSS Distributions 	struct vnode * vp           = NULL;
435*bbb1b6f9SApple OSS Distributions 	struct vnode * tempvp       = NULL;
436*bbb1b6f9SApple OSS Distributions 	struct mount * mp           = vnode_mount(dvp);
437*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp = MOUNTTONULLMOUNT(mp);
438*bbb1b6f9SApple OSS Distributions 	int error                   = ENOENT;
439*bbb1b6f9SApple OSS Distributions 	vfs_context_t ectx     = nullfs_get_patched_context(null_mp, ap->a_context);
440*bbb1b6f9SApple OSS Distributions 
441*bbb1b6f9SApple OSS Distributions 	// null_mp->nullm_lock is locked
442*bbb1b6f9SApple OSS Distributions 	if (dvp == null_mp->nullm_rootvp) {
443*bbb1b6f9SApple OSS Distributions 		/* handle . and .. */
444*bbb1b6f9SApple OSS Distributions 		if (cnp->cn_nameptr[0] == '.') {
445*bbb1b6f9SApple OSS Distributions 			if (cnp->cn_namelen == 1 || (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.')) {
446*bbb1b6f9SApple OSS Distributions 				/* this is the root so both . and .. give back the root */
447*bbb1b6f9SApple OSS Distributions 				vp = dvp;
448*bbb1b6f9SApple OSS Distributions 				lck_mtx_unlock(&null_mp->nullm_lock);
449*bbb1b6f9SApple OSS Distributions 				error = vnode_get(vp);
450*bbb1b6f9SApple OSS Distributions 				goto end;
451*bbb1b6f9SApple OSS Distributions 			}
452*bbb1b6f9SApple OSS Distributions 		}
453*bbb1b6f9SApple OSS Distributions 
454*bbb1b6f9SApple OSS Distributions 		/* our virtual wrapper directory should be d but D is acceptable if the
455*bbb1b6f9SApple OSS Distributions 		 * lower file system is case insensitive */
456*bbb1b6f9SApple OSS Distributions 		if (cnp->cn_namelen == 1 &&
457*bbb1b6f9SApple OSS Distributions 		    (cnp->cn_nameptr[0] == 'd' || (null_mp->nullm_flags & NULLM_CASEINSENSITIVE ? cnp->cn_nameptr[0] == 'D' : 0))) {
458*bbb1b6f9SApple OSS Distributions 			error = 0;
459*bbb1b6f9SApple OSS Distributions 			if (null_mp->nullm_secondvp == NULL) {
460*bbb1b6f9SApple OSS Distributions 				// drop the lock before making a new vnode
461*bbb1b6f9SApple OSS Distributions 				lck_mtx_unlock(&null_mp->nullm_lock);
462*bbb1b6f9SApple OSS Distributions 				error = null_getnewvnode(mp, NULL, dvp, &vp, cnp, 0);
463*bbb1b6f9SApple OSS Distributions 				if (error) {
464*bbb1b6f9SApple OSS Distributions 					goto end;
465*bbb1b6f9SApple OSS Distributions 				}
466*bbb1b6f9SApple OSS Distributions 				// Get the lock before modifying nullm_secondvp
467*bbb1b6f9SApple OSS Distributions 				lck_mtx_lock(&null_mp->nullm_lock);
468*bbb1b6f9SApple OSS Distributions 				if (null_mp->nullm_secondvp == NULL) {
469*bbb1b6f9SApple OSS Distributions 					null_mp->nullm_secondvp = vp;
470*bbb1b6f9SApple OSS Distributions 					lck_mtx_unlock(&null_mp->nullm_lock);
471*bbb1b6f9SApple OSS Distributions 				} else {
472*bbb1b6f9SApple OSS Distributions 					/* Another thread already set null_mp->nullm_secondvp while the
473*bbb1b6f9SApple OSS Distributions 					 * lock was dropped so recycle the vnode we just made */
474*bbb1b6f9SApple OSS Distributions 					tempvp = vp;
475*bbb1b6f9SApple OSS Distributions 					vp = null_mp->nullm_secondvp;
476*bbb1b6f9SApple OSS Distributions 					lck_mtx_unlock(&null_mp->nullm_lock);
477*bbb1b6f9SApple OSS Distributions 					/* recycle will call reclaim which will get rid of the internals */
478*bbb1b6f9SApple OSS Distributions 					vnode_recycle(tempvp);
479*bbb1b6f9SApple OSS Distributions 					vnode_put(tempvp);
480*bbb1b6f9SApple OSS Distributions 
481*bbb1b6f9SApple OSS Distributions 					error = vnode_get(vp);
482*bbb1b6f9SApple OSS Distributions 				}
483*bbb1b6f9SApple OSS Distributions 			} else {
484*bbb1b6f9SApple OSS Distributions 				vp = null_mp->nullm_secondvp;
485*bbb1b6f9SApple OSS Distributions 				lck_mtx_unlock(&null_mp->nullm_lock);
486*bbb1b6f9SApple OSS Distributions 				error = vnode_get(vp);
487*bbb1b6f9SApple OSS Distributions 			}
488*bbb1b6f9SApple OSS Distributions 		} else {
489*bbb1b6f9SApple OSS Distributions 			lck_mtx_unlock(&null_mp->nullm_lock);
490*bbb1b6f9SApple OSS Distributions 		}
491*bbb1b6f9SApple OSS Distributions 	} else if (dvp == null_mp->nullm_secondvp) {
492*bbb1b6f9SApple OSS Distributions 		/* handle . and .. */
493*bbb1b6f9SApple OSS Distributions 		if (cnp->cn_nameptr[0] == '.') {
494*bbb1b6f9SApple OSS Distributions 			if (cnp->cn_namelen == 1) {
495*bbb1b6f9SApple OSS Distributions 				vp = dvp;
496*bbb1b6f9SApple OSS Distributions 				lck_mtx_unlock(&null_mp->nullm_lock);
497*bbb1b6f9SApple OSS Distributions 				error = vnode_get(vp);
498*bbb1b6f9SApple OSS Distributions 				goto end;
499*bbb1b6f9SApple OSS Distributions 			} else if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
500*bbb1b6f9SApple OSS Distributions 				/* parent here is the root vp */
501*bbb1b6f9SApple OSS Distributions 				vp    = null_mp->nullm_rootvp;
502*bbb1b6f9SApple OSS Distributions 				lck_mtx_unlock(&null_mp->nullm_lock);
503*bbb1b6f9SApple OSS Distributions 				error = vnode_get(vp);
504*bbb1b6f9SApple OSS Distributions 				goto end;
505*bbb1b6f9SApple OSS Distributions 			}
506*bbb1b6f9SApple OSS Distributions 		}
507*bbb1b6f9SApple OSS Distributions 		/* nullmp->nullm_lowerrootvp was set at mount time so don't need to lock to
508*bbb1b6f9SApple OSS Distributions 		 * access it */
509*bbb1b6f9SApple OSS Distributions 		/* Drop the global lock since we aren't accessing rootvp or secondvp any more */
510*bbb1b6f9SApple OSS Distributions 		lck_mtx_unlock(&null_mp->nullm_lock);
511*bbb1b6f9SApple OSS Distributions 		error = vnode_getwithvid(null_mp->nullm_lowerrootvp, null_mp->nullm_lowerrootvid);
512*bbb1b6f9SApple OSS Distributions 		if (error) {
513*bbb1b6f9SApple OSS Distributions 			goto end;
514*bbb1b6f9SApple OSS Distributions 		}
515*bbb1b6f9SApple OSS Distributions 
516*bbb1b6f9SApple OSS Distributions 		/* We don't want to mess with case insensitivity and unicode, so the plan to
517*bbb1b6f9SApple OSS Distributions 		 *  check here is
518*bbb1b6f9SApple OSS Distributions 		 *   1. try to get the lower root's parent
519*bbb1b6f9SApple OSS Distributions 		 *   2. If we get a parent, then perform a lookup on the lower file system
520*bbb1b6f9SApple OSS Distributions 		 *  using the parent and the passed in cnp
521*bbb1b6f9SApple OSS Distributions 		 *   3. If that worked and we got a vp, then see if the vp is lowerrootvp. If
522*bbb1b6f9SApple OSS Distributions 		 *  so we got a match
523*bbb1b6f9SApple OSS Distributions 		 *   4. Anything else results in ENOENT.
524*bbb1b6f9SApple OSS Distributions 		 */
525*bbb1b6f9SApple OSS Distributions 		error = null_get_lowerparent(null_mp->nullm_lowerrootvp, &ldvp, ectx);
526*bbb1b6f9SApple OSS Distributions 
527*bbb1b6f9SApple OSS Distributions 		if (error == 0) {
528*bbb1b6f9SApple OSS Distributions 			error = VNOP_LOOKUP(ldvp, &lvp, cnp, ectx);
529*bbb1b6f9SApple OSS Distributions 			vnode_put(ldvp);
530*bbb1b6f9SApple OSS Distributions 
531*bbb1b6f9SApple OSS Distributions 			if (error == 0) {
532*bbb1b6f9SApple OSS Distributions 				// nullm_lowerrootvp is only touched during mount and unmount so we don't need the lock to check it.
533*bbb1b6f9SApple OSS Distributions 				if (lvp == null_mp->nullm_lowerrootvp) {
534*bbb1b6f9SApple OSS Distributions 					/* always check the hashmap for a vnode for this, the root of the
535*bbb1b6f9SApple OSS Distributions 					 * mirrored system */
536*bbb1b6f9SApple OSS Distributions 					error = null_nodeget(mp, lvp, dvp, &vp, cnp, 0);
537*bbb1b6f9SApple OSS Distributions 				} else {
538*bbb1b6f9SApple OSS Distributions 					error = ENOENT;
539*bbb1b6f9SApple OSS Distributions 				}
540*bbb1b6f9SApple OSS Distributions 				vnode_put(lvp);
541*bbb1b6f9SApple OSS Distributions 			}
542*bbb1b6f9SApple OSS Distributions 		}
543*bbb1b6f9SApple OSS Distributions 		vnode_put(null_mp->nullm_lowerrootvp);
544*bbb1b6f9SApple OSS Distributions 	}
545*bbb1b6f9SApple OSS Distributions 
546*bbb1b6f9SApple OSS Distributions end:
547*bbb1b6f9SApple OSS Distributions 	nullfs_cleanup_patched_context(null_mp, ectx);
548*bbb1b6f9SApple OSS Distributions 	if (error == 0) {
549*bbb1b6f9SApple OSS Distributions 		*ap->a_vpp = vp;
550*bbb1b6f9SApple OSS Distributions 	}
551*bbb1b6f9SApple OSS Distributions 	return error;
552*bbb1b6f9SApple OSS Distributions }
553*bbb1b6f9SApple OSS Distributions 
554*bbb1b6f9SApple OSS Distributions /*
555*bbb1b6f9SApple OSS Distributions  * We have to carry on the locking protocol on the null layer vnodes
556*bbb1b6f9SApple OSS Distributions  * as we progress through the tree. We also have to enforce read-only
557*bbb1b6f9SApple OSS Distributions  * if this layer is mounted read-only.
558*bbb1b6f9SApple OSS Distributions  */
559*bbb1b6f9SApple OSS Distributions static int
null_lookup(struct vnop_lookup_args * ap)560*bbb1b6f9SApple OSS Distributions null_lookup(struct vnop_lookup_args * ap)
561*bbb1b6f9SApple OSS Distributions {
562*bbb1b6f9SApple OSS Distributions 	struct componentname * cnp = ap->a_cnp;
563*bbb1b6f9SApple OSS Distributions 	struct vnode * dvp         = ap->a_dvp;
564*bbb1b6f9SApple OSS Distributions 	struct vnode *vp, *ldvp, *lvp;
565*bbb1b6f9SApple OSS Distributions 	struct mount * mp;
566*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp;
567*bbb1b6f9SApple OSS Distributions 	int error;
568*bbb1b6f9SApple OSS Distributions 	vfs_context_t ectx;
569*bbb1b6f9SApple OSS Distributions 
570*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s parent: %p component: %.*s\n", __FUNCTION__, ap->a_dvp, cnp->cn_namelen, cnp->cn_nameptr);
571*bbb1b6f9SApple OSS Distributions 
572*bbb1b6f9SApple OSS Distributions 	mp = vnode_mount(dvp);
573*bbb1b6f9SApple OSS Distributions 	/* rename and delete are not allowed. this is a read only file system */
574*bbb1b6f9SApple OSS Distributions 	if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME || cnp->cn_nameiop == CREATE) {
575*bbb1b6f9SApple OSS Distributions 		return EROFS;
576*bbb1b6f9SApple OSS Distributions 	}
577*bbb1b6f9SApple OSS Distributions 	null_mp = MOUNTTONULLMOUNT(mp);
578*bbb1b6f9SApple OSS Distributions 
579*bbb1b6f9SApple OSS Distributions 
580*bbb1b6f9SApple OSS Distributions 	lck_mtx_lock(&null_mp->nullm_lock);
581*bbb1b6f9SApple OSS Distributions 	if (nullfs_isspecialvp(dvp)) {
582*bbb1b6f9SApple OSS Distributions 		error = null_special_lookup(ap);
583*bbb1b6f9SApple OSS Distributions 		// null_special_lookup drops the lock
584*bbb1b6f9SApple OSS Distributions 		return error;
585*bbb1b6f9SApple OSS Distributions 	}
586*bbb1b6f9SApple OSS Distributions 	lck_mtx_unlock(&null_mp->nullm_lock);
587*bbb1b6f9SApple OSS Distributions 
588*bbb1b6f9SApple OSS Distributions 	// . and .. handling
589*bbb1b6f9SApple OSS Distributions 	if (cnp->cn_nameptr[0] == '.') {
590*bbb1b6f9SApple OSS Distributions 		if (cnp->cn_namelen == 1) {
591*bbb1b6f9SApple OSS Distributions 			vp = dvp;
592*bbb1b6f9SApple OSS Distributions 		} else if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
593*bbb1b6f9SApple OSS Distributions 			/* mount point crossing is handled in null_special_lookup */
594*bbb1b6f9SApple OSS Distributions 			vp = vnode_parent(dvp);
595*bbb1b6f9SApple OSS Distributions 		} else {
596*bbb1b6f9SApple OSS Distributions 			goto notdot;
597*bbb1b6f9SApple OSS Distributions 		}
598*bbb1b6f9SApple OSS Distributions 
599*bbb1b6f9SApple OSS Distributions 		error = vp ? vnode_get(vp) : ENOENT;
600*bbb1b6f9SApple OSS Distributions 
601*bbb1b6f9SApple OSS Distributions 		if (error == 0) {
602*bbb1b6f9SApple OSS Distributions 			*ap->a_vpp = vp;
603*bbb1b6f9SApple OSS Distributions 		}
604*bbb1b6f9SApple OSS Distributions 
605*bbb1b6f9SApple OSS Distributions 		return error;
606*bbb1b6f9SApple OSS Distributions 	}
607*bbb1b6f9SApple OSS Distributions 
608*bbb1b6f9SApple OSS Distributions notdot:
609*bbb1b6f9SApple OSS Distributions 	ectx = nullfs_get_patched_context(null_mp, ap->a_context);
610*bbb1b6f9SApple OSS Distributions 	ldvp = NULLVPTOLOWERVP(dvp);
611*bbb1b6f9SApple OSS Distributions 	vp = lvp = NULL;
612*bbb1b6f9SApple OSS Distributions 
613*bbb1b6f9SApple OSS Distributions 	/*
614*bbb1b6f9SApple OSS Distributions 	 * Hold ldvp.  The reference on it, owned by dvp, is lost in
615*bbb1b6f9SApple OSS Distributions 	 * case of dvp reclamation.
616*bbb1b6f9SApple OSS Distributions 	 */
617*bbb1b6f9SApple OSS Distributions 	error = vnode_getwithref(ldvp);
618*bbb1b6f9SApple OSS Distributions 	if (error) {
619*bbb1b6f9SApple OSS Distributions 		nullfs_cleanup_patched_context(null_mp, ectx);
620*bbb1b6f9SApple OSS Distributions 		return error;
621*bbb1b6f9SApple OSS Distributions 	}
622*bbb1b6f9SApple OSS Distributions 
623*bbb1b6f9SApple OSS Distributions 	error = VNOP_LOOKUP(ldvp, &lvp, cnp, ectx);
624*bbb1b6f9SApple OSS Distributions 
625*bbb1b6f9SApple OSS Distributions 	vnode_put(ldvp);
626*bbb1b6f9SApple OSS Distributions 
627*bbb1b6f9SApple OSS Distributions 	if ((error == 0 || error == EJUSTRETURN) && lvp != NULL) {
628*bbb1b6f9SApple OSS Distributions 		if (ldvp == lvp) {
629*bbb1b6f9SApple OSS Distributions 			vp    = dvp;
630*bbb1b6f9SApple OSS Distributions 			error = vnode_get(vp);
631*bbb1b6f9SApple OSS Distributions 		} else {
632*bbb1b6f9SApple OSS Distributions 			error = null_nodeget(mp, lvp, dvp, &vp, cnp, 0);
633*bbb1b6f9SApple OSS Distributions 		}
634*bbb1b6f9SApple OSS Distributions 		if (error == 0) {
635*bbb1b6f9SApple OSS Distributions 			*ap->a_vpp = vp;
636*bbb1b6f9SApple OSS Distributions 		}
637*bbb1b6f9SApple OSS Distributions 		/* if we got lvp, drop the iocount from VNOP_LOOKUP */
638*bbb1b6f9SApple OSS Distributions 		if (lvp != NULL) {
639*bbb1b6f9SApple OSS Distributions 			vnode_put(lvp);
640*bbb1b6f9SApple OSS Distributions 		}
641*bbb1b6f9SApple OSS Distributions 	}
642*bbb1b6f9SApple OSS Distributions 
643*bbb1b6f9SApple OSS Distributions 	nullfs_cleanup_patched_context(null_mp, ectx);
644*bbb1b6f9SApple OSS Distributions 	return error;
645*bbb1b6f9SApple OSS Distributions }
646*bbb1b6f9SApple OSS Distributions 
647*bbb1b6f9SApple OSS Distributions /*
648*bbb1b6f9SApple OSS Distributions  * Don't think this needs to do anything
649*bbb1b6f9SApple OSS Distributions  */
650*bbb1b6f9SApple OSS Distributions static int
null_inactive(__unused struct vnop_inactive_args * ap)651*bbb1b6f9SApple OSS Distributions null_inactive(__unused struct vnop_inactive_args * ap)
652*bbb1b6f9SApple OSS Distributions {
653*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s %p\n", __FUNCTION__, ap->a_vp);
654*bbb1b6f9SApple OSS Distributions 
655*bbb1b6f9SApple OSS Distributions 	return 0;
656*bbb1b6f9SApple OSS Distributions }
657*bbb1b6f9SApple OSS Distributions 
658*bbb1b6f9SApple OSS Distributions static int
null_reclaim(struct vnop_reclaim_args * ap)659*bbb1b6f9SApple OSS Distributions null_reclaim(struct vnop_reclaim_args * ap)
660*bbb1b6f9SApple OSS Distributions {
661*bbb1b6f9SApple OSS Distributions 	struct vnode * vp;
662*bbb1b6f9SApple OSS Distributions 	struct null_node * xp;
663*bbb1b6f9SApple OSS Distributions 	struct vnode * lowervp;
664*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(ap->a_vp));
665*bbb1b6f9SApple OSS Distributions 
666*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s %p\n", __FUNCTION__, ap->a_vp);
667*bbb1b6f9SApple OSS Distributions 
668*bbb1b6f9SApple OSS Distributions 	vp = ap->a_vp;
669*bbb1b6f9SApple OSS Distributions 
670*bbb1b6f9SApple OSS Distributions 	xp      = VTONULL(vp);
671*bbb1b6f9SApple OSS Distributions 	lowervp = xp->null_lowervp;
672*bbb1b6f9SApple OSS Distributions 
673*bbb1b6f9SApple OSS Distributions 	lck_mtx_lock(&null_mp->nullm_lock);
674*bbb1b6f9SApple OSS Distributions 
675*bbb1b6f9SApple OSS Distributions 	vnode_removefsref(vp);
676*bbb1b6f9SApple OSS Distributions 
677*bbb1b6f9SApple OSS Distributions 	if (lowervp != NULL) {
678*bbb1b6f9SApple OSS Distributions 		/* root and second don't have a lowervp, so nothing to release and nothing
679*bbb1b6f9SApple OSS Distributions 		 * got hashed */
680*bbb1b6f9SApple OSS Distributions 		if (xp->null_flags & NULL_FLAG_HASHED) {
681*bbb1b6f9SApple OSS Distributions 			/* only call this if we actually made it into the hash list. reclaim gets
682*bbb1b6f9SApple OSS Distributions 			 *  called also to
683*bbb1b6f9SApple OSS Distributions 			 *  clean up a vnode that got created when it didn't need to under race
684*bbb1b6f9SApple OSS Distributions 			 *  conditions */
685*bbb1b6f9SApple OSS Distributions 			null_hashrem(xp);
686*bbb1b6f9SApple OSS Distributions 		}
687*bbb1b6f9SApple OSS Distributions 		vnode_rele(lowervp);
688*bbb1b6f9SApple OSS Distributions 	}
689*bbb1b6f9SApple OSS Distributions 
690*bbb1b6f9SApple OSS Distributions 	if (vp == null_mp->nullm_rootvp) {
691*bbb1b6f9SApple OSS Distributions 		null_mp->nullm_rootvp = NULL;
692*bbb1b6f9SApple OSS Distributions 	} else if (vp == null_mp->nullm_secondvp) {
693*bbb1b6f9SApple OSS Distributions 		null_mp->nullm_secondvp = NULL;
694*bbb1b6f9SApple OSS Distributions 	}
695*bbb1b6f9SApple OSS Distributions 
696*bbb1b6f9SApple OSS Distributions 	lck_mtx_unlock(&null_mp->nullm_lock);
697*bbb1b6f9SApple OSS Distributions 
698*bbb1b6f9SApple OSS Distributions 	cache_purge(vp);
699*bbb1b6f9SApple OSS Distributions 	vnode_clearfsnode(vp);
700*bbb1b6f9SApple OSS Distributions 
701*bbb1b6f9SApple OSS Distributions 	kfree_type(struct null_node, xp);
702*bbb1b6f9SApple OSS Distributions 
703*bbb1b6f9SApple OSS Distributions 	return 0;
704*bbb1b6f9SApple OSS Distributions }
705*bbb1b6f9SApple OSS Distributions 
706*bbb1b6f9SApple OSS Distributions #define DIRENT_SZ(dp) ((sizeof(struct dirent) - NAME_MAX) + (((dp)->d_namlen + 1 + 3) & ~3))
707*bbb1b6f9SApple OSS Distributions 
708*bbb1b6f9SApple OSS Distributions static int
store_entry_special(ino_t ino,const char * name,struct uio * uio)709*bbb1b6f9SApple OSS Distributions store_entry_special(ino_t ino, const char * name, struct uio * uio)
710*bbb1b6f9SApple OSS Distributions {
711*bbb1b6f9SApple OSS Distributions 	struct dirent e;
712*bbb1b6f9SApple OSS Distributions 	size_t namelen = strlen(name);
713*bbb1b6f9SApple OSS Distributions 	int error      = EINVAL;
714*bbb1b6f9SApple OSS Distributions 
715*bbb1b6f9SApple OSS Distributions 	if (namelen + 1 <= NAME_MAX) {
716*bbb1b6f9SApple OSS Distributions 		memset(&e, 0, sizeof(e));
717*bbb1b6f9SApple OSS Distributions 
718*bbb1b6f9SApple OSS Distributions 		e.d_ino  = ino;
719*bbb1b6f9SApple OSS Distributions 		e.d_type = DT_DIR;
720*bbb1b6f9SApple OSS Distributions 
721*bbb1b6f9SApple OSS Distributions 		e.d_namlen = namelen; /* don't include NUL */
722*bbb1b6f9SApple OSS Distributions 		e.d_reclen = DIRENT_SZ(&e);
723*bbb1b6f9SApple OSS Distributions 		if (uio_resid(uio) >= e.d_reclen) {
724*bbb1b6f9SApple OSS Distributions 			strlcpy(e.d_name, name, NAME_MAX);
725*bbb1b6f9SApple OSS Distributions 			error = uiomove((caddr_t)&e, e.d_reclen, uio);
726*bbb1b6f9SApple OSS Distributions 		} else {
727*bbb1b6f9SApple OSS Distributions 			error = EMSGSIZE;
728*bbb1b6f9SApple OSS Distributions 		}
729*bbb1b6f9SApple OSS Distributions 	}
730*bbb1b6f9SApple OSS Distributions 	return error;
731*bbb1b6f9SApple OSS Distributions }
732*bbb1b6f9SApple OSS Distributions 
733*bbb1b6f9SApple OSS Distributions static int
nullfs_special_readdir(struct vnop_readdir_args * ap)734*bbb1b6f9SApple OSS Distributions nullfs_special_readdir(struct vnop_readdir_args * ap)
735*bbb1b6f9SApple OSS Distributions {
736*bbb1b6f9SApple OSS Distributions 	struct vnode * vp           = ap->a_vp;
737*bbb1b6f9SApple OSS Distributions 	struct uio * uio            = ap->a_uio;
738*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(vp));
739*bbb1b6f9SApple OSS Distributions 	off_t offset                = uio_offset(uio);
740*bbb1b6f9SApple OSS Distributions 	int error                   = ERANGE;
741*bbb1b6f9SApple OSS Distributions 	int items                   = 0;
742*bbb1b6f9SApple OSS Distributions 	ino_t ino                   = 0;
743*bbb1b6f9SApple OSS Distributions 	const char * name           = NULL;
744*bbb1b6f9SApple OSS Distributions 	boolean_t locked = TRUE;
745*bbb1b6f9SApple OSS Distributions 
746*bbb1b6f9SApple OSS Distributions 	if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF)) {
747*bbb1b6f9SApple OSS Distributions 		lck_mtx_unlock(&null_mp->nullm_lock);
748*bbb1b6f9SApple OSS Distributions 		return EINVAL;
749*bbb1b6f9SApple OSS Distributions 	}
750*bbb1b6f9SApple OSS Distributions 
751*bbb1b6f9SApple OSS Distributions 	if (offset == 0) {
752*bbb1b6f9SApple OSS Distributions 		/* . case */
753*bbb1b6f9SApple OSS Distributions 		if (vp == null_mp->nullm_rootvp) {
754*bbb1b6f9SApple OSS Distributions 			ino = NULL_ROOT_INO;
755*bbb1b6f9SApple OSS Distributions 		} else { /* only get here if vp matches nullm_rootvp or nullm_secondvp */
756*bbb1b6f9SApple OSS Distributions 			ino = NULL_SECOND_INO;
757*bbb1b6f9SApple OSS Distributions 		}
758*bbb1b6f9SApple OSS Distributions 		error = store_entry_special(ino, ".", uio);
759*bbb1b6f9SApple OSS Distributions 		if (error) {
760*bbb1b6f9SApple OSS Distributions 			goto out;
761*bbb1b6f9SApple OSS Distributions 		}
762*bbb1b6f9SApple OSS Distributions 		offset++;
763*bbb1b6f9SApple OSS Distributions 		items++;
764*bbb1b6f9SApple OSS Distributions 	}
765*bbb1b6f9SApple OSS Distributions 	if (offset == 1) {
766*bbb1b6f9SApple OSS Distributions 		/* .. case */
767*bbb1b6f9SApple OSS Distributions 		/* only get here if vp matches nullm_rootvp or nullm_secondvp */
768*bbb1b6f9SApple OSS Distributions 		ino = NULL_ROOT_INO;
769*bbb1b6f9SApple OSS Distributions 
770*bbb1b6f9SApple OSS Distributions 		error = store_entry_special(ino, "..", uio);
771*bbb1b6f9SApple OSS Distributions 		if (error) {
772*bbb1b6f9SApple OSS Distributions 			goto out;
773*bbb1b6f9SApple OSS Distributions 		}
774*bbb1b6f9SApple OSS Distributions 		offset++;
775*bbb1b6f9SApple OSS Distributions 		items++;
776*bbb1b6f9SApple OSS Distributions 	}
777*bbb1b6f9SApple OSS Distributions 	if (offset == 2) {
778*bbb1b6f9SApple OSS Distributions 		/* the directory case */
779*bbb1b6f9SApple OSS Distributions 		if (vp == null_mp->nullm_rootvp) {
780*bbb1b6f9SApple OSS Distributions 			ino  = NULL_SECOND_INO;
781*bbb1b6f9SApple OSS Distributions 			name = "d";
782*bbb1b6f9SApple OSS Distributions 		} else { /* only get here if vp matches nullm_rootvp or nullm_secondvp */
783*bbb1b6f9SApple OSS Distributions 			// drop the lock before performing operations on nullm_lowerrootvp
784*bbb1b6f9SApple OSS Distributions 			lck_mtx_unlock(&null_mp->nullm_lock);
785*bbb1b6f9SApple OSS Distributions 			locked = FALSE;
786*bbb1b6f9SApple OSS Distributions 			ino = NULL_THIRD_INO;
787*bbb1b6f9SApple OSS Distributions 			if (vnode_getwithvid(null_mp->nullm_lowerrootvp, null_mp->nullm_lowerrootvid)) {
788*bbb1b6f9SApple OSS Distributions 				/* In this case the lower file system has been ripped out from under us,
789*bbb1b6f9SApple OSS Distributions 				 *  but we don't want to error out
790*bbb1b6f9SApple OSS Distributions 				 *  Instead we just want d to look empty. */
791*bbb1b6f9SApple OSS Distributions 				error = 0;
792*bbb1b6f9SApple OSS Distributions 				goto out;
793*bbb1b6f9SApple OSS Distributions 			}
794*bbb1b6f9SApple OSS Distributions 			name = vnode_getname_printable(null_mp->nullm_lowerrootvp);
795*bbb1b6f9SApple OSS Distributions 		}
796*bbb1b6f9SApple OSS Distributions 		error = store_entry_special(ino, name, uio);
797*bbb1b6f9SApple OSS Distributions 
798*bbb1b6f9SApple OSS Distributions 		if (ino == NULL_THIRD_INO) {
799*bbb1b6f9SApple OSS Distributions 			vnode_putname_printable(name);
800*bbb1b6f9SApple OSS Distributions 			vnode_put(null_mp->nullm_lowerrootvp);
801*bbb1b6f9SApple OSS Distributions 		}
802*bbb1b6f9SApple OSS Distributions 
803*bbb1b6f9SApple OSS Distributions 		if (error) {
804*bbb1b6f9SApple OSS Distributions 			goto out;
805*bbb1b6f9SApple OSS Distributions 		}
806*bbb1b6f9SApple OSS Distributions 		offset++;
807*bbb1b6f9SApple OSS Distributions 		items++;
808*bbb1b6f9SApple OSS Distributions 	}
809*bbb1b6f9SApple OSS Distributions 
810*bbb1b6f9SApple OSS Distributions out:
811*bbb1b6f9SApple OSS Distributions 	if (locked) {
812*bbb1b6f9SApple OSS Distributions 		lck_mtx_unlock(&null_mp->nullm_lock);
813*bbb1b6f9SApple OSS Distributions 	}
814*bbb1b6f9SApple OSS Distributions 	if (error == EMSGSIZE) {
815*bbb1b6f9SApple OSS Distributions 		error = 0; /* return success if we ran out of space, but we wanted to make
816*bbb1b6f9SApple OSS Distributions 		            *  sure that we didn't update offset and items incorrectly */
817*bbb1b6f9SApple OSS Distributions 	}
818*bbb1b6f9SApple OSS Distributions 	uio_setoffset(uio, offset);
819*bbb1b6f9SApple OSS Distributions 	if (ap->a_numdirent) {
820*bbb1b6f9SApple OSS Distributions 		*ap->a_numdirent = items;
821*bbb1b6f9SApple OSS Distributions 	}
822*bbb1b6f9SApple OSS Distributions 	return error;
823*bbb1b6f9SApple OSS Distributions }
824*bbb1b6f9SApple OSS Distributions 
825*bbb1b6f9SApple OSS Distributions static int
nullfs_readdir(struct vnop_readdir_args * ap)826*bbb1b6f9SApple OSS Distributions nullfs_readdir(struct vnop_readdir_args * ap)
827*bbb1b6f9SApple OSS Distributions {
828*bbb1b6f9SApple OSS Distributions 	struct vnode *vp, *lvp;
829*bbb1b6f9SApple OSS Distributions 	int error;
830*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(ap->a_vp));
831*bbb1b6f9SApple OSS Distributions 
832*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s %p\n", __FUNCTION__, ap->a_vp);
833*bbb1b6f9SApple OSS Distributions 	/* assumption is that any vp that comes through here had to go through lookup
834*bbb1b6f9SApple OSS Distributions 	 */
835*bbb1b6f9SApple OSS Distributions 
836*bbb1b6f9SApple OSS Distributions 	lck_mtx_lock(&null_mp->nullm_lock);
837*bbb1b6f9SApple OSS Distributions 	if (nullfs_isspecialvp(ap->a_vp)) {
838*bbb1b6f9SApple OSS Distributions 		error = nullfs_special_readdir(ap);
839*bbb1b6f9SApple OSS Distributions 		// nullfs_special_readdir drops the lock
840*bbb1b6f9SApple OSS Distributions 		return error;
841*bbb1b6f9SApple OSS Distributions 	}
842*bbb1b6f9SApple OSS Distributions 	lck_mtx_unlock(&null_mp->nullm_lock);
843*bbb1b6f9SApple OSS Distributions 
844*bbb1b6f9SApple OSS Distributions 	vfs_context_t ectx = nullfs_get_patched_context(null_mp, ap->a_context);
845*bbb1b6f9SApple OSS Distributions 	vp    = ap->a_vp;
846*bbb1b6f9SApple OSS Distributions 	lvp   = NULLVPTOLOWERVP(vp);
847*bbb1b6f9SApple OSS Distributions 	error = vnode_getwithref(lvp);
848*bbb1b6f9SApple OSS Distributions 	if (error == 0) {
849*bbb1b6f9SApple OSS Distributions 		error = VNOP_READDIR(lvp, ap->a_uio, ap->a_flags, ap->a_eofflag, ap->a_numdirent, ectx);
850*bbb1b6f9SApple OSS Distributions 		vnode_put(lvp);
851*bbb1b6f9SApple OSS Distributions 	}
852*bbb1b6f9SApple OSS Distributions 
853*bbb1b6f9SApple OSS Distributions 	nullfs_cleanup_patched_context(null_mp, ectx);
854*bbb1b6f9SApple OSS Distributions 	return error;
855*bbb1b6f9SApple OSS Distributions }
856*bbb1b6f9SApple OSS Distributions 
857*bbb1b6f9SApple OSS Distributions static int
nullfs_readlink(struct vnop_readlink_args * ap)858*bbb1b6f9SApple OSS Distributions nullfs_readlink(struct vnop_readlink_args * ap)
859*bbb1b6f9SApple OSS Distributions {
860*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s %p\n", __FUNCTION__, ap->a_vp);
861*bbb1b6f9SApple OSS Distributions 	int error;
862*bbb1b6f9SApple OSS Distributions 	struct vnode *vp, *lvp;
863*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(ap->a_vp));
864*bbb1b6f9SApple OSS Distributions 
865*bbb1b6f9SApple OSS Distributions 	if (nullfs_checkspecialvp(ap->a_vp)) {
866*bbb1b6f9SApple OSS Distributions 		return ENOTSUP; /* the special vnodes aren't links */
867*bbb1b6f9SApple OSS Distributions 	}
868*bbb1b6f9SApple OSS Distributions 
869*bbb1b6f9SApple OSS Distributions 	vfs_context_t ectx = nullfs_get_patched_context(null_mp, ap->a_context);
870*bbb1b6f9SApple OSS Distributions 	vp  = ap->a_vp;
871*bbb1b6f9SApple OSS Distributions 	lvp = NULLVPTOLOWERVP(vp);
872*bbb1b6f9SApple OSS Distributions 
873*bbb1b6f9SApple OSS Distributions 	error = vnode_getwithref(lvp);
874*bbb1b6f9SApple OSS Distributions 	if (error == 0) {
875*bbb1b6f9SApple OSS Distributions 		error = VNOP_READLINK(lvp, ap->a_uio, ectx);
876*bbb1b6f9SApple OSS Distributions 		vnode_put(lvp);
877*bbb1b6f9SApple OSS Distributions 
878*bbb1b6f9SApple OSS Distributions 		if (error) {
879*bbb1b6f9SApple OSS Distributions 			NULLFSDEBUG("readlink failed: %d\n", error);
880*bbb1b6f9SApple OSS Distributions 		}
881*bbb1b6f9SApple OSS Distributions 	}
882*bbb1b6f9SApple OSS Distributions 
883*bbb1b6f9SApple OSS Distributions 	nullfs_cleanup_patched_context(null_mp, ectx);
884*bbb1b6f9SApple OSS Distributions 	return error;
885*bbb1b6f9SApple OSS Distributions }
886*bbb1b6f9SApple OSS Distributions 
887*bbb1b6f9SApple OSS Distributions static int
nullfs_pathconf(__unused struct vnop_pathconf_args * args)888*bbb1b6f9SApple OSS Distributions nullfs_pathconf(__unused struct vnop_pathconf_args * args)
889*bbb1b6f9SApple OSS Distributions {
890*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
891*bbb1b6f9SApple OSS Distributions 	return EINVAL;
892*bbb1b6f9SApple OSS Distributions }
893*bbb1b6f9SApple OSS Distributions 
894*bbb1b6f9SApple OSS Distributions static int
nullfs_fsync(__unused struct vnop_fsync_args * args)895*bbb1b6f9SApple OSS Distributions nullfs_fsync(__unused struct vnop_fsync_args * args)
896*bbb1b6f9SApple OSS Distributions {
897*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
898*bbb1b6f9SApple OSS Distributions 	return 0;
899*bbb1b6f9SApple OSS Distributions }
900*bbb1b6f9SApple OSS Distributions 
901*bbb1b6f9SApple OSS Distributions static int
nullfs_mmap(struct vnop_mmap_args * args)902*bbb1b6f9SApple OSS Distributions nullfs_mmap(struct vnop_mmap_args * args)
903*bbb1b6f9SApple OSS Distributions {
904*bbb1b6f9SApple OSS Distributions 	int error;
905*bbb1b6f9SApple OSS Distributions 	struct vnode *vp, *lvp;
906*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(args->a_vp));
907*bbb1b6f9SApple OSS Distributions 
908*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
909*bbb1b6f9SApple OSS Distributions 
910*bbb1b6f9SApple OSS Distributions 	if (nullfs_checkspecialvp(args->a_vp)) {
911*bbb1b6f9SApple OSS Distributions 		return 0; /* nothing extra needed */
912*bbb1b6f9SApple OSS Distributions 	}
913*bbb1b6f9SApple OSS Distributions 
914*bbb1b6f9SApple OSS Distributions 	vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
915*bbb1b6f9SApple OSS Distributions 	vp    = args->a_vp;
916*bbb1b6f9SApple OSS Distributions 	lvp   = NULLVPTOLOWERVP(vp);
917*bbb1b6f9SApple OSS Distributions 	error = vnode_getwithref(lvp);
918*bbb1b6f9SApple OSS Distributions 	if (error == 0) {
919*bbb1b6f9SApple OSS Distributions 		error = VNOP_MMAP(lvp, args->a_fflags, ectx);
920*bbb1b6f9SApple OSS Distributions 		vnode_put(lvp);
921*bbb1b6f9SApple OSS Distributions 	}
922*bbb1b6f9SApple OSS Distributions 
923*bbb1b6f9SApple OSS Distributions 	nullfs_cleanup_patched_context(null_mp, ectx);
924*bbb1b6f9SApple OSS Distributions 	return error;
925*bbb1b6f9SApple OSS Distributions }
926*bbb1b6f9SApple OSS Distributions 
927*bbb1b6f9SApple OSS Distributions static int
nullfs_mnomap(struct vnop_mnomap_args * args)928*bbb1b6f9SApple OSS Distributions nullfs_mnomap(struct vnop_mnomap_args * args)
929*bbb1b6f9SApple OSS Distributions {
930*bbb1b6f9SApple OSS Distributions 	int error;
931*bbb1b6f9SApple OSS Distributions 	struct vnode *vp, *lvp;
932*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(args->a_vp));
933*bbb1b6f9SApple OSS Distributions 
934*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
935*bbb1b6f9SApple OSS Distributions 
936*bbb1b6f9SApple OSS Distributions 	if (nullfs_checkspecialvp(args->a_vp)) {
937*bbb1b6f9SApple OSS Distributions 		return 0; /* nothing extra needed */
938*bbb1b6f9SApple OSS Distributions 	}
939*bbb1b6f9SApple OSS Distributions 
940*bbb1b6f9SApple OSS Distributions 	vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
941*bbb1b6f9SApple OSS Distributions 	vp    = args->a_vp;
942*bbb1b6f9SApple OSS Distributions 	lvp   = NULLVPTOLOWERVP(vp);
943*bbb1b6f9SApple OSS Distributions 	error = vnode_getwithref(lvp);
944*bbb1b6f9SApple OSS Distributions 	if (error == 0) {
945*bbb1b6f9SApple OSS Distributions 		error = VNOP_MNOMAP(lvp, ectx);
946*bbb1b6f9SApple OSS Distributions 		vnode_put(lvp);
947*bbb1b6f9SApple OSS Distributions 	}
948*bbb1b6f9SApple OSS Distributions 
949*bbb1b6f9SApple OSS Distributions 	nullfs_cleanup_patched_context(null_mp, ectx);
950*bbb1b6f9SApple OSS Distributions 	return error;
951*bbb1b6f9SApple OSS Distributions }
952*bbb1b6f9SApple OSS Distributions 
953*bbb1b6f9SApple OSS Distributions static int
nullfs_getxattr(struct vnop_getxattr_args * args)954*bbb1b6f9SApple OSS Distributions nullfs_getxattr(struct vnop_getxattr_args * args)
955*bbb1b6f9SApple OSS Distributions {
956*bbb1b6f9SApple OSS Distributions 	int error;
957*bbb1b6f9SApple OSS Distributions 	struct vnode *vp, *lvp;
958*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(args->a_vp));
959*bbb1b6f9SApple OSS Distributions 
960*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
961*bbb1b6f9SApple OSS Distributions 
962*bbb1b6f9SApple OSS Distributions 	if (nullfs_checkspecialvp(args->a_vp)) {
963*bbb1b6f9SApple OSS Distributions 		return ENOATTR; /* no xattrs on the special vnodes */
964*bbb1b6f9SApple OSS Distributions 	}
965*bbb1b6f9SApple OSS Distributions 
966*bbb1b6f9SApple OSS Distributions 	vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
967*bbb1b6f9SApple OSS Distributions 	vp    = args->a_vp;
968*bbb1b6f9SApple OSS Distributions 	lvp   = NULLVPTOLOWERVP(vp);
969*bbb1b6f9SApple OSS Distributions 	error = vnode_getwithref(lvp);
970*bbb1b6f9SApple OSS Distributions 	if (error == 0) {
971*bbb1b6f9SApple OSS Distributions 		error = VNOP_GETXATTR(lvp, args->a_name, args->a_uio, args->a_size, args->a_options, ectx);
972*bbb1b6f9SApple OSS Distributions 		vnode_put(lvp);
973*bbb1b6f9SApple OSS Distributions 	}
974*bbb1b6f9SApple OSS Distributions 
975*bbb1b6f9SApple OSS Distributions 	nullfs_cleanup_patched_context(null_mp, ectx);
976*bbb1b6f9SApple OSS Distributions 	return error;
977*bbb1b6f9SApple OSS Distributions }
978*bbb1b6f9SApple OSS Distributions 
979*bbb1b6f9SApple OSS Distributions static int
nullfs_listxattr(struct vnop_listxattr_args * args)980*bbb1b6f9SApple OSS Distributions nullfs_listxattr(struct vnop_listxattr_args * args)
981*bbb1b6f9SApple OSS Distributions {
982*bbb1b6f9SApple OSS Distributions 	int error;
983*bbb1b6f9SApple OSS Distributions 	struct vnode *vp, *lvp;
984*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(args->a_vp));
985*bbb1b6f9SApple OSS Distributions 
986*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
987*bbb1b6f9SApple OSS Distributions 
988*bbb1b6f9SApple OSS Distributions 	if (nullfs_checkspecialvp(args->a_vp)) {
989*bbb1b6f9SApple OSS Distributions 		return 0; /* no xattrs on the special vnodes */
990*bbb1b6f9SApple OSS Distributions 	}
991*bbb1b6f9SApple OSS Distributions 
992*bbb1b6f9SApple OSS Distributions 	vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
993*bbb1b6f9SApple OSS Distributions 	vp    = args->a_vp;
994*bbb1b6f9SApple OSS Distributions 	lvp   = NULLVPTOLOWERVP(vp);
995*bbb1b6f9SApple OSS Distributions 	error = vnode_getwithref(lvp);
996*bbb1b6f9SApple OSS Distributions 	if (error == 0) {
997*bbb1b6f9SApple OSS Distributions 		error = VNOP_LISTXATTR(lvp, args->a_uio, args->a_size, args->a_options, ectx);
998*bbb1b6f9SApple OSS Distributions 		vnode_put(lvp);
999*bbb1b6f9SApple OSS Distributions 	}
1000*bbb1b6f9SApple OSS Distributions 
1001*bbb1b6f9SApple OSS Distributions 	nullfs_cleanup_patched_context(null_mp, ectx);
1002*bbb1b6f9SApple OSS Distributions 	return error;
1003*bbb1b6f9SApple OSS Distributions }
1004*bbb1b6f9SApple OSS Distributions 
1005*bbb1b6f9SApple OSS Distributions /* relies on v1 paging */
1006*bbb1b6f9SApple OSS Distributions static int
nullfs_pagein(struct vnop_pagein_args * ap)1007*bbb1b6f9SApple OSS Distributions nullfs_pagein(struct vnop_pagein_args * ap)
1008*bbb1b6f9SApple OSS Distributions {
1009*bbb1b6f9SApple OSS Distributions 	int error = EIO;
1010*bbb1b6f9SApple OSS Distributions 	struct vnode *vp, *lvp;
1011*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(ap->a_vp));
1012*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s %p\n", __FUNCTION__, ap->a_vp);
1013*bbb1b6f9SApple OSS Distributions 
1014*bbb1b6f9SApple OSS Distributions 	vp  = ap->a_vp;
1015*bbb1b6f9SApple OSS Distributions 	lvp = NULLVPTOLOWERVP(vp);
1016*bbb1b6f9SApple OSS Distributions 
1017*bbb1b6f9SApple OSS Distributions 	if (vnode_vtype(vp) != VREG) {
1018*bbb1b6f9SApple OSS Distributions 		return ENOTSUP;
1019*bbb1b6f9SApple OSS Distributions 	}
1020*bbb1b6f9SApple OSS Distributions 
1021*bbb1b6f9SApple OSS Distributions 	vfs_context_t ectx = nullfs_get_patched_context(null_mp, ap->a_context);
1022*bbb1b6f9SApple OSS Distributions 	/*
1023*bbb1b6f9SApple OSS Distributions 	 * Ask VM/UBC/VFS to do our bidding
1024*bbb1b6f9SApple OSS Distributions 	 */
1025*bbb1b6f9SApple OSS Distributions 	if (vnode_getwithvid(lvp, NULLVPTOLOWERVID(vp)) == 0) {
1026*bbb1b6f9SApple OSS Distributions 		vm_offset_t ioaddr;
1027*bbb1b6f9SApple OSS Distributions 		uio_t auio;
1028*bbb1b6f9SApple OSS Distributions 		kern_return_t kret;
1029*bbb1b6f9SApple OSS Distributions 		off_t bytes_to_commit;
1030*bbb1b6f9SApple OSS Distributions 		off_t lowersize;
1031*bbb1b6f9SApple OSS Distributions 		upl_t upl      = ap->a_pl;
1032*bbb1b6f9SApple OSS Distributions 		user_ssize_t bytes_remaining = 0;
1033*bbb1b6f9SApple OSS Distributions 
1034*bbb1b6f9SApple OSS Distributions 		auio = uio_create(1, ap->a_f_offset, UIO_SYSSPACE, UIO_READ);
1035*bbb1b6f9SApple OSS Distributions 		if (auio == NULL) {
1036*bbb1b6f9SApple OSS Distributions 			error = EIO;
1037*bbb1b6f9SApple OSS Distributions 			goto exit_no_unmap;
1038*bbb1b6f9SApple OSS Distributions 		}
1039*bbb1b6f9SApple OSS Distributions 
1040*bbb1b6f9SApple OSS Distributions 		kret = ubc_upl_map(upl, &ioaddr);
1041*bbb1b6f9SApple OSS Distributions 		if (KERN_SUCCESS != kret) {
1042*bbb1b6f9SApple OSS Distributions 			panic("nullfs_pagein: ubc_upl_map() failed with (%d)", kret);
1043*bbb1b6f9SApple OSS Distributions 		}
1044*bbb1b6f9SApple OSS Distributions 
1045*bbb1b6f9SApple OSS Distributions 		ioaddr += ap->a_pl_offset;
1046*bbb1b6f9SApple OSS Distributions 
1047*bbb1b6f9SApple OSS Distributions 		error = uio_addiov(auio, (user_addr_t)ioaddr, ap->a_size);
1048*bbb1b6f9SApple OSS Distributions 		if (error) {
1049*bbb1b6f9SApple OSS Distributions 			goto exit;
1050*bbb1b6f9SApple OSS Distributions 		}
1051*bbb1b6f9SApple OSS Distributions 
1052*bbb1b6f9SApple OSS Distributions 		lowersize = ubc_getsize(lvp);
1053*bbb1b6f9SApple OSS Distributions 		if (lowersize != ubc_getsize(vp)) {
1054*bbb1b6f9SApple OSS Distributions 			(void)ubc_setsize(vp, lowersize); /* ignore failures, nothing can be done */
1055*bbb1b6f9SApple OSS Distributions 		}
1056*bbb1b6f9SApple OSS Distributions 
1057*bbb1b6f9SApple OSS Distributions 		error = VNOP_READ(lvp, auio, ((ap->a_flags & UPL_IOSYNC) ? IO_SYNC : 0), ectx);
1058*bbb1b6f9SApple OSS Distributions 
1059*bbb1b6f9SApple OSS Distributions 		bytes_remaining = uio_resid(auio);
1060*bbb1b6f9SApple OSS Distributions 		if (bytes_remaining > 0 && bytes_remaining <= (user_ssize_t)ap->a_size) {
1061*bbb1b6f9SApple OSS Distributions 			/* zero bytes that weren't read in to the upl */
1062*bbb1b6f9SApple OSS Distributions 			bzero((void*)((uintptr_t)(ioaddr + ap->a_size - bytes_remaining)), (size_t) bytes_remaining);
1063*bbb1b6f9SApple OSS Distributions 		}
1064*bbb1b6f9SApple OSS Distributions 
1065*bbb1b6f9SApple OSS Distributions exit:
1066*bbb1b6f9SApple OSS Distributions 		kret = ubc_upl_unmap(upl);
1067*bbb1b6f9SApple OSS Distributions 		if (KERN_SUCCESS != kret) {
1068*bbb1b6f9SApple OSS Distributions 			panic("nullfs_pagein: ubc_upl_unmap() failed with (%d)", kret);
1069*bbb1b6f9SApple OSS Distributions 		}
1070*bbb1b6f9SApple OSS Distributions 
1071*bbb1b6f9SApple OSS Distributions 		if (auio != NULL) {
1072*bbb1b6f9SApple OSS Distributions 			uio_free(auio);
1073*bbb1b6f9SApple OSS Distributions 		}
1074*bbb1b6f9SApple OSS Distributions 
1075*bbb1b6f9SApple OSS Distributions exit_no_unmap:
1076*bbb1b6f9SApple OSS Distributions 		if ((ap->a_flags & UPL_NOCOMMIT) == 0) {
1077*bbb1b6f9SApple OSS Distributions 			if (!error && (bytes_remaining >= 0) && (bytes_remaining <= (user_ssize_t)ap->a_size)) {
1078*bbb1b6f9SApple OSS Distributions 				/* only commit what was read in (page aligned)*/
1079*bbb1b6f9SApple OSS Distributions 				bytes_to_commit = ap->a_size - bytes_remaining;
1080*bbb1b6f9SApple OSS Distributions 				if (bytes_to_commit) {
1081*bbb1b6f9SApple OSS Distributions 					/* need to make sure bytes_to_commit and byte_remaining are page aligned before calling ubc_upl_commit_range*/
1082*bbb1b6f9SApple OSS Distributions 					if (bytes_to_commit & PAGE_MASK) {
1083*bbb1b6f9SApple OSS Distributions 						bytes_to_commit = (bytes_to_commit & (~PAGE_MASK)) + (PAGE_MASK + 1);
1084*bbb1b6f9SApple OSS Distributions 						assert(bytes_to_commit <= (off_t)ap->a_size);
1085*bbb1b6f9SApple OSS Distributions 
1086*bbb1b6f9SApple OSS Distributions 						bytes_remaining = ap->a_size - bytes_to_commit;
1087*bbb1b6f9SApple OSS Distributions 					}
1088*bbb1b6f9SApple OSS Distributions 					ubc_upl_commit_range(upl, ap->a_pl_offset, (upl_size_t)bytes_to_commit, UPL_COMMIT_FREE_ON_EMPTY);
1089*bbb1b6f9SApple OSS Distributions 				}
1090*bbb1b6f9SApple OSS Distributions 
1091*bbb1b6f9SApple OSS Distributions 				/* abort anything thats left */
1092*bbb1b6f9SApple OSS Distributions 				if (bytes_remaining) {
1093*bbb1b6f9SApple OSS Distributions 					ubc_upl_abort_range(upl, ap->a_pl_offset + bytes_to_commit, (upl_size_t)bytes_remaining, UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
1094*bbb1b6f9SApple OSS Distributions 				}
1095*bbb1b6f9SApple OSS Distributions 			} else {
1096*bbb1b6f9SApple OSS Distributions 				ubc_upl_abort_range(upl, ap->a_pl_offset, (upl_size_t)ap->a_size, UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
1097*bbb1b6f9SApple OSS Distributions 			}
1098*bbb1b6f9SApple OSS Distributions 		}
1099*bbb1b6f9SApple OSS Distributions 		vnode_put(lvp);
1100*bbb1b6f9SApple OSS Distributions 	} else if ((ap->a_flags & UPL_NOCOMMIT) == 0) {
1101*bbb1b6f9SApple OSS Distributions 		ubc_upl_abort_range(ap->a_pl, ap->a_pl_offset, (upl_size_t)ap->a_size, UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
1102*bbb1b6f9SApple OSS Distributions 	}
1103*bbb1b6f9SApple OSS Distributions 
1104*bbb1b6f9SApple OSS Distributions 	nullfs_cleanup_patched_context(null_mp, ectx);
1105*bbb1b6f9SApple OSS Distributions 	return error;
1106*bbb1b6f9SApple OSS Distributions }
1107*bbb1b6f9SApple OSS Distributions 
1108*bbb1b6f9SApple OSS Distributions static int
nullfs_read(struct vnop_read_args * ap)1109*bbb1b6f9SApple OSS Distributions nullfs_read(struct vnop_read_args * ap)
1110*bbb1b6f9SApple OSS Distributions {
1111*bbb1b6f9SApple OSS Distributions 	int error = EIO;
1112*bbb1b6f9SApple OSS Distributions 
1113*bbb1b6f9SApple OSS Distributions 	struct vnode *vp, *lvp;
1114*bbb1b6f9SApple OSS Distributions 	struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(ap->a_vp));
1115*bbb1b6f9SApple OSS Distributions 	NULLFSDEBUG("%s %p\n", __FUNCTION__, ap->a_vp);
1116*bbb1b6f9SApple OSS Distributions 
1117*bbb1b6f9SApple OSS Distributions 	if (nullfs_checkspecialvp(ap->a_vp)) {
1118*bbb1b6f9SApple OSS Distributions 		return ENOTSUP; /* the special vnodes can't be read */
1119*bbb1b6f9SApple OSS Distributions 	}
1120*bbb1b6f9SApple OSS Distributions 
1121*bbb1b6f9SApple OSS Distributions 	vfs_context_t ectx = nullfs_get_patched_context(null_mp, ap->a_context);
1122*bbb1b6f9SApple OSS Distributions 	vp  = ap->a_vp;
1123*bbb1b6f9SApple OSS Distributions 	lvp = NULLVPTOLOWERVP(vp);
1124*bbb1b6f9SApple OSS Distributions 
1125*bbb1b6f9SApple OSS Distributions 	/*
1126*bbb1b6f9SApple OSS Distributions 	 * First some house keeping
1127*bbb1b6f9SApple OSS Distributions 	 */
1128*bbb1b6f9SApple OSS Distributions 	if (vnode_getwithvid(lvp, NULLVPTOLOWERVID(vp)) == 0) {
1129*bbb1b6f9SApple OSS Distributions 		if (!vnode_isreg(lvp) && !vnode_islnk(lvp)) {
1130*bbb1b6f9SApple OSS Distributions 			error = EPERM;
1131*bbb1b6f9SApple OSS Distributions 			goto end;
1132*bbb1b6f9SApple OSS Distributions 		}
1133*bbb1b6f9SApple OSS Distributions 
1134*bbb1b6f9SApple OSS Distributions 		if (uio_resid(ap->a_uio) == 0) {
1135*bbb1b6f9SApple OSS Distributions 			error = 0;
1136*bbb1b6f9SApple OSS Distributions 			goto end;
1137*bbb1b6f9SApple OSS Distributions 		}
1138*bbb1b6f9SApple OSS Distributions 
1139*bbb1b6f9SApple OSS Distributions 		/*
1140*bbb1b6f9SApple OSS Distributions 		 * Now ask VM/UBC/VFS to do our bidding
1141*bbb1b6f9SApple OSS Distributions 		 */
1142*bbb1b6f9SApple OSS Distributions 
1143*bbb1b6f9SApple OSS Distributions 		error = VNOP_READ(lvp, ap->a_uio, ap->a_ioflag, ectx);
1144*bbb1b6f9SApple OSS Distributions 		if (error) {
1145*bbb1b6f9SApple OSS Distributions 			NULLFSDEBUG("VNOP_READ failed: %d\n", error);
1146*bbb1b6f9SApple OSS Distributions 		}
1147*bbb1b6f9SApple OSS Distributions end:
1148*bbb1b6f9SApple OSS Distributions 		vnode_put(lvp);
1149*bbb1b6f9SApple OSS Distributions 	}
1150*bbb1b6f9SApple OSS Distributions 
1151*bbb1b6f9SApple OSS Distributions 	nullfs_cleanup_patched_context(null_mp, ectx);
1152*bbb1b6f9SApple OSS Distributions 	return error;
1153*bbb1b6f9SApple OSS Distributions }
1154*bbb1b6f9SApple OSS Distributions 
1155*bbb1b6f9SApple OSS Distributions /*
1156*bbb1b6f9SApple OSS Distributions  * Global vfs data structures
1157*bbb1b6f9SApple OSS Distributions  */
1158*bbb1b6f9SApple OSS Distributions 
1159*bbb1b6f9SApple OSS Distributions static const struct vnodeopv_entry_desc nullfs_vnodeop_entries[] = {
1160*bbb1b6f9SApple OSS Distributions 	{.opve_op = &vnop_default_desc, .opve_impl = (vop_t)nullfs_default}, {.opve_op = &vnop_getattr_desc, .opve_impl = (vop_t)nullfs_getattr},
1161*bbb1b6f9SApple OSS Distributions 	{.opve_op = &vnop_open_desc, .opve_impl = (vop_t)nullfs_open}, {.opve_op = &vnop_close_desc, .opve_impl = (vop_t)nullfs_close},
1162*bbb1b6f9SApple OSS Distributions 	{.opve_op = &vnop_inactive_desc, .opve_impl = (vop_t)null_inactive}, {.opve_op = &vnop_reclaim_desc, .opve_impl = (vop_t)null_reclaim},
1163*bbb1b6f9SApple OSS Distributions 	{.opve_op = &vnop_lookup_desc, .opve_impl = (vop_t)null_lookup}, {.opve_op = &vnop_readdir_desc, .opve_impl = (vop_t)nullfs_readdir},
1164*bbb1b6f9SApple OSS Distributions 	{.opve_op = &vnop_readlink_desc, .opve_impl = (vop_t)nullfs_readlink}, {.opve_op = &vnop_pathconf_desc, .opve_impl = (vop_t)nullfs_pathconf},
1165*bbb1b6f9SApple OSS Distributions 	{.opve_op = &vnop_fsync_desc, .opve_impl = (vop_t)nullfs_fsync}, {.opve_op = &vnop_mmap_desc, .opve_impl = (vop_t)nullfs_mmap},
1166*bbb1b6f9SApple OSS Distributions 	{.opve_op = &vnop_mnomap_desc, .opve_impl = (vop_t)nullfs_mnomap}, {.opve_op = &vnop_getxattr_desc, .opve_impl = (vop_t)nullfs_getxattr},
1167*bbb1b6f9SApple OSS Distributions 	{.opve_op = &vnop_pagein_desc, .opve_impl = (vop_t)nullfs_pagein}, {.opve_op = &vnop_read_desc, .opve_impl = (vop_t)nullfs_read},
1168*bbb1b6f9SApple OSS Distributions 	{.opve_op = &vnop_listxattr_desc, .opve_impl = (vop_t)nullfs_listxattr}, {.opve_op = NULL, .opve_impl = NULL},
1169*bbb1b6f9SApple OSS Distributions };
1170*bbb1b6f9SApple OSS Distributions 
1171*bbb1b6f9SApple OSS Distributions const struct vnodeopv_desc nullfs_vnodeop_opv_desc = {.opv_desc_vector_p = &nullfs_vnodeop_p, .opv_desc_ops = nullfs_vnodeop_entries};
1172*bbb1b6f9SApple OSS Distributions 
1173*bbb1b6f9SApple OSS Distributions //NULLFS Specific helper function
1174*bbb1b6f9SApple OSS Distributions 
1175*bbb1b6f9SApple OSS Distributions int
nullfs_getbackingvnode(vnode_t in_vp,vnode_t * out_vpp)1176*bbb1b6f9SApple OSS Distributions nullfs_getbackingvnode(vnode_t in_vp, vnode_t* out_vpp)
1177*bbb1b6f9SApple OSS Distributions {
1178*bbb1b6f9SApple OSS Distributions 	int result = EINVAL;
1179*bbb1b6f9SApple OSS Distributions 
1180*bbb1b6f9SApple OSS Distributions 	if (out_vpp == NULL || in_vp == NULL) {
1181*bbb1b6f9SApple OSS Distributions 		goto end;
1182*bbb1b6f9SApple OSS Distributions 	}
1183*bbb1b6f9SApple OSS Distributions 
1184*bbb1b6f9SApple OSS Distributions 	struct vfsstatfs * sp   = NULL;
1185*bbb1b6f9SApple OSS Distributions 	mount_t mp = vnode_mount(in_vp);
1186*bbb1b6f9SApple OSS Distributions 
1187*bbb1b6f9SApple OSS Distributions 	sp = vfs_statfs(mp);
1188*bbb1b6f9SApple OSS Distributions 	//If this isn't a nullfs vnode or it is but it's a special vnode
1189*bbb1b6f9SApple OSS Distributions 	if (strcmp(sp->f_fstypename, "nullfs") != 0 || nullfs_checkspecialvp(in_vp)) {
1190*bbb1b6f9SApple OSS Distributions 		*out_vpp = NULLVP;
1191*bbb1b6f9SApple OSS Distributions 		result = ENOENT;
1192*bbb1b6f9SApple OSS Distributions 		goto end;
1193*bbb1b6f9SApple OSS Distributions 	}
1194*bbb1b6f9SApple OSS Distributions 
1195*bbb1b6f9SApple OSS Distributions 	vnode_t lvp = NULLVPTOLOWERVP(in_vp);
1196*bbb1b6f9SApple OSS Distributions 	if ((result = vnode_getwithvid(lvp, NULLVPTOLOWERVID(in_vp)))) {
1197*bbb1b6f9SApple OSS Distributions 		goto end;
1198*bbb1b6f9SApple OSS Distributions 	}
1199*bbb1b6f9SApple OSS Distributions 
1200*bbb1b6f9SApple OSS Distributions 	*out_vpp = lvp;
1201*bbb1b6f9SApple OSS Distributions 
1202*bbb1b6f9SApple OSS Distributions end:
1203*bbb1b6f9SApple OSS Distributions 	return result;
1204*bbb1b6f9SApple OSS Distributions }
1205