union_subr.c revision 10093
1/*
2 * Copyright (c) 1994 Jan-Simon Pendry
3 * Copyright (c) 1994
4 *	The Regents of the University of California.  All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Jan-Simon Pendry.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *	This product includes software developed by the University of
20 *	California, Berkeley and its contributors.
21 * 4. 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.4 (Berkeley) 2/17/94
38 * $Id: union_subr.c,v 1.6 1995/05/30 08:07:25 rgrimes Exp $
39 */
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/time.h>
44#include <sys/kernel.h>
45#include <sys/vnode.h>
46#include <sys/namei.h>
47#include <sys/malloc.h>
48#include <sys/file.h>
49#include <sys/filedesc.h>
50#include <sys/queue.h>
51#include <miscfs/union/union.h>
52
53#include <sys/proc.h>
54
55/* must be power of two, otherwise change UNION_HASH() */
56#define NHASH 32
57
58/* unsigned int ... */
59#define UNION_HASH(u, l) \
60	(((((unsigned long) (u)) + ((unsigned long) l)) >> 8) & (NHASH-1))
61
62static LIST_HEAD(unhead, union_node) unhead[NHASH];
63static int unvplock[NHASH];
64
65int
66union_init()
67{
68	int i;
69
70	for (i = 0; i < NHASH; i++)
71		LIST_INIT(&unhead[i]);
72	bzero((caddr_t) unvplock, sizeof(unvplock));
73	return (0);
74}
75
76static int
77union_list_lock(ix)
78	int ix;
79{
80
81	if (unvplock[ix] & UN_LOCKED) {
82		unvplock[ix] |= UN_WANT;
83		(void) tsleep((caddr_t) &unvplock[ix], PINOD, "unllck", 0);
84		return (1);
85	}
86
87	unvplock[ix] |= UN_LOCKED;
88
89	return (0);
90}
91
92static void
93union_list_unlock(ix)
94	int ix;
95{
96
97	unvplock[ix] &= ~UN_LOCKED;
98
99	if (unvplock[ix] & UN_WANT) {
100		unvplock[ix] &= ~UN_WANT;
101		wakeup((caddr_t) &unvplock[ix]);
102	}
103}
104
105void
106union_updatevp(un, uppervp, lowervp)
107	struct union_node *un;
108	struct vnode *uppervp;
109	struct vnode *lowervp;
110{
111	int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp);
112	int nhash = UNION_HASH(uppervp, lowervp);
113
114	if (ohash != nhash) {
115		/*
116		 * Ensure locking is ordered from lower to higher
117		 * to avoid deadlocks.
118		 */
119		if (nhash < ohash) {
120			int t = ohash;
121			ohash = nhash;
122			nhash = t;
123		}
124
125		while (union_list_lock(ohash))
126			continue;
127
128		while (union_list_lock(nhash))
129			continue;
130
131		LIST_REMOVE(un, un_cache);
132		union_list_unlock(ohash);
133	} else {
134		while (union_list_lock(nhash))
135			continue;
136	}
137
138	if (un->un_lowervp != lowervp) {
139		if (un->un_lowervp) {
140			vrele(un->un_lowervp);
141			if (un->un_path) {
142				free(un->un_path, M_TEMP);
143				un->un_path = 0;
144			}
145			if (un->un_dirvp) {
146				vrele(un->un_dirvp);
147				un->un_dirvp = NULLVP;
148			}
149		}
150		un->un_lowervp = lowervp;
151	}
152
153	if (un->un_uppervp != uppervp) {
154		if (un->un_uppervp)
155			vrele(un->un_uppervp);
156
157		un->un_uppervp = uppervp;
158	}
159
160	if (ohash != nhash)
161		LIST_INSERT_HEAD(&unhead[nhash], un, un_cache);
162
163	union_list_unlock(nhash);
164}
165
166void
167union_newlower(un, lowervp)
168	struct union_node *un;
169	struct vnode *lowervp;
170{
171
172	union_updatevp(un, un->un_uppervp, lowervp);
173}
174
175void
176union_newupper(un, uppervp)
177	struct union_node *un;
178	struct vnode *uppervp;
179{
180
181	union_updatevp(un, uppervp, un->un_lowervp);
182}
183
184/*
185 * allocate a union_node/vnode pair.  the vnode is
186 * referenced and locked.  the new vnode is returned
187 * via (vpp).  (mp) is the mountpoint of the union filesystem,
188 * (dvp) is the parent directory where the upper layer object
189 * should exist (but doesn't) and (cnp) is the componentname
190 * information which is partially copied to allow the upper
191 * layer object to be created at a later time.  (uppervp)
192 * and (lowervp) reference the upper and lower layer objects
193 * being mapped.  either, but not both, can be nil.
194 * if supplied, (uppervp) is locked.
195 * the reference is either maintained in the new union_node
196 * object which is allocated, or they are vrele'd.
197 *
198 * all union_nodes are maintained on a singly-linked
199 * list.  new nodes are only allocated when they cannot
200 * be found on this list.  entries on the list are
201 * removed when the vfs reclaim entry is called.
202 *
203 * a single lock is kept for the entire list.  this is
204 * needed because the getnewvnode() function can block
205 * waiting for a vnode to become free, in which case there
206 * may be more than one process trying to get the same
207 * vnode.  this lock is only taken if we are going to
208 * call getnewvnode, since the kernel itself is single-threaded.
209 *
210 * if an entry is found on the list, then call vget() to
211 * take a reference.  this is done because there may be
212 * zero references to it and so it needs to removed from
213 * the vnode free list.
214 */
215int
216union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp)
217	struct vnode **vpp;
218	struct mount *mp;
219	struct vnode *undvp;
220	struct vnode *dvp;		/* may be null */
221	struct componentname *cnp;	/* may be null */
222	struct vnode *uppervp;		/* may be null */
223	struct vnode *lowervp;		/* may be null */
224{
225	int error;
226	struct union_node *un = 0;
227	struct vnode *xlowervp = NULLVP;
228	int hash = 0;
229	int try;
230
231	if (uppervp == NULLVP && lowervp == NULLVP)
232		panic("union: unidentifiable allocation");
233
234	if (uppervp && lowervp && (uppervp->v_type != lowervp->v_type)) {
235		xlowervp = lowervp;
236		lowervp = NULLVP;
237	}
238
239loop:
240	for (try = 0; try < 3; try++) {
241		switch (try) {
242		case 0:
243			if (lowervp == NULLVP)
244				continue;
245			hash = UNION_HASH(uppervp, lowervp);
246			break;
247
248		case 1:
249			if (uppervp == NULLVP)
250				continue;
251			hash = UNION_HASH(uppervp, NULLVP);
252			break;
253
254		case 2:
255			if (lowervp == NULLVP)
256				continue;
257			hash = UNION_HASH(NULLVP, lowervp);
258			break;
259		}
260
261		while (union_list_lock(hash))
262			continue;
263
264		for (un = unhead[hash].lh_first; un != 0;
265					un = un->un_cache.le_next) {
266			if ((un->un_lowervp == lowervp ||
267			     un->un_lowervp == NULLVP) &&
268			    (un->un_uppervp == uppervp ||
269			     un->un_uppervp == NULLVP) &&
270			    (UNIONTOV(un)->v_mount == mp)) {
271				if (vget(UNIONTOV(un), 0)) {
272					union_list_unlock(hash);
273					goto loop;
274				}
275				break;
276			}
277		}
278
279		union_list_unlock(hash);
280
281		if (un)
282			break;
283	}
284
285	if (un) {
286		/*
287		 * Obtain a lock on the union_node.
288		 * uppervp is locked, though un->un_uppervp
289		 * may not be.  this doesn't break the locking
290		 * hierarchy since in the case that un->un_uppervp
291		 * is not yet locked it will be vrele'd and replaced
292		 * with uppervp.
293		 */
294
295		if ((dvp != NULLVP) && (uppervp == dvp)) {
296			/*
297			 * Access ``.'', so (un) will already
298			 * be locked.  Since this process has
299			 * the lock on (uppervp) no other
300			 * process can hold the lock on (un).
301			 */
302#ifdef DIAGNOSTIC
303			if ((un->un_flags & UN_LOCKED) == 0)
304				panic("union: . not locked");
305			else if (curproc && un->un_pid != curproc->p_pid &&
306				    un->un_pid > -1 && curproc->p_pid > -1)
307				panic("union: allocvp not lock owner");
308#endif
309		} else {
310			if (un->un_flags & UN_LOCKED) {
311				vrele(UNIONTOV(un));
312				un->un_flags |= UN_WANT;
313				(void) tsleep((caddr_t) &un->un_flags, PINOD, "unalvp", 0);
314				goto loop;
315			}
316			un->un_flags |= UN_LOCKED;
317
318#ifdef DIAGNOSTIC
319			if (curproc)
320				un->un_pid = curproc->p_pid;
321			else
322				un->un_pid = -1;
323#endif
324		}
325
326		/*
327		 * At this point, the union_node is locked,
328		 * un->un_uppervp may not be locked, and uppervp
329		 * is locked or nil.
330		 */
331
332		/*
333		 * Save information about the upper layer.
334		 */
335		if (uppervp != un->un_uppervp) {
336			union_newupper(un, uppervp);
337		} else if (uppervp) {
338			vrele(uppervp);
339		}
340
341		if (un->un_uppervp) {
342			un->un_flags |= UN_ULOCK;
343			un->un_flags &= ~UN_KLOCK;
344		}
345
346		/*
347		 * Save information about the lower layer.
348		 * This needs to keep track of pathname
349		 * and directory information which union_vn_create
350		 * might need.
351		 */
352		if (lowervp != un->un_lowervp) {
353			union_newlower(un, lowervp);
354			if (cnp && (lowervp != NULLVP) &&
355			    (lowervp->v_type == VREG)) {
356				un->un_hash = cnp->cn_hash;
357				un->un_path = malloc(cnp->cn_namelen+1,
358						M_TEMP, M_WAITOK);
359				bcopy(cnp->cn_nameptr, un->un_path,
360						cnp->cn_namelen);
361				un->un_path[cnp->cn_namelen] = '\0';
362				VREF(dvp);
363				un->un_dirvp = dvp;
364			}
365		} else if (lowervp) {
366			vrele(lowervp);
367		}
368		*vpp = UNIONTOV(un);
369		return (0);
370	}
371
372	/*
373	 * otherwise lock the vp list while we call getnewvnode
374	 * since that can block.
375	 */
376	hash = UNION_HASH(uppervp, lowervp);
377
378	if (union_list_lock(hash))
379		goto loop;
380
381	error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp);
382	if (error) {
383		if (uppervp) {
384			if (dvp == uppervp)
385				vrele(uppervp);
386			else
387				vput(uppervp);
388		}
389		if (lowervp)
390			vrele(lowervp);
391
392		goto out;
393	}
394
395	MALLOC((*vpp)->v_data, void *, sizeof(struct union_node),
396		M_TEMP, M_WAITOK);
397
398	if (uppervp)
399		(*vpp)->v_type = uppervp->v_type;
400	else
401		(*vpp)->v_type = lowervp->v_type;
402	un = VTOUNION(*vpp);
403	un->un_vnode = *vpp;
404	un->un_uppervp = uppervp;
405	un->un_lowervp = lowervp;
406	un->un_openl = 0;
407	un->un_flags = UN_LOCKED;
408	if (un->un_uppervp)
409		un->un_flags |= UN_ULOCK;
410#ifdef DIAGNOSTIC
411	if (curproc)
412		un->un_pid = curproc->p_pid;
413	else
414		un->un_pid = -1;
415#endif
416	if (cnp && (lowervp != NULLVP) && (lowervp->v_type == VREG)) {
417		un->un_hash = cnp->cn_hash;
418		un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK);
419		bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen);
420		un->un_path[cnp->cn_namelen] = '\0';
421		VREF(dvp);
422		un->un_dirvp = dvp;
423	} else {
424		un->un_hash = 0;
425		un->un_path = 0;
426		un->un_dirvp = 0;
427	}
428
429	LIST_INSERT_HEAD(&unhead[hash], un, un_cache);
430
431	if (xlowervp)
432		vrele(xlowervp);
433
434out:
435	union_list_unlock(hash);
436
437	return (error);
438}
439
440int
441union_freevp(vp)
442	struct vnode *vp;
443{
444	struct union_node *un = VTOUNION(vp);
445
446	LIST_REMOVE(un, un_cache);
447
448	if (un->un_uppervp)
449		vrele(un->un_uppervp);
450	if (un->un_lowervp)
451		vrele(un->un_lowervp);
452	if (un->un_dirvp)
453		vrele(un->un_dirvp);
454	if (un->un_path)
455		free(un->un_path, M_TEMP);
456
457	FREE(vp->v_data, M_TEMP);
458	vp->v_data = 0;
459
460	return (0);
461}
462
463/*
464 * copyfile.  copy the vnode (fvp) to the vnode (tvp)
465 * using a sequence of reads and writes.  both (fvp)
466 * and (tvp) are locked on entry and exit.
467 */
468int
469union_copyfile(p, cred, fvp, tvp)
470	struct proc *p;
471	struct ucred *cred;
472	struct vnode *fvp;
473	struct vnode *tvp;
474{
475	char *buf;
476	struct uio uio;
477	struct iovec iov;
478	int error = 0;
479
480	/*
481	 * strategy:
482	 * allocate a buffer of size MAXBSIZE.
483	 * loop doing reads and writes, keeping track
484	 * of the current uio offset.
485	 * give up at the first sign of trouble.
486	 */
487
488	uio.uio_procp = p;
489	uio.uio_segflg = UIO_SYSSPACE;
490	uio.uio_offset = 0;
491
492	VOP_UNLOCK(fvp);				/* XXX */
493	LEASE_CHECK(fvp, p, cred, LEASE_READ);
494	VOP_LOCK(fvp);					/* XXX */
495	VOP_UNLOCK(tvp);				/* XXX */
496	LEASE_CHECK(tvp, p, cred, LEASE_WRITE);
497	VOP_LOCK(tvp);					/* XXX */
498
499	buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK);
500
501	/* ugly loop follows... */
502	do {
503		off_t offset = uio.uio_offset;
504
505		uio.uio_iov = &iov;
506		uio.uio_iovcnt = 1;
507		iov.iov_base = buf;
508		iov.iov_len = MAXBSIZE;
509		uio.uio_resid = iov.iov_len;
510		uio.uio_rw = UIO_READ;
511		error = VOP_READ(fvp, &uio, 0, cred);
512
513		if (error == 0) {
514			uio.uio_iov = &iov;
515			uio.uio_iovcnt = 1;
516			iov.iov_base = buf;
517			iov.iov_len = MAXBSIZE - uio.uio_resid;
518			uio.uio_offset = offset;
519			uio.uio_rw = UIO_WRITE;
520			uio.uio_resid = iov.iov_len;
521
522			if (uio.uio_resid == 0)
523				break;
524
525			do {
526				error = VOP_WRITE(tvp, &uio, 0, cred);
527			} while ((uio.uio_resid > 0) && (error == 0));
528		}
529
530	} while (error == 0);
531
532	free(buf, M_TEMP);
533	return (error);
534}
535
536/*
537 * Create a shadow directory in the upper layer.
538 * The new vnode is returned locked.
539 *
540 * (um) points to the union mount structure for access to the
541 * the mounting process's credentials.
542 * (dvp) is the directory in which to create the shadow directory.
543 * it is unlocked on entry and exit.
544 * (cnp) is the componentname to be created.
545 * (vpp) is the returned newly created shadow directory, which
546 * is returned locked.
547 */
548int
549union_mkshadow(um, dvp, cnp, vpp)
550	struct union_mount *um;
551	struct vnode *dvp;
552	struct componentname *cnp;
553	struct vnode **vpp;
554{
555	int error;
556	struct vattr va;
557	struct proc *p = cnp->cn_proc;
558	struct componentname cn;
559
560	/*
561	 * policy: when creating the shadow directory in the
562	 * upper layer, create it owned by the user who did
563	 * the mount, group from parent directory, and mode
564	 * 777 modified by umask (ie mostly identical to the
565	 * mkdir syscall).  (jsp, kb)
566	 */
567
568	/*
569	 * A new componentname structure must be faked up because
570	 * there is no way to know where the upper level cnp came
571	 * from or what it is being used for.  This must duplicate
572	 * some of the work done by NDINIT, some of the work done
573	 * by namei, some of the work done by lookup and some of
574	 * the work done by VOP_LOOKUP when given a CREATE flag.
575	 * Conclusion: Horrible.
576	 *
577	 * The pathname buffer will be FREEed by VOP_MKDIR.
578	 */
579	cn.cn_pnbuf = malloc(cnp->cn_namelen+1, M_NAMEI, M_WAITOK);
580	bcopy(cnp->cn_nameptr, cn.cn_pnbuf, cnp->cn_namelen);
581	cn.cn_pnbuf[cnp->cn_namelen] = '\0';
582
583	cn.cn_nameiop = CREATE;
584	cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN);
585	cn.cn_proc = cnp->cn_proc;
586	if (um->um_op == UNMNT_ABOVE)
587		cn.cn_cred = cnp->cn_cred;
588	else
589		cn.cn_cred = um->um_cred;
590	cn.cn_nameptr = cn.cn_pnbuf;
591	cn.cn_namelen = cnp->cn_namelen;
592	cn.cn_hash = cnp->cn_hash;
593	cn.cn_consume = cnp->cn_consume;
594
595	VREF(dvp);
596	error = relookup(dvp, vpp, &cn);
597	if (error)
598		return (error);
599	vrele(dvp);
600
601	if (*vpp) {
602		VOP_ABORTOP(dvp, &cn);
603		VOP_UNLOCK(dvp);
604		vrele(*vpp);
605		*vpp = NULLVP;
606		return (EEXIST);
607	}
608
609	VATTR_NULL(&va);
610	va.va_type = VDIR;
611	va.va_mode = um->um_cmode;
612
613	/* LEASE_CHECK: dvp is locked */
614	LEASE_CHECK(dvp, p, p->p_ucred, LEASE_WRITE);
615
616	error = VOP_MKDIR(dvp, vpp, &cn, &va);
617	return (error);
618}
619
620/*
621 * union_vn_create: creates and opens a new shadow file
622 * on the upper union layer.  this function is similar
623 * in spirit to calling vn_open but it avoids calling namei().
624 * the problem with calling namei is that a) it locks too many
625 * things, and b) it doesn't start at the "right" directory,
626 * whereas relookup is told where to start.
627 */
628int
629union_vn_create(vpp, un, p)
630	struct vnode **vpp;
631	struct union_node *un;
632	struct proc *p;
633{
634	struct vnode *vp;
635	struct ucred *cred = p->p_ucred;
636	struct vattr vat;
637	struct vattr *vap = &vat;
638	int fmode = FFLAGS(O_WRONLY|O_CREAT|O_TRUNC|O_EXCL);
639	int error;
640	int cmode = UN_FILEMODE & ~p->p_fd->fd_cmask;
641	struct componentname cn;
642
643	*vpp = NULLVP;
644
645	/*
646	 * Build a new componentname structure (for the same
647	 * reasons outlines in union_mkshadow).
648	 * The difference here is that the file is owned by
649	 * the current user, rather than by the person who
650	 * did the mount, since the current user needs to be
651	 * able to write the file (that's why it is being
652	 * copied in the first place).
653	 */
654	cn.cn_namelen = strlen(un->un_path);
655	cn.cn_pnbuf = (caddr_t) malloc(cn.cn_namelen, M_NAMEI, M_WAITOK);
656	bcopy(un->un_path, cn.cn_pnbuf, cn.cn_namelen+1);
657	cn.cn_nameiop = CREATE;
658	cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN);
659	cn.cn_proc = p;
660	cn.cn_cred = p->p_ucred;
661	cn.cn_nameptr = cn.cn_pnbuf;
662	cn.cn_hash = un->un_hash;
663	cn.cn_consume = 0;
664
665	VREF(un->un_dirvp);
666	error = relookup(un->un_dirvp, &vp, &cn);
667	if (error)
668		return (error);
669	vrele(un->un_dirvp);
670
671	if (vp) {
672		VOP_ABORTOP(un->un_dirvp, &cn);
673		if (un->un_dirvp == vp)
674			vrele(un->un_dirvp);
675		else
676			vput(un->un_dirvp);
677		vrele(vp);
678		return (EEXIST);
679	}
680
681	/*
682	 * Good - there was no race to create the file
683	 * so go ahead and create it.  The permissions
684	 * on the file will be 0666 modified by the
685	 * current user's umask.  Access to the file, while
686	 * it is unioned, will require access to the top *and*
687	 * bottom files.  Access when not unioned will simply
688	 * require access to the top-level file.
689	 * TODO: confirm choice of access permissions.
690	 */
691	VATTR_NULL(vap);
692	vap->va_type = VREG;
693	vap->va_mode = cmode;
694	LEASE_CHECK(un->un_dirvp, p, cred, LEASE_WRITE);
695	error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap);
696	if (error)
697		return (error);
698
699	error = VOP_OPEN(vp, fmode, cred, p);
700	if (error) {
701		vput(vp);
702		return (error);
703	}
704
705	vp->v_writecount++;
706	*vpp = vp;
707	return (0);
708}
709
710int
711union_vn_close(vp, fmode, cred, p)
712	struct vnode *vp;
713	int fmode;
714	struct ucred *cred;
715	struct proc *p;
716{
717	if (fmode & FWRITE)
718		--vp->v_writecount;
719	return (VOP_CLOSE(vp, fmode, cred, p));
720}
721
722void
723union_removed_upper(un)
724	struct union_node *un;
725{
726	if (un->un_flags & UN_ULOCK) {
727		un->un_flags &= ~UN_ULOCK;
728		VOP_UNLOCK(un->un_uppervp);
729	}
730
731	union_newupper(un, NULLVP);
732}
733
734struct vnode *
735union_lowervp(vp)
736	struct vnode *vp;
737{
738	struct union_node *un = VTOUNION(vp);
739
740	if (un->un_lowervp && (vp->v_type == un->un_lowervp->v_type)) {
741		if (vget(un->un_lowervp, 0))
742			return (NULLVP);
743	}
744
745	return (un->un_lowervp);
746}
747