xref: /freebsd-13-stable/sys/fs/unionfs/union_subr.c (revision f872814e2d7a8841411569fc707b028463c7656b)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1994 Jan-Simon Pendry
5  * Copyright (c) 1994
6  *	The Regents of the University of California.  All rights reserved.
7  * Copyright (c) 2005, 2006, 2012 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc.
8  * Copyright (c) 2006, 2012 Daichi Goto <daichi@freebsd.org>
9  *
10  * This code is derived from software contributed to Berkeley by
11  * Jan-Simon Pendry.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *	@(#)union_subr.c	8.20 (Berkeley) 5/20/95
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/ktr.h>
44 #include <sys/lock.h>
45 #include <sys/mutex.h>
46 #include <sys/malloc.h>
47 #include <sys/mount.h>
48 #include <sys/namei.h>
49 #include <sys/proc.h>
50 #include <sys/vnode.h>
51 #include <sys/dirent.h>
52 #include <sys/fcntl.h>
53 #include <sys/filedesc.h>
54 #include <sys/stat.h>
55 #include <sys/resourcevar.h>
56 
57 #include <security/mac/mac_framework.h>
58 
59 #include <vm/uma.h>
60 
61 #include <fs/unionfs/union.h>
62 
63 #define NUNIONFSNODECACHE 16
64 
65 static MALLOC_DEFINE(M_UNIONFSHASH, "UNIONFS hash", "UNIONFS hash table");
66 MALLOC_DEFINE(M_UNIONFSNODE, "UNIONFS node", "UNIONFS vnode private part");
67 MALLOC_DEFINE(M_UNIONFSPATH, "UNIONFS path", "UNIONFS path private part");
68 
69 /*
70  * Initialize
71  */
72 int
unionfs_init(struct vfsconf * vfsp)73 unionfs_init(struct vfsconf *vfsp)
74 {
75 	UNIONFSDEBUG("unionfs_init\n");	/* printed during system boot */
76 	return (0);
77 }
78 
79 /*
80  * Uninitialize
81  */
82 int
unionfs_uninit(struct vfsconf * vfsp)83 unionfs_uninit(struct vfsconf *vfsp)
84 {
85 	return (0);
86 }
87 
88 static struct unionfs_node_hashhead *
unionfs_get_hashhead(struct vnode * dvp,char * path)89 unionfs_get_hashhead(struct vnode *dvp, char *path)
90 {
91 	int		count;
92 	char		hash;
93 	struct unionfs_node *unp;
94 
95 	hash = 0;
96 	unp = VTOUNIONFS(dvp);
97 	if (path != NULL) {
98 		for (count = 0; path[count]; count++)
99 			hash += path[count];
100 	}
101 
102 	return (&(unp->un_hashtbl[hash & (unp->un_hashmask)]));
103 }
104 
105 /*
106  * Get the cached vnode.
107  */
108 static struct vnode *
unionfs_get_cached_vnode(struct vnode * uvp,struct vnode * lvp,struct vnode * dvp,char * path)109 unionfs_get_cached_vnode(struct vnode *uvp, struct vnode *lvp,
110 			struct vnode *dvp, char *path)
111 {
112 	struct unionfs_node_hashhead *hd;
113 	struct unionfs_node *unp;
114 	struct vnode   *vp;
115 
116 	KASSERT((uvp == NULLVP || uvp->v_type == VDIR),
117 	    ("unionfs_get_cached_vnode: v_type != VDIR"));
118 	KASSERT((lvp == NULLVP || lvp->v_type == VDIR),
119 	    ("unionfs_get_cached_vnode: v_type != VDIR"));
120 
121 	VI_LOCK(dvp);
122 	hd = unionfs_get_hashhead(dvp, path);
123 	LIST_FOREACH(unp, hd, un_hash) {
124 		if (!strcmp(unp->un_path, path)) {
125 			vp = UNIONFSTOV(unp);
126 			VI_LOCK_FLAGS(vp, MTX_DUPOK);
127 			VI_UNLOCK(dvp);
128 			vp->v_iflag &= ~VI_OWEINACT;
129 			if (VN_IS_DOOMED(vp) ||
130 			    ((vp->v_iflag & VI_DOINGINACT) != 0)) {
131 				VI_UNLOCK(vp);
132 				vp = NULLVP;
133 			} else
134 				VI_UNLOCK(vp);
135 			return (vp);
136 		}
137 	}
138 	VI_UNLOCK(dvp);
139 
140 	return (NULLVP);
141 }
142 
143 /*
144  * Add the new vnode into cache.
145  */
146 static struct vnode *
unionfs_ins_cached_vnode(struct unionfs_node * uncp,struct vnode * dvp,char * path)147 unionfs_ins_cached_vnode(struct unionfs_node *uncp,
148 			struct vnode *dvp, char *path)
149 {
150 	struct unionfs_node_hashhead *hd;
151 	struct unionfs_node *unp;
152 	struct vnode   *vp;
153 
154 	KASSERT((uncp->un_uppervp==NULLVP || uncp->un_uppervp->v_type==VDIR),
155 	    ("unionfs_ins_cached_vnode: v_type != VDIR"));
156 	KASSERT((uncp->un_lowervp==NULLVP || uncp->un_lowervp->v_type==VDIR),
157 	    ("unionfs_ins_cached_vnode: v_type != VDIR"));
158 
159 	VI_LOCK(dvp);
160 	hd = unionfs_get_hashhead(dvp, path);
161 	LIST_FOREACH(unp, hd, un_hash) {
162 		if (!strcmp(unp->un_path, path)) {
163 			vp = UNIONFSTOV(unp);
164 			VI_LOCK_FLAGS(vp, MTX_DUPOK);
165 			vp->v_iflag &= ~VI_OWEINACT;
166 			if (VN_IS_DOOMED(vp) ||
167 			    ((vp->v_iflag & VI_DOINGINACT) != 0)) {
168 				LIST_INSERT_HEAD(hd, uncp, un_hash);
169 				VI_UNLOCK(vp);
170 				vp = NULLVP;
171 			} else
172 				VI_UNLOCK(vp);
173 			VI_UNLOCK(dvp);
174 			return (vp);
175 		}
176 	}
177 
178 	LIST_INSERT_HEAD(hd, uncp, un_hash);
179 	VI_UNLOCK(dvp);
180 
181 	return (NULLVP);
182 }
183 
184 /*
185  * Remove the vnode.
186  */
187 static void
unionfs_rem_cached_vnode(struct unionfs_node * unp,struct vnode * dvp)188 unionfs_rem_cached_vnode(struct unionfs_node *unp, struct vnode *dvp)
189 {
190 	KASSERT((unp != NULL), ("unionfs_rem_cached_vnode: null node"));
191 	KASSERT((dvp != NULLVP),
192 	    ("unionfs_rem_cached_vnode: null parent vnode"));
193 	KASSERT((unp->un_hash.le_prev != NULL),
194 	    ("unionfs_rem_cached_vnode: null hash"));
195 
196 	VI_LOCK(dvp);
197 	LIST_REMOVE(unp, un_hash);
198 	unp->un_hash.le_next = NULL;
199 	unp->un_hash.le_prev = NULL;
200 	VI_UNLOCK(dvp);
201 }
202 
203 /*
204  * Make a new or get existing unionfs node.
205  *
206  * uppervp and lowervp should be unlocked. Because if new unionfs vnode is
207  * locked, uppervp or lowervp is locked too. In order to prevent dead lock,
208  * you should not lock plurality simultaneously.
209  */
210 int
unionfs_nodeget(struct mount * mp,struct vnode * uppervp,struct vnode * lowervp,struct vnode * dvp,struct vnode ** vpp,struct componentname * cnp,struct thread * td)211 unionfs_nodeget(struct mount *mp, struct vnode *uppervp,
212 		struct vnode *lowervp, struct vnode *dvp,
213 		struct vnode **vpp, struct componentname *cnp,
214 		struct thread *td)
215 {
216 	struct unionfs_mount *ump;
217 	struct unionfs_node *unp;
218 	struct vnode   *vp;
219 	int		error;
220 	int		lkflags;
221 	enum vtype	vt;
222 	char	       *path;
223 
224 	ump = MOUNTTOUNIONFSMOUNT(mp);
225 	lkflags = (cnp ? cnp->cn_lkflags : 0);
226 	path = (cnp ? cnp->cn_nameptr : NULL);
227 	*vpp = NULLVP;
228 
229 	if (uppervp == NULLVP && lowervp == NULLVP)
230 		panic("unionfs_nodeget: upper and lower is null");
231 
232 	vt = (uppervp != NULLVP ? uppervp->v_type : lowervp->v_type);
233 
234 	/* If it has no ISLASTCN flag, path check is skipped. */
235 	if (cnp && !(cnp->cn_flags & ISLASTCN))
236 		path = NULL;
237 
238 	/* check the cache */
239 	if (path != NULL && dvp != NULLVP && vt == VDIR) {
240 		vp = unionfs_get_cached_vnode(uppervp, lowervp, dvp, path);
241 		if (vp != NULLVP) {
242 			vref(vp);
243 			*vpp = vp;
244 			goto unionfs_nodeget_out;
245 		}
246 	}
247 
248 	if ((uppervp == NULLVP || ump->um_uppervp != uppervp) ||
249 	    (lowervp == NULLVP || ump->um_lowervp != lowervp)) {
250 		/* dvp will be NULLVP only in case of root vnode. */
251 		if (dvp == NULLVP)
252 			return (EINVAL);
253 	}
254 	unp = malloc(sizeof(struct unionfs_node),
255 	    M_UNIONFSNODE, M_WAITOK | M_ZERO);
256 
257 	error = getnewvnode("unionfs", mp, &unionfs_vnodeops, &vp);
258 	if (error != 0) {
259 		free(unp, M_UNIONFSNODE);
260 		return (error);
261 	}
262 	error = insmntque(vp, mp);	/* XXX: Too early for mpsafe fs */
263 	if (error != 0) {
264 		free(unp, M_UNIONFSNODE);
265 		return (error);
266 	}
267 	if (dvp != NULLVP)
268 		vref(dvp);
269 	if (uppervp != NULLVP)
270 		vref(uppervp);
271 	if (lowervp != NULLVP)
272 		vref(lowervp);
273 
274 	if (vt == VDIR)
275 		unp->un_hashtbl = hashinit(NUNIONFSNODECACHE, M_UNIONFSHASH,
276 		    &(unp->un_hashmask));
277 
278 	unp->un_vnode = vp;
279 	unp->un_uppervp = uppervp;
280 	unp->un_lowervp = lowervp;
281 	unp->un_dvp = dvp;
282 	if (uppervp != NULLVP)
283 		vp->v_vnlock = uppervp->v_vnlock;
284 	else
285 		vp->v_vnlock = lowervp->v_vnlock;
286 
287 	if (path != NULL) {
288 		unp->un_path = (char *)
289 		    malloc(cnp->cn_namelen +1, M_UNIONFSPATH, M_WAITOK|M_ZERO);
290 		bcopy(cnp->cn_nameptr, unp->un_path, cnp->cn_namelen);
291 		unp->un_path[cnp->cn_namelen] = '\0';
292 	}
293 	vp->v_type = vt;
294 	vp->v_data = unp;
295 
296 	if ((uppervp != NULLVP && ump->um_uppervp == uppervp) &&
297 	    (lowervp != NULLVP && ump->um_lowervp == lowervp))
298 		vp->v_vflag |= VV_ROOT;
299 
300 	if (path != NULL && dvp != NULLVP && vt == VDIR)
301 		*vpp = unionfs_ins_cached_vnode(unp, dvp, path);
302 	if ((*vpp) != NULLVP) {
303 		if (dvp != NULLVP)
304 			vrele(dvp);
305 		if (uppervp != NULLVP)
306 			vrele(uppervp);
307 		if (lowervp != NULLVP)
308 			vrele(lowervp);
309 
310 		unp->un_uppervp = NULLVP;
311 		unp->un_lowervp = NULLVP;
312 		unp->un_dvp = NULLVP;
313 		vrele(vp);
314 		vp = *vpp;
315 		vref(vp);
316 	} else
317 		*vpp = vp;
318 
319 unionfs_nodeget_out:
320 	if (lkflags & LK_TYPE_MASK)
321 		vn_lock(vp, lkflags | LK_RETRY);
322 
323 	return (0);
324 }
325 
326 /*
327  * Clean up the unionfs node.
328  */
329 void
unionfs_noderem(struct vnode * vp,struct thread * td)330 unionfs_noderem(struct vnode *vp, struct thread *td)
331 {
332 	int		count;
333 	struct unionfs_node *unp, *unp_t1, *unp_t2;
334 	struct unionfs_node_hashhead *hd;
335 	struct unionfs_node_status *unsp, *unsp_tmp;
336 	struct vnode   *lvp;
337 	struct vnode   *uvp;
338 	struct vnode   *dvp;
339 
340 	/*
341 	 * Use the interlock to protect the clearing of v_data to
342 	 * prevent faults in unionfs_lock().
343 	 */
344 	VI_LOCK(vp);
345 	unp = VTOUNIONFS(vp);
346 	lvp = unp->un_lowervp;
347 	uvp = unp->un_uppervp;
348 	dvp = unp->un_dvp;
349 	unp->un_lowervp = unp->un_uppervp = NULLVP;
350 	vp->v_vnlock = &(vp->v_lock);
351 	vp->v_data = NULL;
352 	vp->v_object = NULL;
353 	if (vp->v_writecount > 0) {
354 		if (uvp != NULL)
355 			VOP_ADD_WRITECOUNT(uvp, -vp->v_writecount);
356 		else if (lvp != NULL)
357 			VOP_ADD_WRITECOUNT(lvp, -vp->v_writecount);
358 	} else if (vp->v_writecount < 0)
359 		vp->v_writecount = 0;
360 	VI_UNLOCK(vp);
361 
362 	if (lvp != NULLVP)
363 		VOP_UNLOCK(lvp);
364 	if (uvp != NULLVP)
365 		VOP_UNLOCK(uvp);
366 
367 	if (dvp != NULLVP && unp->un_hash.le_prev != NULL)
368 		unionfs_rem_cached_vnode(unp, dvp);
369 
370 	if (lockmgr(vp->v_vnlock, LK_EXCLUSIVE, VI_MTX(vp)) != 0)
371 		panic("the lock for deletion is unacquirable.");
372 
373 	if (lvp != NULLVP)
374 		vrele(lvp);
375 	if (uvp != NULLVP)
376 		vrele(uvp);
377 	if (dvp != NULLVP) {
378 		vrele(dvp);
379 		unp->un_dvp = NULLVP;
380 	}
381 	if (unp->un_path != NULL) {
382 		free(unp->un_path, M_UNIONFSPATH);
383 		unp->un_path = NULL;
384 	}
385 
386 	if (unp->un_hashtbl != NULL) {
387 		for (count = 0; count <= unp->un_hashmask; count++) {
388 			hd = unp->un_hashtbl + count;
389 			LIST_FOREACH_SAFE(unp_t1, hd, un_hash, unp_t2) {
390 				LIST_REMOVE(unp_t1, un_hash);
391 				unp_t1->un_hash.le_next = NULL;
392 				unp_t1->un_hash.le_prev = NULL;
393 			}
394 		}
395 		hashdestroy(unp->un_hashtbl, M_UNIONFSHASH, unp->un_hashmask);
396 	}
397 
398 	LIST_FOREACH_SAFE(unsp, &(unp->un_unshead), uns_list, unsp_tmp) {
399 		LIST_REMOVE(unsp, uns_list);
400 		free(unsp, M_TEMP);
401 	}
402 	free(unp, M_UNIONFSNODE);
403 }
404 
405 /*
406  * Get the unionfs node status.
407  * You need exclusive lock this vnode.
408  */
409 void
unionfs_get_node_status(struct unionfs_node * unp,struct thread * td,struct unionfs_node_status ** unspp)410 unionfs_get_node_status(struct unionfs_node *unp, struct thread *td,
411 			struct unionfs_node_status **unspp)
412 {
413 	struct unionfs_node_status *unsp;
414 	pid_t pid = td->td_proc->p_pid;
415 
416 	KASSERT(NULL != unspp, ("null pointer"));
417 	ASSERT_VOP_ELOCKED(UNIONFSTOV(unp), "unionfs_get_node_status");
418 
419 	LIST_FOREACH(unsp, &(unp->un_unshead), uns_list) {
420 		if (unsp->uns_pid == pid) {
421 			*unspp = unsp;
422 			return;
423 		}
424 	}
425 
426 	/* create a new unionfs node status */
427 	unsp = malloc(sizeof(struct unionfs_node_status),
428 	    M_TEMP, M_WAITOK | M_ZERO);
429 
430 	unsp->uns_pid = pid;
431 	LIST_INSERT_HEAD(&(unp->un_unshead), unsp, uns_list);
432 
433 	*unspp = unsp;
434 }
435 
436 /*
437  * Remove the unionfs node status, if you can.
438  * You need exclusive lock this vnode.
439  */
440 void
unionfs_tryrem_node_status(struct unionfs_node * unp,struct unionfs_node_status * unsp)441 unionfs_tryrem_node_status(struct unionfs_node *unp,
442 			   struct unionfs_node_status *unsp)
443 {
444 	KASSERT(NULL != unsp, ("null pointer"));
445 	ASSERT_VOP_ELOCKED(UNIONFSTOV(unp), "unionfs_get_node_status");
446 
447 	if (0 < unsp->uns_lower_opencnt || 0 < unsp->uns_upper_opencnt)
448 		return;
449 
450 	LIST_REMOVE(unsp, uns_list);
451 	free(unsp, M_TEMP);
452 }
453 
454 /*
455  * Create upper node attr.
456  */
457 void
unionfs_create_uppervattr_core(struct unionfs_mount * ump,struct vattr * lva,struct vattr * uva,struct thread * td)458 unionfs_create_uppervattr_core(struct unionfs_mount *ump,
459 			       struct vattr *lva,
460 			       struct vattr *uva,
461 			       struct thread *td)
462 {
463 	VATTR_NULL(uva);
464 	uva->va_type = lva->va_type;
465 	uva->va_atime = lva->va_atime;
466 	uva->va_mtime = lva->va_mtime;
467 	uva->va_ctime = lva->va_ctime;
468 
469 	switch (ump->um_copymode) {
470 	case UNIONFS_TRANSPARENT:
471 		uva->va_mode = lva->va_mode;
472 		uva->va_uid = lva->va_uid;
473 		uva->va_gid = lva->va_gid;
474 		break;
475 	case UNIONFS_MASQUERADE:
476 		if (ump->um_uid == lva->va_uid) {
477 			uva->va_mode = lva->va_mode & 077077;
478 			uva->va_mode |= (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile) & 0700;
479 			uva->va_uid = lva->va_uid;
480 			uva->va_gid = lva->va_gid;
481 		} else {
482 			uva->va_mode = (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile);
483 			uva->va_uid = ump->um_uid;
484 			uva->va_gid = ump->um_gid;
485 		}
486 		break;
487 	default:		/* UNIONFS_TRADITIONAL */
488 		uva->va_mode = 0777 & ~td->td_proc->p_pd->pd_cmask;
489 		uva->va_uid = ump->um_uid;
490 		uva->va_gid = ump->um_gid;
491 		break;
492 	}
493 }
494 
495 /*
496  * Create upper node attr.
497  */
498 int
unionfs_create_uppervattr(struct unionfs_mount * ump,struct vnode * lvp,struct vattr * uva,struct ucred * cred,struct thread * td)499 unionfs_create_uppervattr(struct unionfs_mount *ump,
500 			  struct vnode *lvp,
501 			  struct vattr *uva,
502 			  struct ucred *cred,
503 			  struct thread *td)
504 {
505 	int		error;
506 	struct vattr	lva;
507 
508 	if ((error = VOP_GETATTR(lvp, &lva, cred)))
509 		return (error);
510 
511 	unionfs_create_uppervattr_core(ump, &lva, uva, td);
512 
513 	return (error);
514 }
515 
516 /*
517  * relookup
518  *
519  * dvp should be locked on entry and will be locked on return.
520  *
521  * If an error is returned, *vpp will be invalid, otherwise it will hold a
522  * locked, referenced vnode. If *vpp == dvp then remember that only one
523  * LK_EXCLUSIVE lock is held.
524  */
525 int
unionfs_relookup(struct vnode * dvp,struct vnode ** vpp,struct componentname * cnp,struct componentname * cn,struct thread * td,char * path,int pathlen,u_long nameiop)526 unionfs_relookup(struct vnode *dvp, struct vnode **vpp,
527 		 struct componentname *cnp, struct componentname *cn,
528 		 struct thread *td, char *path, int pathlen, u_long nameiop)
529 {
530 	int	error;
531 
532 	cn->cn_namelen = pathlen;
533 	cn->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
534 	bcopy(path, cn->cn_pnbuf, pathlen);
535 	cn->cn_pnbuf[pathlen] = '\0';
536 
537 	cn->cn_nameiop = nameiop;
538 	cn->cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN);
539 	cn->cn_lkflags = LK_EXCLUSIVE;
540 	cn->cn_thread = td;
541 	cn->cn_cred = cnp->cn_cred;
542 
543 	cn->cn_nameptr = cn->cn_pnbuf;
544 
545 	if (nameiop == DELETE)
546 		cn->cn_flags |= (cnp->cn_flags & (DOWHITEOUT | SAVESTART));
547 	else if (RENAME == nameiop)
548 		cn->cn_flags |= (cnp->cn_flags & SAVESTART);
549 	else if (nameiop == CREATE)
550 		cn->cn_flags |= NOCACHE;
551 
552 	vref(dvp);
553 	VOP_UNLOCK(dvp);
554 
555 	if ((error = relookup(dvp, vpp, cn))) {
556 		uma_zfree(namei_zone, cn->cn_pnbuf);
557 		cn->cn_flags &= ~HASBUF;
558 		vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
559 	} else
560 		vrele(dvp);
561 
562 	return (error);
563 }
564 
565 /*
566  * relookup for CREATE namei operation.
567  *
568  * dvp is unionfs vnode. dvp should be locked.
569  *
570  * If it called 'unionfs_copyfile' function by unionfs_link etc,
571  * VOP_LOOKUP information is broken.
572  * So it need relookup in order to create link etc.
573  */
574 int
unionfs_relookup_for_create(struct vnode * dvp,struct componentname * cnp,struct thread * td)575 unionfs_relookup_for_create(struct vnode *dvp, struct componentname *cnp,
576 			    struct thread *td)
577 {
578 	int	error;
579 	struct vnode *udvp;
580 	struct vnode *vp;
581 	struct componentname cn;
582 
583 	udvp = UNIONFSVPTOUPPERVP(dvp);
584 	vp = NULLVP;
585 
586 	error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr,
587 	    strlen(cnp->cn_nameptr), CREATE);
588 	if (error)
589 		return (error);
590 
591 	if (vp != NULLVP) {
592 		if (udvp == vp)
593 			vrele(vp);
594 		else
595 			vput(vp);
596 
597 		error = EEXIST;
598 	}
599 
600 	if (cn.cn_flags & HASBUF) {
601 		uma_zfree(namei_zone, cn.cn_pnbuf);
602 		cn.cn_flags &= ~HASBUF;
603 	}
604 
605 	if (!error) {
606 		cn.cn_flags |= (cnp->cn_flags & HASBUF);
607 		cnp->cn_flags = cn.cn_flags;
608 	}
609 
610 	return (error);
611 }
612 
613 /*
614  * relookup for DELETE namei operation.
615  *
616  * dvp is unionfs vnode. dvp should be locked.
617  */
618 int
unionfs_relookup_for_delete(struct vnode * dvp,struct componentname * cnp,struct thread * td)619 unionfs_relookup_for_delete(struct vnode *dvp, struct componentname *cnp,
620 			    struct thread *td)
621 {
622 	int	error;
623 	struct vnode *udvp;
624 	struct vnode *vp;
625 	struct componentname cn;
626 
627 	udvp = UNIONFSVPTOUPPERVP(dvp);
628 	vp = NULLVP;
629 
630 	error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr,
631 	    strlen(cnp->cn_nameptr), DELETE);
632 	if (error)
633 		return (error);
634 
635 	if (vp == NULLVP)
636 		error = ENOENT;
637 	else {
638 		if (udvp == vp)
639 			vrele(vp);
640 		else
641 			vput(vp);
642 	}
643 
644 	if (cn.cn_flags & HASBUF) {
645 		uma_zfree(namei_zone, cn.cn_pnbuf);
646 		cn.cn_flags &= ~HASBUF;
647 	}
648 
649 	if (!error) {
650 		cn.cn_flags |= (cnp->cn_flags & HASBUF);
651 		cnp->cn_flags = cn.cn_flags;
652 	}
653 
654 	return (error);
655 }
656 
657 /*
658  * relookup for RENAME namei operation.
659  *
660  * dvp is unionfs vnode. dvp should be locked.
661  */
662 int
unionfs_relookup_for_rename(struct vnode * dvp,struct componentname * cnp,struct thread * td)663 unionfs_relookup_for_rename(struct vnode *dvp, struct componentname *cnp,
664 			    struct thread *td)
665 {
666 	int error;
667 	struct vnode *udvp;
668 	struct vnode *vp;
669 	struct componentname cn;
670 
671 	udvp = UNIONFSVPTOUPPERVP(dvp);
672 	vp = NULLVP;
673 
674 	error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr,
675 	    strlen(cnp->cn_nameptr), RENAME);
676 	if (error)
677 		return (error);
678 
679 	if (vp != NULLVP) {
680 		if (udvp == vp)
681 			vrele(vp);
682 		else
683 			vput(vp);
684 	}
685 
686 	if (cn.cn_flags & HASBUF) {
687 		uma_zfree(namei_zone, cn.cn_pnbuf);
688 		cn.cn_flags &= ~HASBUF;
689 	}
690 
691 	if (!error) {
692 		cn.cn_flags |= (cnp->cn_flags & HASBUF);
693 		cnp->cn_flags = cn.cn_flags;
694 	}
695 
696 	return (error);
697 
698 }
699 
700 /*
701  * Update the unionfs_node.
702  *
703  * uvp is new locked upper vnode. unionfs vnode's lock will be exchanged to the
704  * uvp's lock and lower's lock will be unlocked.
705  */
706 static void
unionfs_node_update(struct unionfs_node * unp,struct vnode * uvp,struct thread * td)707 unionfs_node_update(struct unionfs_node *unp, struct vnode *uvp,
708 		    struct thread *td)
709 {
710 	unsigned	count, lockrec;
711 	struct vnode   *vp;
712 	struct vnode   *lvp;
713 	struct vnode   *dvp;
714 
715 	vp = UNIONFSTOV(unp);
716 	lvp = unp->un_lowervp;
717 	ASSERT_VOP_ELOCKED(lvp, "unionfs_node_update");
718 	dvp = unp->un_dvp;
719 
720 	/*
721 	 * lock update
722 	 */
723 	VI_LOCK(vp);
724 	unp->un_uppervp = uvp;
725 	vp->v_vnlock = uvp->v_vnlock;
726 	VI_UNLOCK(vp);
727 	lockrec = lvp->v_vnlock->lk_recurse;
728 	for (count = 0; count < lockrec; count++)
729 		vn_lock(uvp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY);
730 
731 	/*
732 	 * cache update
733 	 */
734 	if (unp->un_path != NULL && dvp != NULLVP && vp->v_type == VDIR) {
735 		static struct unionfs_node_hashhead *hd;
736 
737 		VI_LOCK(dvp);
738 		hd = unionfs_get_hashhead(dvp, unp->un_path);
739 		LIST_REMOVE(unp, un_hash);
740 		LIST_INSERT_HEAD(hd, unp, un_hash);
741 		VI_UNLOCK(dvp);
742 	}
743 }
744 
745 /*
746  * Create a new shadow dir.
747  *
748  * udvp should be locked on entry and will be locked on return.
749  *
750  * If no error returned, unp will be updated.
751  */
752 int
unionfs_mkshadowdir(struct unionfs_mount * ump,struct vnode * udvp,struct unionfs_node * unp,struct componentname * cnp,struct thread * td)753 unionfs_mkshadowdir(struct unionfs_mount *ump, struct vnode *udvp,
754 		    struct unionfs_node *unp, struct componentname *cnp,
755 		    struct thread *td)
756 {
757 	int		error;
758 	struct vnode   *lvp;
759 	struct vnode   *uvp;
760 	struct vattr	va;
761 	struct vattr	lva;
762 	struct nameidata nd;
763 	struct mount   *mp;
764 	struct ucred   *cred;
765 	struct ucred   *credbk;
766 	struct uidinfo *rootinfo;
767 
768 	if (unp->un_uppervp != NULLVP)
769 		return (EEXIST);
770 
771 	lvp = unp->un_lowervp;
772 	uvp = NULLVP;
773 	credbk = cnp->cn_cred;
774 
775 	/* Authority change to root */
776 	rootinfo = uifind((uid_t)0);
777 	cred = crdup(cnp->cn_cred);
778 	change_euid(cred, rootinfo);
779 	change_ruid(cred, rootinfo);
780 	change_svuid(cred, (uid_t)0);
781 	uifree(rootinfo);
782 	cnp->cn_cred = cred;
783 
784 	memset(&nd.ni_cnd, 0, sizeof(struct componentname));
785 	NDPREINIT(&nd);
786 
787 	if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred)))
788 		goto unionfs_mkshadowdir_abort;
789 
790 	if ((error = unionfs_relookup(udvp, &uvp, cnp, &nd.ni_cnd, td,
791 	    cnp->cn_nameptr, cnp->cn_namelen, CREATE)))
792 		goto unionfs_mkshadowdir_abort;
793 	if (uvp != NULLVP) {
794 		if (udvp == uvp)
795 			vrele(uvp);
796 		else
797 			vput(uvp);
798 
799 		error = EEXIST;
800 		goto unionfs_mkshadowdir_free_out;
801 	}
802 
803 	if ((error = vn_start_write(udvp, &mp, V_WAIT | PCATCH)))
804 		goto unionfs_mkshadowdir_free_out;
805 	unionfs_create_uppervattr_core(ump, &lva, &va, td);
806 
807 	error = VOP_MKDIR(udvp, &uvp, &nd.ni_cnd, &va);
808 
809 	if (!error) {
810 		unionfs_node_update(unp, uvp, td);
811 
812 		/*
813 		 * XXX The bug which cannot set uid/gid was corrected.
814 		 * Ignore errors.
815 		 */
816 		va.va_type = VNON;
817 		VOP_SETATTR(uvp, &va, nd.ni_cnd.cn_cred);
818 	}
819 	vn_finished_write(mp);
820 
821 unionfs_mkshadowdir_free_out:
822 	if (nd.ni_cnd.cn_flags & HASBUF) {
823 		uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf);
824 		nd.ni_cnd.cn_flags &= ~HASBUF;
825 	}
826 
827 unionfs_mkshadowdir_abort:
828 	cnp->cn_cred = credbk;
829 	crfree(cred);
830 
831 	return (error);
832 }
833 
834 /*
835  * Create a new whiteout.
836  *
837  * dvp should be locked on entry and will be locked on return.
838  */
839 int
unionfs_mkwhiteout(struct vnode * dvp,struct componentname * cnp,struct thread * td,char * path)840 unionfs_mkwhiteout(struct vnode *dvp, struct componentname *cnp,
841 		   struct thread *td, char *path)
842 {
843 	int		error;
844 	struct vnode   *wvp;
845 	struct nameidata nd;
846 	struct mount   *mp;
847 
848 	if (path == NULL)
849 		path = cnp->cn_nameptr;
850 
851 	wvp = NULLVP;
852 	NDPREINIT(&nd);
853 	if ((error = unionfs_relookup(dvp, &wvp, cnp, &nd.ni_cnd, td, path,
854 	    strlen(path), CREATE)))
855 		return (error);
856 	if (wvp != NULLVP) {
857 		if (nd.ni_cnd.cn_flags & HASBUF) {
858 			uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf);
859 			nd.ni_cnd.cn_flags &= ~HASBUF;
860 		}
861 		if (dvp == wvp)
862 			vrele(wvp);
863 		else
864 			vput(wvp);
865 
866 		return (EEXIST);
867 	}
868 
869 	if ((error = vn_start_write(dvp, &mp, V_WAIT | PCATCH)))
870 		goto unionfs_mkwhiteout_free_out;
871 	error = VOP_WHITEOUT(dvp, &nd.ni_cnd, CREATE);
872 
873 	vn_finished_write(mp);
874 
875 unionfs_mkwhiteout_free_out:
876 	if (nd.ni_cnd.cn_flags & HASBUF) {
877 		uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf);
878 		nd.ni_cnd.cn_flags &= ~HASBUF;
879 	}
880 
881 	return (error);
882 }
883 
884 /*
885  * Create a new vnode for create a new shadow file.
886  *
887  * If an error is returned, *vpp will be invalid, otherwise it will hold a
888  * locked, referenced and opened vnode.
889  *
890  * unp is never updated.
891  */
892 static int
unionfs_vn_create_on_upper(struct vnode ** vpp,struct vnode * udvp,struct unionfs_node * unp,struct vattr * uvap,struct thread * td)893 unionfs_vn_create_on_upper(struct vnode **vpp, struct vnode *udvp,
894 			   struct unionfs_node *unp, struct vattr *uvap,
895 			   struct thread *td)
896 {
897 	struct unionfs_mount *ump;
898 	struct vnode   *vp;
899 	struct vnode   *lvp;
900 	struct ucred   *cred;
901 	struct vattr	lva;
902 	int		fmode;
903 	int		error;
904 	struct nameidata nd;
905 
906 	ump = MOUNTTOUNIONFSMOUNT(UNIONFSTOV(unp)->v_mount);
907 	vp = NULLVP;
908 	lvp = unp->un_lowervp;
909 	cred = td->td_ucred;
910 	fmode = FFLAGS(O_WRONLY | O_CREAT | O_TRUNC | O_EXCL);
911 	error = 0;
912 
913 	if ((error = VOP_GETATTR(lvp, &lva, cred)) != 0)
914 		return (error);
915 	unionfs_create_uppervattr_core(ump, &lva, uvap, td);
916 
917 	if (unp->un_path == NULL)
918 		panic("unionfs: un_path is null");
919 
920 	nd.ni_cnd.cn_namelen = strlen(unp->un_path);
921 	nd.ni_cnd.cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
922 	bcopy(unp->un_path, nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_namelen + 1);
923 	nd.ni_cnd.cn_nameiop = CREATE;
924 	nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME |
925 	    ISLASTCN;
926 	nd.ni_cnd.cn_lkflags = LK_EXCLUSIVE;
927 	nd.ni_cnd.cn_thread = td;
928 	nd.ni_cnd.cn_cred = cred;
929 	nd.ni_cnd.cn_nameptr = nd.ni_cnd.cn_pnbuf;
930 	NDPREINIT(&nd);
931 
932 	vref(udvp);
933 	if ((error = relookup(udvp, &vp, &nd.ni_cnd)) != 0)
934 		goto unionfs_vn_create_on_upper_free_out2;
935 	vrele(udvp);
936 
937 	if (vp != NULLVP) {
938 		if (vp == udvp)
939 			vrele(vp);
940 		else
941 			vput(vp);
942 		error = EEXIST;
943 		goto unionfs_vn_create_on_upper_free_out1;
944 	}
945 
946 	if ((error = VOP_CREATE(udvp, &vp, &nd.ni_cnd, uvap)) != 0)
947 		goto unionfs_vn_create_on_upper_free_out1;
948 
949 	if ((error = VOP_OPEN(vp, fmode, cred, td, NULL)) != 0) {
950 		vput(vp);
951 		goto unionfs_vn_create_on_upper_free_out1;
952 	}
953 	error = VOP_ADD_WRITECOUNT(vp, 1);
954 	CTR3(KTR_VFS, "%s: vp %p v_writecount increased to %d",  __func__, vp,
955 	    vp->v_writecount);
956 	if (error == 0) {
957 		*vpp = vp;
958 	} else {
959 		VOP_CLOSE(vp, fmode, cred, td);
960 	}
961 
962 unionfs_vn_create_on_upper_free_out1:
963 	VOP_UNLOCK(udvp);
964 
965 unionfs_vn_create_on_upper_free_out2:
966 	if (nd.ni_cnd.cn_flags & HASBUF) {
967 		uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf);
968 		nd.ni_cnd.cn_flags &= ~HASBUF;
969 	}
970 
971 	return (error);
972 }
973 
974 /*
975  * Copy from lvp to uvp.
976  *
977  * lvp and uvp should be locked and opened on entry and will be locked and
978  * opened on return.
979  */
980 static int
unionfs_copyfile_core(struct vnode * lvp,struct vnode * uvp,struct ucred * cred,struct thread * td)981 unionfs_copyfile_core(struct vnode *lvp, struct vnode *uvp,
982 		      struct ucred *cred, struct thread *td)
983 {
984 	int		error;
985 	off_t		offset;
986 	int		count;
987 	int		bufoffset;
988 	char           *buf;
989 	struct uio	uio;
990 	struct iovec	iov;
991 
992 	error = 0;
993 	memset(&uio, 0, sizeof(uio));
994 
995 	uio.uio_td = td;
996 	uio.uio_segflg = UIO_SYSSPACE;
997 	uio.uio_offset = 0;
998 
999 	buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK);
1000 
1001 	while (error == 0) {
1002 		offset = uio.uio_offset;
1003 
1004 		uio.uio_iov = &iov;
1005 		uio.uio_iovcnt = 1;
1006 		iov.iov_base = buf;
1007 		iov.iov_len = MAXBSIZE;
1008 		uio.uio_resid = iov.iov_len;
1009 		uio.uio_rw = UIO_READ;
1010 
1011 		if ((error = VOP_READ(lvp, &uio, 0, cred)) != 0)
1012 			break;
1013 		if ((count = MAXBSIZE - uio.uio_resid) == 0)
1014 			break;
1015 
1016 		bufoffset = 0;
1017 		while (bufoffset < count) {
1018 			uio.uio_iov = &iov;
1019 			uio.uio_iovcnt = 1;
1020 			iov.iov_base = buf + bufoffset;
1021 			iov.iov_len = count - bufoffset;
1022 			uio.uio_offset = offset + bufoffset;
1023 			uio.uio_resid = iov.iov_len;
1024 			uio.uio_rw = UIO_WRITE;
1025 
1026 			if ((error = VOP_WRITE(uvp, &uio, 0, cred)) != 0)
1027 				break;
1028 
1029 			bufoffset += (count - bufoffset) - uio.uio_resid;
1030 		}
1031 
1032 		uio.uio_offset = offset + bufoffset;
1033 	}
1034 
1035 	free(buf, M_TEMP);
1036 
1037 	return (error);
1038 }
1039 
1040 /*
1041  * Copy file from lower to upper.
1042  *
1043  * If you need copy of the contents, set 1 to docopy. Otherwise, set 0 to
1044  * docopy.
1045  *
1046  * If no error returned, unp will be updated.
1047  */
1048 int
unionfs_copyfile(struct unionfs_node * unp,int docopy,struct ucred * cred,struct thread * td)1049 unionfs_copyfile(struct unionfs_node *unp, int docopy, struct ucred *cred,
1050 		 struct thread *td)
1051 {
1052 	int		error;
1053 	struct mount   *mp;
1054 	struct vnode   *udvp;
1055 	struct vnode   *lvp;
1056 	struct vnode   *uvp;
1057 	struct vattr	uva;
1058 
1059 	lvp = unp->un_lowervp;
1060 	uvp = NULLVP;
1061 
1062 	if ((UNIONFSTOV(unp)->v_mount->mnt_flag & MNT_RDONLY))
1063 		return (EROFS);
1064 	if (unp->un_dvp == NULLVP)
1065 		return (EINVAL);
1066 	if (unp->un_uppervp != NULLVP)
1067 		return (EEXIST);
1068 	udvp = VTOUNIONFS(unp->un_dvp)->un_uppervp;
1069 	if (udvp == NULLVP)
1070 		return (EROFS);
1071 	if ((udvp->v_mount->mnt_flag & MNT_RDONLY))
1072 		return (EROFS);
1073 
1074 	error = VOP_ACCESS(lvp, VREAD, cred, td);
1075 	if (error != 0)
1076 		return (error);
1077 
1078 	if ((error = vn_start_write(udvp, &mp, V_WAIT | PCATCH)) != 0)
1079 		return (error);
1080 	error = unionfs_vn_create_on_upper(&uvp, udvp, unp, &uva, td);
1081 	if (error != 0) {
1082 		vn_finished_write(mp);
1083 		return (error);
1084 	}
1085 
1086 	if (docopy != 0) {
1087 		error = VOP_OPEN(lvp, FREAD, cred, td, NULL);
1088 		if (error == 0) {
1089 			error = unionfs_copyfile_core(lvp, uvp, cred, td);
1090 			VOP_CLOSE(lvp, FREAD, cred, td);
1091 		}
1092 	}
1093 	VOP_CLOSE(uvp, FWRITE, cred, td);
1094 	VOP_ADD_WRITECOUNT_CHECKED(uvp, -1);
1095 	CTR3(KTR_VFS, "%s: vp %p v_writecount decreased to %d", __func__, uvp,
1096 	    uvp->v_writecount);
1097 
1098 	vn_finished_write(mp);
1099 
1100 	if (error == 0) {
1101 		/* Reset the attributes. Ignore errors. */
1102 		uva.va_type = VNON;
1103 		VOP_SETATTR(uvp, &uva, cred);
1104 	}
1105 
1106 	unionfs_node_update(unp, uvp, td);
1107 
1108 	return (error);
1109 }
1110 
1111 /*
1112  * It checks whether vp can rmdir. (check empty)
1113  *
1114  * vp is unionfs vnode.
1115  * vp should be locked.
1116  */
1117 int
unionfs_check_rmdir(struct vnode * vp,struct ucred * cred,struct thread * td)1118 unionfs_check_rmdir(struct vnode *vp, struct ucred *cred, struct thread *td)
1119 {
1120 	int		error;
1121 	int		eofflag;
1122 	int		lookuperr;
1123 	struct vnode   *uvp;
1124 	struct vnode   *lvp;
1125 	struct vnode   *tvp;
1126 	struct vattr	va;
1127 	struct componentname cn;
1128 	/*
1129 	 * The size of buf needs to be larger than DIRBLKSIZ.
1130 	 */
1131 	char		buf[256 * 6];
1132 	struct dirent  *dp;
1133 	struct dirent  *edp;
1134 	struct uio	uio;
1135 	struct iovec	iov;
1136 
1137 	ASSERT_VOP_ELOCKED(vp, "unionfs_check_rmdir");
1138 
1139 	eofflag = 0;
1140 	uvp = UNIONFSVPTOUPPERVP(vp);
1141 	lvp = UNIONFSVPTOLOWERVP(vp);
1142 
1143 	/* check opaque */
1144 	if ((error = VOP_GETATTR(uvp, &va, cred)) != 0)
1145 		return (error);
1146 	if (va.va_flags & OPAQUE)
1147 		return (0);
1148 
1149 	/* open vnode */
1150 #ifdef MAC
1151 	if ((error = mac_vnode_check_open(cred, vp, VEXEC|VREAD)) != 0)
1152 		return (error);
1153 #endif
1154 	if ((error = VOP_ACCESS(vp, VEXEC|VREAD, cred, td)) != 0)
1155 		return (error);
1156 	if ((error = VOP_OPEN(vp, FREAD, cred, td, NULL)) != 0)
1157 		return (error);
1158 
1159 	uio.uio_rw = UIO_READ;
1160 	uio.uio_segflg = UIO_SYSSPACE;
1161 	uio.uio_td = td;
1162 	uio.uio_offset = 0;
1163 
1164 #ifdef MAC
1165 	error = mac_vnode_check_readdir(td->td_ucred, lvp);
1166 #endif
1167 	while (!error && !eofflag) {
1168 		iov.iov_base = buf;
1169 		iov.iov_len = sizeof(buf);
1170 		uio.uio_iov = &iov;
1171 		uio.uio_iovcnt = 1;
1172 		uio.uio_resid = iov.iov_len;
1173 
1174 		error = VOP_READDIR(lvp, &uio, cred, &eofflag, NULL, NULL);
1175 		if (error != 0)
1176 			break;
1177 		if (eofflag == 0 && uio.uio_resid == sizeof(buf)) {
1178 #ifdef DIAGNOSTIC
1179 			panic("bad readdir response from lower FS.");
1180 #endif
1181 			break;
1182 		}
1183 
1184 		edp = (struct dirent*)&buf[sizeof(buf) - uio.uio_resid];
1185 		for (dp = (struct dirent*)buf; !error && dp < edp;
1186 		     dp = (struct dirent*)((caddr_t)dp + dp->d_reclen)) {
1187 			if (dp->d_type == DT_WHT || dp->d_fileno == 0 ||
1188 			    (dp->d_namlen == 1 && dp->d_name[0] == '.') ||
1189 			    (dp->d_namlen == 2 && !bcmp(dp->d_name, "..", 2)))
1190 				continue;
1191 
1192 			cn.cn_namelen = dp->d_namlen;
1193 			cn.cn_pnbuf = NULL;
1194 			cn.cn_nameptr = dp->d_name;
1195 			cn.cn_nameiop = LOOKUP;
1196 			cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
1197 			cn.cn_lkflags = LK_EXCLUSIVE;
1198 			cn.cn_thread = td;
1199 			cn.cn_cred = cred;
1200 
1201 			/*
1202 			 * check entry in lower.
1203 			 * Sometimes, readdir function returns
1204 			 * wrong entry.
1205 			 */
1206 			lookuperr = VOP_LOOKUP(lvp, &tvp, &cn);
1207 
1208 			if (!lookuperr)
1209 				vput(tvp);
1210 			else
1211 				continue; /* skip entry */
1212 
1213 			/*
1214 			 * check entry
1215 			 * If it has no exist/whiteout entry in upper,
1216 			 * directory is not empty.
1217 			 */
1218 			cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
1219 			lookuperr = VOP_LOOKUP(uvp, &tvp, &cn);
1220 
1221 			if (!lookuperr)
1222 				vput(tvp);
1223 
1224 			/* ignore exist or whiteout entry */
1225 			if (!lookuperr ||
1226 			    (lookuperr == ENOENT && (cn.cn_flags & ISWHITEOUT)))
1227 				continue;
1228 
1229 			error = ENOTEMPTY;
1230 		}
1231 	}
1232 
1233 	/* close vnode */
1234 	VOP_CLOSE(vp, FREAD, cred, td);
1235 
1236 	return (error);
1237 }
1238 
1239 #ifdef DIAGNOSTIC
1240 
1241 struct vnode   *
unionfs_checkuppervp(struct vnode * vp,char * fil,int lno)1242 unionfs_checkuppervp(struct vnode *vp, char *fil, int lno)
1243 {
1244 	struct unionfs_node *unp;
1245 
1246 	unp = VTOUNIONFS(vp);
1247 
1248 #ifdef notyet
1249 	if (vp->v_op != unionfs_vnodeop_p) {
1250 		printf("unionfs_checkuppervp: on non-unionfs-node.\n");
1251 #ifdef KDB
1252 		kdb_enter(KDB_WHY_UNIONFS,
1253 		    "unionfs_checkuppervp: on non-unionfs-node.\n");
1254 #endif
1255 		panic("unionfs_checkuppervp");
1256 	}
1257 #endif
1258 	return (unp->un_uppervp);
1259 }
1260 
1261 struct vnode   *
unionfs_checklowervp(struct vnode * vp,char * fil,int lno)1262 unionfs_checklowervp(struct vnode *vp, char *fil, int lno)
1263 {
1264 	struct unionfs_node *unp;
1265 
1266 	unp = VTOUNIONFS(vp);
1267 
1268 #ifdef notyet
1269 	if (vp->v_op != unionfs_vnodeop_p) {
1270 		printf("unionfs_checklowervp: on non-unionfs-node.\n");
1271 #ifdef KDB
1272 		kdb_enter(KDB_WHY_UNIONFS,
1273 		    "unionfs_checklowervp: on non-unionfs-node.\n");
1274 #endif
1275 		panic("unionfs_checklowervp");
1276 	}
1277 #endif
1278 	return (unp->un_lowervp);
1279 }
1280 #endif
1281