diff -ruN /backup/src.old/sys/adosfs/adlookup.c sys/adosfs/adlookup.c --- /backup/src.old/sys/adosfs/adlookup.c Mon Dec 9 21:33:12 2002 +++ sys/adosfs/adlookup.c Mon Dec 9 21:39:13 2002 @@ -90,6 +90,7 @@ *vpp = NULL; ucp = cnp->cn_cred; nameiop = cnp->cn_nameiop; + cnp->cn_flags &= ~PDIRUNLOCK; flags = cnp->cn_flags; last = flags & ISLASTCN; lockp = flags & LOCKPARENT; @@ -121,26 +122,35 @@ error = 0; } else if (flags & ISDOTDOT) { VOP_UNLOCK(vdp, 0, p); /* race */ + cnp->cn_flags |= PDIRUNLOCK; error = vget(*vpp, LK_EXCLUSIVE, p); - if (error == 0 && lockp && last) + if (error == 0 && lockp && last) { error = vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p); + if (error == 0) + cnp->cn_flags &= ~PDIRUNLOCK; + } } else { error = vget(*vpp, LK_EXCLUSIVE, p); /* if (lockp == 0 || error || last) */ - if (lockp == 0 || error || last == 0) + if (lockp == 0 || error || last == 0) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } } if (error == 0) { if (vpid == vdp->v_id) return (0); vput(*vpp); - if (lockp && vdp != *vpp && last) + if (lockp && vdp != *vpp && last) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } } *vpp = NULL; if ((error = vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p)) != 0) return (error); + cnp->cn_flags &= ~PDIRUNLOCK; } /* @@ -174,12 +184,18 @@ * */ VOP_UNLOCK(vdp, 0, p); /* race */ - if ((error = VFS_VGET(vdp->v_mount, ABLKTOINO(adp->pblock), - vpp)) != 0) - vn_lock(vdp, LK_RETRY | LK_EXCLUSIVE, p); - else if (last && lockp && - (error = vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p))) - vput(*vpp); + cnp->cn_flags |= PDIRUNLOCK; + error = VFS_VGET(vdp->v_mount, ABLKTOINO(adp->pblock), vpp); + if (error != 0) { + if (vn_lock(vdp, LK_RETRY | LK_EXCLUSIVE, p) == 0) + cnp->cn_flags &= ~PDIRUNLOCK; + } else if (last && lockp) { + if (error = vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p)){ + vput(*vpp); + } else { + cnp->cn_flags &= ~PDIRUNLOCK; + } + } if (error) { *vpp = NULL; return (error); @@ -238,8 +254,10 @@ #endif return (error); } - if (lockp == 0) + if (lockp == 0) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } cnp->cn_nameiop |= SAVENAME; #ifdef ADOSFS_DIAGNOSTIC printf("EJUSTRETURN)"); @@ -267,8 +285,7 @@ if (nameiop == RENAME && wantp && last) { if (vdp == *vpp) return(EISDIR); - if ((error = VOP_ACCESS(vdp, VWRITE, ucp, cnp->cn_proc)) != 0) - { + if ((error = VOP_ACCESS(vdp, VWRITE, ucp, cnp->cn_proc)) != 0) { vput(*vpp); *vpp = NULL; return (error); @@ -278,8 +295,10 @@ } if (vdp == *vpp) VREF(vdp); - else if (lockp == 0 || last == 0) + else if (lockp == 0 || last == 0) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } found_lockdone: if ((cnp->cn_flags & MAKEENTRY) && nocache == 0) cache_enter(vdp, *vpp, cnp); diff -ruN /backup/src.old/sys/adosfs/adosfs.h sys/adosfs/adosfs.h --- /backup/src.old/sys/adosfs/adosfs.h Mon Dec 9 21:33:12 2002 +++ sys/adosfs/adosfs.h Mon Dec 9 21:39:13 2002 @@ -60,7 +60,6 @@ struct adosfsmount *amp; /* owner file system */ struct vnode *vp; /* owner vnode */ struct lockf *a_lockf; /* byte level lock list */ - struct lock a_lock; /* anode lock */ u_int32_t fsize; /* (f) size of file in bytes */ daddr_t block; /* block num */ daddr_t pblock; /* (d/f/e) parent block */ diff -ruN /backup/src.old/sys/adosfs/adutil.c sys/adosfs/adutil.c --- /backup/src.old/sys/adosfs/adutil.c Mon Dec 9 21:33:12 2002 +++ sys/adosfs/adutil.c Mon Dec 9 21:39:13 2002 @@ -82,6 +82,8 @@ /* * insert in hash table and lock + * + * ap->vp must have been initialized before this call. */ int adosfs_ainshash(amp, ap) @@ -93,13 +95,13 @@ struct anode *aq; /* lock the inode, then put it on the appropriate hash list */ - lockmgr(&ap->a_lock, LK_EXCLUSIVE, (struct simplelock *)0, p); + lockmgr(&ap->vp->v_lock, LK_EXCLUSIVE, (struct simplelock *)0, p); hp = &->anodetab[AHASH(ap->block)]; for (aq = hp->lh_first; aq ; aq = aq->link.le_next) { if (aq->block == ap->block) { - lockmgr(&ap->a_lock, LK_RELEASE, + lockmgr(&ap->vp->v_lock, LK_RELEASE, (struct simplelock *)0, p); return (EEXIST); diff -ruN /backup/src.old/sys/adosfs/advfsops.c sys/adosfs/advfsops.c --- /backup/src.old/sys/adosfs/advfsops.c Mon Dec 9 21:33:12 2002 +++ sys/adosfs/advfsops.c Mon Dec 9 21:39:14 2002 @@ -379,7 +379,6 @@ */ vp->v_data = ap = malloc(sizeof(struct anode), M_ANODE, M_WAITOK); bzero(ap, sizeof(struct anode)); - lockinit(&ap->a_lock, PINOD, "anode", 0, 0); ap->vp = vp; ap->amp = amp; ap->block = AINOTOBLK(an); diff -ruN /backup/src.old/sys/adosfs/advnops.c sys/adosfs/advnops.c --- /backup/src.old/sys/adosfs/advnops.c Mon Dec 9 21:33:12 2002 +++ sys/adosfs/advnops.c Mon Dec 9 21:39:14 2002 @@ -507,7 +507,7 @@ advopprint(ap); #endif - rv = lockmgr(&VTOA(vp)->a_lock, ap->a_flags, &vp->v_interlock, + rv = lockmgr(vp->v_vnlock, ap->a_flags, &vp->v_interlock, ap->a_p); #ifdef ADOSFS_DIAGNOSTIC @@ -533,7 +533,7 @@ advopprint(ap); #endif - rv = lockmgr(&VTOA(vp)->a_lock, ap->a_flags | LK_RELEASE, + rv = lockmgr(vp->v_vnlock, ap->a_flags | LK_RELEASE, &vp->v_interlock, ap->a_p); #ifdef ADOSFS_DIAGNOSTIC @@ -685,7 +685,7 @@ /* XXX Fill in more info here. */ printf("tag VT_ADOSFS\n"); #ifdef DIAGNOSTIC - lockmgr_printinfo(&anp->a_lock); + lockmgr_printinfo(&ap->a_vp->v_lock); #endif return(0); } @@ -974,7 +974,7 @@ advopprint(ap); #endif - locked = lockstatus(&VTOA(ap->a_vp)->a_lock); + locked = lockstatus(ap->a_vp->v_vnlock); #ifdef ADOSFS_DIAGNOSTIC printf(" %d)", locked); diff -ruN /backup/src.old/sys/conf/files sys/conf/files --- /backup/src.old/sys/conf/files Mon Dec 9 21:34:07 2002 +++ sys/conf/files Mon Dec 9 21:39:14 2002 @@ -569,9 +569,11 @@ file miscfs/fdesc/fdesc_vfsops.c fdesc file miscfs/fdesc/fdesc_vnops.c fdesc file miscfs/fifofs/fifo_vnops.c fifo +file miscfs/genfs/layer_subr.c nullfs | umapfs +file miscfs/genfs/layer_vfsops.c nullfs | umapfs +file miscfs/genfs/layer_vnops.c nullfs | umapfs file miscfs/kernfs/kernfs_vfsops.c kernfs file miscfs/kernfs/kernfs_vnops.c kernfs -file miscfs/nullfs/null_subr.c nullfs file miscfs/nullfs/null_vfsops.c nullfs file miscfs/nullfs/null_vnops.c nullfs file miscfs/tcfs/tcfs_subr.c tcfs @@ -603,12 +605,12 @@ file miscfs/procfs/procfs_vfsops.c procfs file miscfs/procfs/procfs_vnops.c procfs file miscfs/specfs/spec_vnops.c -file miscfs/umapfs/umap_subr.c umapfs -file miscfs/umapfs/umap_vfsops.c umapfs -file miscfs/umapfs/umap_vnops.c umapfs -file miscfs/union/union_subr.c union -file miscfs/union/union_vfsops.c union -file miscfs/union/union_vnops.c union +file miscfs/umapfs/umap_subr.c umapfs +file miscfs/umapfs/umap_vfsops.c umapfs +file miscfs/umapfs/umap_vnops.c umapfs +file miscfs/union/union_subr.c union +file miscfs/union/union_vfsops.c union +file miscfs/union/union_vnops.c union file msdosfs/msdosfs_conv.c msdosfs file msdosfs/msdosfs_denode.c msdosfs file msdosfs/msdosfs_fat.c msdosfs diff -ruN /backup/src.old/sys/isofs/cd9660/cd9660_lookup.c sys/isofs/cd9660/cd9660_lookup.c --- /backup/src.old/sys/isofs/cd9660/cd9660_lookup.c Mon Dec 9 21:34:18 2002 +++ sys/isofs/cd9660/cd9660_lookup.c Mon Dec 9 21:39:14 2002 @@ -129,10 +129,13 @@ struct vnode **vpp = ap->a_vpp; struct componentname *cnp = ap->a_cnp; struct ucred *cred = cnp->cn_cred; - int flags = cnp->cn_flags; + int flags; int nameiop = cnp->cn_nameiop; struct proc *p = cnp->cn_proc; + cnp->cn_flags &= ~PDIRUNLOCK; + flags = cnp->cn_flags; + bp = NULL; *vpp = NULL; vdp = ap->a_dvp; @@ -181,13 +184,19 @@ error = 0; } else if (flags & ISDOTDOT) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; error = vget(vdp, LK_EXCLUSIVE, p); - if (!error && lockparent && (flags & ISLASTCN)) + if (!error && lockparent && (flags & ISLASTCN)) { error = vn_lock(pdp, LK_EXCLUSIVE, p); + if (error == 0) + cnp->cn_flags &= ~PDIRUNLOCK; + } } else { error = vget(vdp, LK_EXCLUSIVE, p); - if (!lockparent || error || !(flags & ISLASTCN)) + if (!lockparent || error || !(flags & ISLASTCN)) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } } /* * Check that the capability number did not change @@ -197,11 +206,14 @@ if (vpid == vdp->v_id) return (0); vput(vdp); - if (lockparent && pdp != vdp && (flags & ISLASTCN)) + if (lockparent && pdp != vdp && (flags & ISLASTCN)) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } } if ((error = vn_lock(pdp, LK_EXCLUSIVE, p)) != 0) return (error); + cnp->cn_flags &= ~PDIRUNLOCK; vdp = pdp; dp = VTOI(pdp); *vpp = NULL; @@ -426,16 +438,20 @@ if (flags & ISDOTDOT) { brelse(bp); VOP_UNLOCK(pdp, 0, p); /* race to get the inode */ + cnp->cn_flags |= PDIRUNLOCK; error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, &tdp, dp->i_ino != ino, NULL); if (error) { - vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p); + if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p) == 0) + cnp->cn_flags &= ~PDIRUNLOCK; return (error); } - if (lockparent && (flags & ISLASTCN) && - (error = vn_lock(pdp, LK_EXCLUSIVE, p))) { - vput(tdp); - return (error); + if (lockparent && (flags & ISLASTCN)) { + if ((error = vn_lock(pdp, LK_EXCLUSIVE, p))) { + vput(tdp); + return (error); + } + cnp->cn_flags &= ~PDIRUNLOCK; } *vpp = tdp; } else if (dp->i_number == dp->i_ino) { @@ -448,8 +464,10 @@ brelse(bp); if (error) return (error); - if (!lockparent || !(flags & ISLASTCN)) + if (!lockparent || !(flags & ISLASTCN)) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } *vpp = tdp; } diff -ruN /backup/src.old/sys/isofs/cd9660/cd9660_node.c sys/isofs/cd9660/cd9660_node.c --- /backup/src.old/sys/isofs/cd9660/cd9660_node.c Mon Dec 9 21:34:18 2002 +++ sys/isofs/cd9660/cd9660_node.c Mon Dec 9 21:39:14 2002 @@ -204,7 +204,7 @@ *ipp = ip; simple_unlock(&cd9660_ihash_slock); - lockmgr(&ip->i_lock, LK_EXCLUSIVE, 0, p); + lockmgr(&ip->i_vnode->v_lock, LK_EXCLUSIVE, 0, p); return (0); } diff -ruN /backup/src.old/sys/isofs/cd9660/cd9660_node.h sys/isofs/cd9660/cd9660_node.h --- /backup/src.old/sys/isofs/cd9660/cd9660_node.h Mon Dec 9 21:34:18 2002 +++ sys/isofs/cd9660/cd9660_node.h Mon Dec 9 21:39:14 2002 @@ -89,8 +89,6 @@ doff_t i_diroff; /* offset in dir, where we found last entry */ doff_t i_offset; /* offset of free space in directory */ ino_t i_ino; /* inode number of found directory */ - struct lock i_lock; /* node lock */ - long iso_extent; /* extent of file */ long i_size; long iso_start; /* actual start of data of file (may be different */ diff -ruN /backup/src.old/sys/isofs/cd9660/cd9660_vfsops.c sys/isofs/cd9660/cd9660_vfsops.c --- /backup/src.old/sys/isofs/cd9660/cd9660_vfsops.c Mon Dec 9 21:34:18 2002 +++ sys/isofs/cd9660/cd9660_vfsops.c Mon Dec 9 21:39:14 2002 @@ -745,6 +745,7 @@ struct vnode *vp, *nvp; dev_t dev; int error; + struct proc *p = curproc; retry: imp = VFSTOISOFS(mp); @@ -760,7 +761,7 @@ MALLOC(ip, struct iso_node *, sizeof(struct iso_node), M_ISOFSNODE, M_WAITOK); bzero((caddr_t)ip, sizeof(struct iso_node)); - lockinit(&ip->i_lock, PINOD, "isoinode", 0, 0); + vp->v_data = ip; ip->i_vnode = vp; ip->i_dev = dev; @@ -921,8 +922,9 @@ nvp->v_data = vp->v_data; vp->v_data = NULL; vp->v_op = spec_vnodeop_p; - vrele(vp); + vput(vp); vgone(vp); + lockmgr(&nvp->v_lock, LK_EXCLUSIVE, &nvp->v_interlock, p); /* * Reinitialize aliased inode. */ diff -ruN /backup/src.old/sys/isofs/cd9660/cd9660_vnops.c sys/isofs/cd9660/cd9660_vnops.c --- /backup/src.old/sys/isofs/cd9660/cd9660_vnops.c Mon Dec 9 21:34:18 2002 +++ sys/isofs/cd9660/cd9660_vnops.c Mon Dec 9 21:39:14 2002 @@ -864,7 +864,7 @@ } */ *ap = v; struct vnode *vp = ap->a_vp; - return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags, &vp->v_interlock, + return (lockmgr(vp->v_vnlock, ap->a_flags, &vp->v_interlock, ap->a_p)); } @@ -880,7 +880,7 @@ } */ *ap = v; struct vnode *vp = ap->a_vp; - return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags | LK_RELEASE, + return (lockmgr(vp->v_vnlock, ap->a_flags | LK_RELEASE, &vp->v_interlock, ap->a_p)); } @@ -952,7 +952,7 @@ struct vnode *a_vp; } */ *ap = v; - return (lockstatus(&VTOI(ap->a_vp)->i_lock)); + return (lockstatus(ap->a_vp->v_vnlock)); } /* diff -ruN /backup/src.old/sys/kern/vfs_conf.c sys/kern/vfs_conf.c --- /backup/src.old/sys/kern/vfs_conf.c Mon Dec 9 21:34:19 2002 +++ sys/kern/vfs_conf.c Mon Dec 9 21:39:14 2002 @@ -112,11 +112,11 @@ #endif #ifdef NULLFS -extern struct vfsops null_vfsops; +extern struct vfsops nullfs_vfsops; #endif #ifdef UMAPFS -extern struct vfsops umap_vfsops; +extern struct vfsops umapfs_vfsops; #endif #ifdef KERNFS @@ -215,7 +215,7 @@ /* Loopback (Minimal) Filesystem Layer */ #ifdef NULLFS - { &null_vfsops, MOUNT_NULL, 9, 0, 0, NULL, NULL }, + { &nullfs_vfsops, MOUNT_NULL, 9, 0, 0, NULL, NULL }, #endif /* Union (translucent) Filesystem */ @@ -225,7 +225,7 @@ /* User/Group Identifer Remapping Filesystem */ #ifdef UMAPFS - { &umap_vfsops, MOUNT_UMAP, 10, 0, 0, NULL, NULL }, + { &umapfs_vfsops, MOUNT_UMAP, 10, 0, 0, NULL, NULL }, #endif /* Portal Filesystem */ @@ -280,7 +280,7 @@ extern struct vnodeopv_desc fdesc_vnodeop_opv_desc; extern struct vnodeopv_desc portal_vnodeop_opv_desc; extern struct vnodeopv_desc null_vnodeop_opv_desc; -extern struct vnodeopv_desc umap_vnodeop_opv_desc; +extern struct vnodeopv_desc umapfs_vnodeop_opv_desc; extern struct vnodeopv_desc kernfs_vnodeop_opv_desc; extern struct vnodeopv_desc procfs_vnodeop_opv_desc; extern struct vnodeopv_desc cd9660_vnodeop_opv_desc; @@ -336,7 +336,7 @@ &null_vnodeop_opv_desc, #endif #ifdef UMAPFS - &umap_vnodeop_opv_desc, + &umapfs_vnodeop_opv_desc, #endif #ifdef KERNFS &kernfs_vnodeop_opv_desc, diff -ruN /backup/src.old/sys/kern/vfs_default.c sys/kern/vfs_default.c --- /backup/src.old/sys/kern/vfs_default.c Mon Dec 9 21:34:19 2002 +++ sys/kern/vfs_default.c Mon Dec 9 21:39:14 2002 @@ -225,17 +225,7 @@ vop_generic_unlock(v) void *v; { - struct vop_unlock_args /* { - struct vnode *a_vp; - int a_flags; - struct proc *a_p; - } */ *ap = v; - - struct vnode *vp = ap->a_vp; - - if (vp->v_vnlock == NULL) - return (0); - return (lockmgr(vp->v_vnlock, LK_RELEASE, NULL, ap->a_p)); + return (0); } /* diff -ruN /backup/src.old/sys/kern/vfs_lookup.c sys/kern/vfs_lookup.c --- /backup/src.old/sys/kern/vfs_lookup.c Mon Dec 9 21:34:19 2002 +++ sys/kern/vfs_lookup.c Mon Dec 9 21:39:14 2002 @@ -439,6 +439,8 @@ unionlookup: ndp->ni_dvp = dp; ndp->ni_vp = NULL; + cnp->cn_flags &= ~PDIRUNLOCK; + if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) { #ifdef DIAGNOSTIC if (ndp->ni_vp != NULL) @@ -452,7 +454,10 @@ (dp->v_mount->mnt_flag & MNT_UNION)) { tdp = dp; dp = dp->v_mount->mnt_vnodecovered; - vput(tdp); + if (cnp->cn_flags & PDIRUNLOCK) + vrele(tdp); + else + vput(tdp); VREF(dp); vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); goto unionlookup; @@ -585,7 +590,8 @@ return (0); bad2: - if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) + if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN) && + ((cnp->cn_flags & PDIRUNLOCK) == 0)) VOP_UNLOCK(ndp->ni_dvp, 0, p); vrele(ndp->ni_dvp); bad: diff -ruN /backup/src.old/sys/kern/vfs_subr.c sys/kern/vfs_subr.c --- /backup/src.old/sys/kern/vfs_subr.c Mon Dec 9 21:34:19 2002 +++ sys/kern/vfs_subr.c Mon Dec 9 21:39:14 2002 @@ -409,13 +409,21 @@ simple_unlock(&vnode_free_list_slock); vp = pool_get(&vnode_pool, PR_WAITOK); bzero((char *)vp, sizeof *vp); + simple_lock_init(&vp->v_interlock); numvnodes++; } else { for (vp = TAILQ_FIRST(listhd); vp != NULLVP; vp = TAILQ_NEXT(vp, v_freelist)) { - if (simple_lock_try(&vp->v_interlock)) - break; + if (simple_lock_try(&vp->v_interlock)) { + if ((vp->v_flag & VLAYER) == 0) + break; + if (VOP_ISLOCKED(vp) == 0) + break; + else + simple_unlock(&vp->v_interlock); + } } + /* * Unless this is a bad time of the month, at most * the first NCPUS items on the free list are @@ -456,6 +464,8 @@ vp->v_socket = 0; } vp->v_type = VNON; + vp->v_vnlock = &vp->v_lock; + lockinit(vp->v_vnlock, PVFS, "vnlock", 0, 0); cache_purge(vp); vp->v_tag = tag; vp->v_op = vops; @@ -635,6 +645,8 @@ vclean(vp, 0, p); vp->v_op = nvp->v_op; vp->v_tag = nvp->v_tag; + vp->v_vnlock = &vp->v_lock; + lockinit(vp->v_vnlock, PVFS, "vnlock", 0, 0); nvp->v_type = VNON; insmntque(vp, mp); return (vp); @@ -880,7 +892,7 @@ if (vp->v_mount != mp) goto loop; nvp = vp->v_mntvnodes.le_next; - simple_lock(&vp->v_interlock); + simple_lock(&vp->v_interlock); simple_unlock(&mntvnode_slock); error = func(vp, arg); @@ -896,85 +908,80 @@ } -struct vflush_args { - struct vnode *skipvp; - int busy; - int flags; -}; - -int -vflush_vnode(struct vnode *vp, void *arg) { - struct vflush_args *va = arg; - struct proc *p = curproc; - - if (vp == va->skipvp) { - simple_unlock(&vp->v_interlock); - return (0); - } - - if ((va->flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) { - simple_unlock(&vp->v_interlock); - return (0); - } - - /* - * If WRITECLOSE is set, only flush out regular file - * vnodes open for writing. - */ - if ((va->flags & WRITECLOSE) && - (vp->v_writecount == 0 || vp->v_type != VREG)) { - simple_unlock(&vp->v_interlock); - return (0); - } - - /* - * With v_usecount == 0, all we need to do is clear - * out the vnode data structures and we are done. - */ - if (vp->v_usecount == 0) { - vgonel(vp, p); - return (0); - } - - /* - * If FORCECLOSE is set, forcibly close the vnode. - * For block or character devices, revert to an - * anonymous device. For all other files, just kill them. - */ - if (va->flags & FORCECLOSE) { - if (vp->v_type != VBLK && vp->v_type != VCHR) { - vgonel(vp, p); - } else { - vclean(vp, 0, p); - vp->v_op = spec_vnodeop_p; - insmntque(vp, (struct mount *)0); - } - return (0); - } - -#ifdef DEBUG - if (busyprt) - vprint("vflush: busy vnode", vp); -#endif - simple_unlock(&vp->v_interlock); - va->busy++; - return (0); -} - int vflush(mp, skipvp, flags) struct mount *mp; struct vnode *skipvp; int flags; { - struct vflush_args va; - va.skipvp = skipvp; - va.busy = 0; - va.flags = flags; - - vfs_mount_foreach_vnode(mp, vflush_vnode, &va); + struct proc *p = curproc; /* XXX */ + struct vnode *vp, *nvp; + int busy = 0; - if (va.busy) + simple_lock(&mntvnode_slock); +loop: + for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) { + if (vp->v_mount != mp) + goto loop; + nvp = LIST_NEXT(vp, v_mntvnodes); + /* + * Skip over a selected vnode. + */ + if (vp == skipvp) + continue; + simple_lock(&vp->v_interlock); + /* + * Skip over a vnodes marked VSYSTEM. + */ + if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) { + simple_unlock(&vp->v_interlock); + continue; + } + /* + * If WRITECLOSE is set, only flush out regular file + * vnodes open for writing. + */ + if ((flags & WRITECLOSE) && + (vp->v_writecount == 0 || vp->v_type != VREG)) { + simple_unlock(&vp->v_interlock); + continue; + } + /* + * With v_usecount == 0, all we need to do is clear + * out the vnode data structures and we are done. + */ + if (vp->v_usecount == 0) { + simple_unlock(&mntvnode_slock); + vgonel(vp, p); + simple_lock(&mntvnode_slock); + continue; + } + /* + * If FORCECLOSE is set, forcibly close the vnode. + * For block or character devices, revert to an + * anonymous device. For all other files, just kill them. + */ + if (flags & FORCECLOSE) { + simple_unlock(&mntvnode_slock); + if (vp->v_type != VBLK && vp->v_type != VCHR) { + vgonel(vp, p); + } else { + vclean(vp, 0, p); + vp->v_op = spec_vnodeop_p; + insmntque(vp, (struct mount *)0); + } + simple_lock(&mntvnode_slock); + continue; + } +#ifdef DEBUG + if (busyprt) + vprint("vflush: busy vnode", vp); +#endif + simple_unlock(&vp->v_interlock); + busy++; + } + simple_unlock(&mntvnode_slock); + if (busy) return (EBUSY); return (0); } @@ -1060,12 +1067,6 @@ simple_unlock(&vp->v_interlock); } cache_purge(vp); - if (vp->v_vnlock) { - if ((vp->v_vnlock->lk_flags & LK_DRAINED) == 0) - vprint("vclean: lock not drained", vp); - FREE(vp->v_vnlock, M_VNODE); - vp->v_vnlock = NULL; - } /* * Done with purge, notify sleepers of the grim news. @@ -1135,6 +1136,11 @@ register struct vnode *vq; struct vnode *vx; + if (vp == NULLVP) { + printf("vgonel on nullvp\n"); + return; + } + /* * If a vgone (or vclean) is already in progress, * wait until it is done and return. @@ -1160,33 +1166,37 @@ */ if ((vp->v_type == VBLK || vp->v_type == VCHR) && vp->v_specinfo != 0) { simple_lock(&spechash_slock); - if (*vp->v_hashchain == vp) { - *vp->v_hashchain = vp->v_specnext; - } else { - for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { - if (vq->v_specnext != vp) - continue; - vq->v_specnext = vp->v_specnext; - break; - } - if (vq == NULL) - panic("missing bdev"); - } - if (vp->v_flag & VALIASED) { - vx = NULL; - for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { - if (vq->v_rdev != vp->v_rdev || - vq->v_type != vp->v_type) - continue; - if (vx) + if (vp->v_hashchain != NULL) { + if (*vp->v_hashchain == vp) { + *vp->v_hashchain = vp->v_specnext; + } else { + for (vq = *vp->v_hashchain; vq; + vq = vq->v_specnext) { + if (vq->v_specnext != vp) + continue; + vq->v_specnext = vp->v_specnext; break; - vx = vq; + } + if (vq == NULL) + panic("missing bdev"); + } + if (vp->v_flag & VALIASED) { + vx = NULL; + for (vq = *vp->v_hashchain; vq; + vq = vq->v_specnext) { + if (vq->v_rdev != vp->v_rdev || + vq->v_type != vp->v_type) + continue; + if (vx) + break; + vx = vq; + } + if (vx == NULL) + panic("missing alias"); + if (vq == NULL) + vx->v_flag &= ~VALIASED; + vp->v_flag &= ~VALIASED; } - if (vx == NULL) - panic("missing alias"); - if (vq == NULL) - vx->v_flag &= ~VALIASED; - vp->v_flag &= ~VALIASED; } simple_unlock(&spechash_slock); FREE(vp->v_specinfo, M_VNODE); @@ -1283,11 +1293,14 @@ /* * Alias, but not in use, so flush it out. */ - if (vq->v_usecount == 0 && vq != vp) { + if (vq->v_usecount == 0 && vq != vp && + (vq->v_flag & VXLOCK) == 0) { simple_unlock(&spechash_slock); vgone(vq); goto loop; } + if ((vq->v_flag & VXLOCK)) + printf("VXLOCK got one!\n"); count += vq->v_usecount; } simple_unlock(&spechash_slock); diff -ruN /backup/src.old/sys/kern/vfs_syscalls.c sys/kern/vfs_syscalls.c --- /backup/src.old/sys/kern/vfs_syscalls.c Mon Dec 9 21:34:19 2002 +++ sys/kern/vfs_syscalls.c Mon Dec 9 21:39:14 2002 @@ -2607,7 +2607,7 @@ if (p->p_ucred->cr_uid != vattr.va_uid && (error = suser(p->p_ucred, &p->p_acflag))) goto out; - if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) + if (vp->v_usecount > 1 || (vp->v_flag & (VALIASED | VLAYER))) VOP_REVOKE(vp, REVOKEALL); out: vrele(vp); diff -ruN /backup/src.old/sys/kern/vnode_if.c sys/kern/vnode_if.c --- /backup/src.old/sys/kern/vnode_if.c Mon Dec 9 21:34:19 2002 +++ sys/kern/vnode_if.c Mon Dec 9 21:39:14 2002 @@ -5,7 +5,7 @@ * Created from the file: * OpenBSD: vnode_if.src,v 1.19 2002/02/22 20:37:45 drahn Exp * by the script: - * OpenBSD: vnode_if.sh,v 1.8 2001/02/26 17:34:18 art Exp + * OpenBSD: vnode_if.sh,v 1.10 2002/03/14 23:47:05 millert Exp */ /* @@ -119,7 +119,7 @@ struct vnodeop_desc vop_create_desc = { 0, "vop_create", - 0 | VDESC_VP0_WILLRELE, + 0 | VDESC_VP0_WILLPUT, vop_create_vp_offsets, VOPARG_OFFSETOF(struct vop_create_args, a_vpp), VDESC_NO_OFFSET, @@ -154,7 +154,7 @@ struct vnodeop_desc vop_mknod_desc = { 0, "vop_mknod", - 0 | VDESC_VP0_WILLRELE | VDESC_VPP_WILLRELE, + 0 | VDESC_VP0_WILLPUT | VDESC_VPP_WILLRELE, vop_mknod_vp_offsets, VOPARG_OFFSETOF(struct vop_mknod_args, a_vpp), VDESC_NO_OFFSET, @@ -611,7 +611,7 @@ struct vnodeop_desc vop_remove_desc = { 0, "vop_remove", - 0 | VDESC_VP0_WILLRELE | VDESC_VP1_WILLRELE, + 0 | VDESC_VP0_WILLPUT | VDESC_VP1_WILLPUT, vop_remove_vp_offsets, VDESC_NO_OFFSET, VDESC_NO_OFFSET, @@ -649,7 +649,7 @@ struct vnodeop_desc vop_link_desc = { 0, "vop_link", - 0 | VDESC_VP0_WILLRELE, + 0 | VDESC_VP0_WILLPUT, vop_link_vp_offsets, VDESC_NO_OFFSET, VDESC_NO_OFFSET, @@ -685,7 +685,7 @@ struct vnodeop_desc vop_rename_desc = { 0, "vop_rename", - 0 | VDESC_VP0_WILLRELE | VDESC_VP1_WILLRELE | VDESC_VP2_WILLRELE | VDESC_VP3_WILLRELE, + 0 | VDESC_VP0_WILLRELE | VDESC_VP1_WILLRELE | VDESC_VP2_WILLPUT | VDESC_VP3_WILLRELE, vop_rename_vp_offsets, VDESC_NO_OFFSET, VDESC_NO_OFFSET, @@ -724,7 +724,7 @@ struct vnodeop_desc vop_mkdir_desc = { 0, "vop_mkdir", - 0 | VDESC_VP0_WILLRELE, + 0 | VDESC_VP0_WILLPUT, vop_mkdir_vp_offsets, VOPARG_OFFSETOF(struct vop_mkdir_args, a_vpp), VDESC_NO_OFFSET, @@ -760,7 +760,7 @@ struct vnodeop_desc vop_rmdir_desc = { 0, "vop_rmdir", - 0 | VDESC_VP0_WILLRELE | VDESC_VP1_WILLRELE, + 0 | VDESC_VP0_WILLPUT | VDESC_VP1_WILLPUT, vop_rmdir_vp_offsets, VDESC_NO_OFFSET, VDESC_NO_OFFSET, @@ -797,7 +797,7 @@ struct vnodeop_desc vop_symlink_desc = { 0, "vop_symlink", - 0 | VDESC_VP0_WILLRELE | VDESC_VPP_WILLRELE, + 0 | VDESC_VP0_WILLPUT | VDESC_VPP_WILLRELE, vop_symlink_vp_offsets, VOPARG_OFFSETOF(struct vop_symlink_args, a_vpp), VDESC_NO_OFFSET, @@ -933,7 +933,7 @@ struct vnodeop_desc vop_inactive_desc = { 0, "vop_inactive", - 0, + 0 | VDESC_VP0_WILLUNLOCK, vop_inactive_vp_offsets, VDESC_NO_OFFSET, VDESC_NO_OFFSET, diff -ruN /backup/src.old/sys/kern/vnode_if.sh sys/kern/vnode_if.sh --- /backup/src.old/sys/kern/vnode_if.sh Mon Dec 9 21:34:19 2002 +++ sys/kern/vnode_if.sh Mon Dec 9 21:39:14 2002 @@ -112,8 +112,17 @@ $3 == "WILLRELE") { willrele[argc] = 1; i++; + } else if ($2 == "WILLUNLOCK" || + $3 == "WILLUNLOCK") { + willrele[argc] = 2; + i++; + } else if ($2 == "WILLPUT" || + $3 == "WILLPUT") { + willrele[argc] = 3; + i++; } else willrele[argc] = 0; + if ($2 == "SHOULDBELOCKED") { shouldbelocked[argc] = 1; @@ -280,10 +289,17 @@ vpnum = 0; for (i=0; icn_namelen == 1 && *pname == '.') { *vpp = dvp; VREF(dvp); - vn_lock(dvp, LK_SHARED | LK_RETRY, p); return (0); } @@ -277,8 +275,7 @@ goto bad; *vpp = fvp; fvp->v_type = VDIR; - vn_lock(fvp, LK_SHARED | LK_RETRY, p); - return (0); + goto good; } if (cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) { @@ -292,8 +289,7 @@ goto bad; *vpp = fvp; fvp->v_type = VCHR; - vn_lock(fvp, LK_SHARED | LK_RETRY, p); - return (0); + goto good; } ln = 0; @@ -323,8 +319,7 @@ VTOFDESC(fvp)->fd_link = ln; *vpp = fvp; fvp->v_type = VLNK; - vn_lock(fvp, LK_SHARED | LK_RETRY, p); - return (0); + goto good; } else { error = ENOENT; goto bad; @@ -334,9 +329,15 @@ case Fdevfd: if (cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) { - if ((error = fdesc_root(dvp->v_mount, vpp))) + VOP_UNLOCK(dvp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + error = fdesc_root(dvp->v_mount, vpp); + if (error) goto bad; + if (((~cnp->cn_flags & (ISLASTCN | LOCKPARENT)) == 0) && + ((error = vn_lock(dvp, LK_EXCLUSIVE, p)) == 0)) + cnp->cn_flags &= ~PDIRUNLOCK; return (0); } @@ -361,15 +362,22 @@ if (error) goto bad; VTOFDESC(fvp)->fd_fd = fd; - vn_lock(fvp, LK_SHARED | LK_RETRY, p); *vpp = fvp; - return (0); + goto good; } bad:; - vn_lock(dvp, LK_SHARED | LK_RETRY, p); *vpp = NULL; return (error); + +good:; + + if (((~cnp->cn_flags) & (ISLASTCN | LOCKPARENT)) != 0) { + VOP_UNLOCK(dvp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } + return(0); + } int @@ -746,10 +754,14 @@ struct ucred *a_cred; } */ *ap = v; int error = EOPNOTSUPP; + struct vnode *vp = ap->a_vp; + struct proc *p = curproc; switch (VTOFDESC(ap->a_vp)->fd_type) { case Fctty: + VOP_UNLOCK(vp, 0, p); error = cttyread(devctty, ap->a_uio, ap->a_ioflag); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); break; default: @@ -771,10 +783,14 @@ struct ucred *a_cred; } */ *ap = v; int error = EOPNOTSUPP; + struct vnode *vp = ap->a_vp; + struct proc *p = curproc; switch (VTOFDESC(ap->a_vp)->fd_type) { case Fctty: + VOP_UNLOCK(vp, 0, p); error = cttywrite(devctty, ap->a_uio, ap->a_ioflag); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); break; default: diff -ruN /backup/src.old/sys/miscfs/genfs/genfs.h sys/miscfs/genfs/genfs.h --- /backup/src.old/sys/miscfs/genfs/genfs.h Wed Dec 31 19:00:00 1969 +++ sys/miscfs/genfs/genfs.h Mon Dec 9 21:39:15 2002 @@ -0,0 +1,30 @@ +/* $NetBSD: genfs.h,v 1.16 2002/10/23 09:14:36 jdolecek Exp $ */ + +int genfs_badop(void *); +int genfs_nullop(void *); +int genfs_enoioctl(void *); +int genfs_enoextops(void *); +int genfs_einval(void *); +int genfs_eopnotsupp(void *); +int genfs_eopnotsupp_rele(void *); +int genfs_ebadf(void *); +int genfs_nolock(void *); +int genfs_noislocked(void *); +int genfs_nounlock(void *); + +int genfs_poll(void *); +int genfs_kqfilter(void *); +int genfs_fcntl(void *); +int genfs_fsync(void *); +int genfs_seek(void *); +int genfs_abortop(void *); +int genfs_revoke(void *); +int genfs_lease_check(void *); +int genfs_lock(void *); +int genfs_islocked(void *); +int genfs_unlock(void *); +int genfs_mmap(void *); +int genfs_getpages(void *); +int genfs_putpages(void *); +int genfs_null_putpages(void *); +int genfs_compat_getpages(void *); diff -ruN /backup/src.old/sys/miscfs/genfs/layer.h sys/miscfs/genfs/layer.h --- /backup/src.old/sys/miscfs/genfs/layer.h Wed Dec 31 19:00:00 1969 +++ sys/miscfs/genfs/layer.h Mon Dec 9 21:39:15 2002 @@ -0,0 +1,166 @@ +/* $NetBSD: layer.h,v 1.4 2001/06/07 13:32:46 wiz Exp $ */ + +/* + * Copyright (c) 1999 National Aeronautics & Space Administration + * All rights reserved. + * + * This software was written by William Studenmund of the + * Numerical Aerospace Simulation Facility, NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the National Aeronautics & Space Administration + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB- + * UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software donated to Berkeley by + * Jan-Simon Pendry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: Id: lofs.h,v 1.8 1992/05/30 10:05:43 jsp Exp + * @(#)null.h 8.2 (Berkeley) 1/21/94 + */ + +#ifndef _MISCFS_GENFS_LAYER_H_ +#define _MISCFS_GENFS_LAYER_H_ + +struct layer_args { + char *target; /* Target of loopback */ + struct export_args export; /* network export info */ +}; + +#ifdef _KERNEL + +struct layer_node; + +LIST_HEAD(layer_node_hashhead, layer_node); + +struct layer_mount { + struct mount *layerm_vfs; + struct vnode *layerm_rootvp; /* Ref to root layer_node */ + struct netexport layerm_export; /* export info */ + u_int layerm_flags; /* mount point layer flags */ + u_int layerm_size; /* size of fs's struct node */ + enum vtype layerm_tag; /* vtag of our vnodes */ + int /* bypass routine for this mount */ + (*layerm_bypass)(void *); + int (*layerm_alloc) /* alloc a new layer node */ + (struct mount *, struct vnode *, + struct vnode **); + int /* ops for our nodes */ + (**layerm_vnodeop_p)(void *); + struct layer_node_hashhead /* head of hash list for layer_nodes */ + *layerm_node_hashtbl; + u_long layerm_node_hash; /* hash mask for hash chain */ + struct simplelock layerm_hashlock; /* interlock for hash chain. */ +}; + +#define LAYERFS_MFLAGS 0x00000fff /* reserved layer mount flags */ +#define LAYERFS_MBYPASSDEBUG 0x00000001 + +/* + * A cache of vnode references + */ +struct layer_node { + LIST_ENTRY(layer_node) layer_hash; /* Hash list */ + struct vnode *layer_lowervp; /* VREFed once */ + struct vnode *layer_vnode; /* Back pointer */ + unsigned int layer_flags; /* locking, etc. */ +}; + +#define LAYERFS_RESFLAGS 0x00000fff /* flags reserved for layerfs */ + +/* + * The following macros handle upperfs-specific locking. They are needed + * when the lowerfs does not export a struct lock for locking use by the + * upper layers. These macros are inteded for adjusting the upperfs + * struct lock to reflect changes in the underlying vnode's lock state. + */ +#define LAYERFS_UPPERLOCK(v, f, r) do { \ + if ((v)->v_vnlock == NULL) \ + r = lockmgr(&(v)->v_lock, (f), &(v)->v_interlock, curproc); \ + else \ + r = 0; \ + } while (0) + +#define LAYERFS_UPPERUNLOCK(v, f, r) do { \ + if ((v)->v_vnlock == NULL) \ + r = lockmgr(&(v)->v_lock, (f) | LK_RELEASE, &(v)->v_interlock, curproc); \ + else \ + r = 0; \ + } while (0) + +#define LAYERFS_UPPERISLOCKED(v, r) do { \ + if ((v)->v_vnlock == NULL) \ + r = lockstatus(&(v)->v_lock); \ + else \ + r = -1; \ + } while (0) + +#define LAYERFS_DO_BYPASS(vp, ap) \ + (*MOUNTTOLAYERMOUNT((vp)->v_mount)->layerm_bypass)((ap)) + +extern struct vnode *layer_checkvp(struct vnode *vp, char *fil, int lno); + +#define MOUNTTOLAYERMOUNT(mp) ((struct layer_mount *)((mp)->mnt_data)) +#define VTOLAYER(vp) ((struct layer_node *)(vp)->v_data) +#define LAYERTOV(xp) ((xp)->layer_vnode) +#ifdef LAYERFS_DIAGNOSTIC +#define LAYERVPTOLOWERVP(vp) layer_checkvp((vp), __FILE__, __LINE__) +#else +#define LAYERVPTOLOWERVP(vp) (VTOLAYER(vp)->layer_lowervp) +#endif + +#endif /* _KERNEL */ +#endif /* _MISCFS_GENFS_LAYER_H_ */ diff -ruN /backup/src.old/sys/miscfs/genfs/layer_extern.h sys/miscfs/genfs/layer_extern.h --- /backup/src.old/sys/miscfs/genfs/layer_extern.h Wed Dec 31 19:00:00 1969 +++ sys/miscfs/genfs/layer_extern.h Mon Dec 9 21:39:15 2002 @@ -0,0 +1,121 @@ +/* $NetBSD: layer_extern.h,v 1.5 2001/12/06 04:29:23 chs Exp $ */ + +/* + * Copyright (c) 1999 National Aeronautics & Space Administration + * All rights reserved. + * + * This software was written by William Studenmund of the + * Numerical Aerospace Simulation Facility, NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the National Aeronautics & Space Administration + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB- + * UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1992, 1993, 1995 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software donated to Berkeley by + * Jan-Simon Pendry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* + * Routines defined by layerfs + */ + +/* misc routines in layer_subr.c */ +int layerfs_init(struct vfsconf *); +void layerfs_done(void); +int layer_node_alloc(struct mount *, struct vnode *, struct vnode **); +int layer_node_create(struct mount *, struct vnode *, struct vnode **); +struct vnode * + layer_node_find(struct mount *, struct vnode *); +#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ +#define LAYER_NHASH(lmp, vp) \ + (&((lmp)->layerm_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & \ + (lmp)->layerm_node_hash])) + +/* vfs routines */ +int layerfs_start(struct mount *, int, struct proc *); +int layerfs_root(struct mount *, struct vnode **); +int layerfs_quotactl(struct mount *, int, uid_t, caddr_t, + struct proc *); +int layerfs_statfs(struct mount *, struct statfs *, struct proc *); +int layerfs_sync(struct mount *, int, struct ucred *, struct proc *); +int layerfs_vget(struct mount *, ino_t, struct vnode **); +int layerfs_fhtovp(struct mount *, struct fid *, struct vnode **); +int layerfs_checkexp(struct mount *, struct mbuf *, int *, + struct ucred **); +int layerfs_vptofh(struct vnode *, struct fid *); +int layerfs_sysctl(int *, u_int, void *, size_t *, void *, size_t, + struct proc *); + +/* VOP routines */ +int layer_bypass(void *); +int layer_getattr(void *); +int layer_inactive(void *); +int layer_reclaim(void *); +int layer_print(void *); +int layer_strategy(void *); +int layer_bwrite(void *); +int layer_bmap(void *); +int layer_lock(void *); +int layer_unlock(void *); +int layer_islocked(void *); +int layer_fsync(void *); +int layer_lookup(void *); +int layer_setattr(void *); +int layer_access(void *); +int layer_open(void *); +int layer_getpages(void *); +int layer_putpages(void *); diff -ruN /backup/src.old/sys/miscfs/genfs/layer_subr.c sys/miscfs/genfs/layer_subr.c --- /backup/src.old/sys/miscfs/genfs/layer_subr.c Wed Dec 31 19:00:00 1969 +++ sys/miscfs/genfs/layer_subr.c Mon Dec 9 21:39:15 2002 @@ -0,0 +1,400 @@ +/* $NetBSD: layer_subr.c,v 1.11 2002/02/20 06:16:22 enami Exp $ */ + +/* + * Copyright (c) 1999 National Aeronautics & Space Administration + * All rights reserved. + * + * This software was written by William Studenmund of the + * Numerical Aerospace Simulation Facility, NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the National Aeronautics & Space Administration + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB- + * UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software donated to Berkeley by + * Jan-Simon Pendry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp + * @(#)null_subr.c 8.7 (Berkeley) 5/14/95 + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NLAYERNODECACHE 16 + +/* + * layer cache: + * Each cache entry holds a reference to the lower vnode + * along with a pointer to the alias vnode. When an + * entry is added the lower vnode is VREF'd. When the + * alias is removed the lower vnode is vrele'd. + */ + +/* + * Initialise cache headers + */ +int +layerfs_init(struct vfsconf *v) +{ +#ifdef LAYERFS_DIAGNOSTIC + printf("layerfs_init\n"); /* printed during system boot */ +#endif + return (0); +} + +/* + * Free global resources of layerfs. + */ +void +layerfs_done() +{ +#ifdef LAYERFS_DIAGNOSTIC + printf("layerfs_done\n"); /* printed on layerfs detach */ +#endif +} + +/* + * Return a locked, VREF'ed alias for lower vnode if already exists, else 0. + */ +struct vnode * +layer_node_find(mp, lowervp) + struct mount *mp; + struct vnode *lowervp; +{ + struct layer_mount *lmp = MOUNTTOLAYERMOUNT(mp); + struct layer_node_hashhead *hd; + struct layer_node *a; + struct vnode *vp; + + /* + * Find hash base, and then search the (two-way) linked + * list looking for a layer_node structure which is referencing + * the lower vnode. If found, the increment the layer_node + * reference count (but NOT the lower vnode's VREF counter) + * and return the vnode locked. + */ + hd = LAYER_NHASH(lmp, lowervp); +loop: + simple_lock(&lmp->layerm_hashlock); + for (a = hd->lh_first; a != 0; a = a->layer_hash.le_next) { + if (a->layer_lowervp == lowervp && LAYERTOV(a)->v_mount == mp) { + vp = LAYERTOV(a); + simple_unlock(&lmp->layerm_hashlock); + /* + * We must be careful here as the fact the lower + * vnode is locked will imply vp is locked unless + * someone has decided to start vclean'ing either + * vp or lowervp. + * + * So we try for an exclusive, recursive lock + * on the upper vnode. If it fails, vcleaning + * is in progress (so when we try again, we'll + * fail). If it succeeds, we now have double + * locked the bottom node. So we do an explicit + * VOP_UNLOCK on it to keep the counts right. Note + * that we will end up with the upper node and + * the lower node locked once. + */ + if (vget(vp, LK_EXCLUSIVE | LK_CANRECURSE, curproc)) { + printf ("layer_node_find: vget failed.\n"); + goto loop; + } + VOP_UNLOCK(lowervp, 0, curproc); + return (vp); + } + } + + simple_unlock(&lmp->layerm_hashlock); + return NULL; +} + + +/* + * Make a new layer_node node. + * Vp is the alias vnode, lowervp is the lower vnode. + * Maintain a reference to lowervp. + */ +int +layer_node_alloc(mp, lowervp, vpp) + struct mount *mp; + struct vnode *lowervp; + struct vnode **vpp; +{ + struct layer_mount *lmp = MOUNTTOLAYERMOUNT(mp); + struct layer_node_hashhead *hd; + struct layer_node *xp; + struct vnode *vp, *nvp; + int error; + extern int (**dead_vnodeop_p)(void *); + + if ((error = getnewvnode(lmp->layerm_tag, mp, lmp->layerm_vnodeop_p, + &vp)) != 0) + return (error); + vp->v_type = lowervp->v_type; + vp->v_flag |= VLAYER; + + xp = malloc(lmp->layerm_size, M_TEMP, M_WAITOK); + if (vp->v_type == VBLK || vp->v_type == VCHR) { + MALLOC(vp->v_specinfo, struct specinfo *, + sizeof(struct specinfo), M_VNODE, M_WAITOK); + vp->v_hashchain = NULL; + vp->v_rdev = lowervp->v_rdev; + } + + vp->v_data = xp; + xp->layer_vnode = vp; + xp->layer_lowervp = lowervp; + xp->layer_flags = 0; + /* + * Before we insert our new node onto the hash chains, + * check to see if someone else has beaten us to it. + * (We could have slept in MALLOC.) + */ + if ((nvp = layer_node_find(mp, lowervp)) != NULL) { + *vpp = nvp; + + /* free the substructures we've allocated. */ + FREE(xp, M_TEMP); + if (vp->v_type == VBLK || vp->v_type == VCHR) + FREE(vp->v_specinfo, M_VNODE); + + vp->v_type = VBAD; /* node is discarded */ + vp->v_op = dead_vnodeop_p; /* so ops will still work */ + vrele(vp); /* get rid of it. */ + return (0); + } + + simple_lock(&lmp->layerm_hashlock); + + /* + * Now lock the new node. We rely on the fact that we were passed + * a locked vnode. If the lower node is exporting a struct lock + * (v_vnlock != NULL) then we just set the upper v_vnlock to the + * lower one, and both are now locked. If the lower node is exporting + * NULL, then we copy that up and manually lock the upper node. + * + * LAYERFS_UPPERLOCK already has the test, so we use it after copying + * up the v_vnlock from below. + */ + + vp->v_vnlock = lowervp->v_vnlock; + LAYERFS_UPPERLOCK(vp, LK_EXCLUSIVE, error); + + if (error) { + /* + * How did we get a locking error? The node just came off + * of the free list, and we're the only routine which + * knows it's there... + */ + vp->v_vnlock = &vp->v_lock; + *vpp = NULL; + + /* free the substructures we've allocated. */ + FREE(xp, M_TEMP); + if (vp->v_type == VBLK || vp->v_type == VCHR) + FREE(vp->v_specinfo, M_VNODE); + + vp->v_type = VBAD; /* node is discarded */ + vp->v_op = dead_vnodeop_p; /* so ops will still work */ + vrele(vp); /* get rid of it. */ + return (error); + } + /* + * NetBSD used to do an inlined checkalias here. We do not, as + * we never flag device nodes as being aliased. The lowervp + * node will, when appropriate, be flaged as an alias. + */ + + *vpp = vp; + VREF(lowervp); /* Take into account reference held in layer_node */ + hd = LAYER_NHASH(lmp, lowervp); + LIST_INSERT_HEAD(hd, xp, layer_hash); + uvm_vnp_setsize(vp, 0); + simple_unlock(&lmp->layerm_hashlock); + return (0); +} + + +/* + * Try to find an existing layer_node vnode refering + * to it, otherwise make a new layer_node vnode which + * contains a reference to the lower vnode. + * + * >>> we assume that the lower node is already locked upon entry, so we + * propagate the lock state to upper node << + */ +int +layer_node_create(mp, lowervp, newvpp) + struct mount *mp; + struct vnode *lowervp; + struct vnode **newvpp; +{ + struct vnode *aliasvp; + struct layer_mount *lmp = MOUNTTOLAYERMOUNT(mp); + + if ((aliasvp = layer_node_find(mp, lowervp)) != NULL) { + /* + * layer_node_find has taken another reference + * to the alias vnode and moved the lock holding to + * aliasvp + */ +#ifdef LAYERFS_DIAGNOSTIC + vprint("layer_node_create: exists", aliasvp); +#endif + } else { + int error; + + /* + * Get new vnode. + */ +#ifdef LAYERFS_DIAGNOSTIC + printf("layer_node_create: create new alias vnode\n"); +#endif + + /* + * Make new vnode reference the layer_node. + */ + if ((error = (lmp->layerm_alloc)(mp, lowervp, &aliasvp)) != 0) + return error; + + /* + * aliasvp is already VREF'd by getnewvnode() + */ + } + + /* + * Now that we have VREF'd the upper vnode, release the reference + * to the lower node. The existance of the layer_node retains one + * reference to the lower node. + */ + vrele(lowervp); + +#ifdef DIAGNOSTIC + if (lowervp->v_usecount < 1) { + /* Should never happen... */ + vprint("layer_node_create: alias", aliasvp); + vprint("layer_node_create: lower", lowervp); + panic("layer_node_create: lower has 0 usecount."); + } +#endif + +#ifdef LAYERFS_DIAGNOSTIC + vprint("layer_node_create: alias", aliasvp); +#endif + *newvpp = aliasvp; + return (0); +} + +struct vnode * +layer_checkvp(vp, fil, lno) + struct vnode *vp; + char *fil; + int lno; +{ + struct layer_node *a = VTOLAYER(vp); +#ifdef notyet + /* + * Can't do this check because vop_reclaim runs + * with a funny vop vector. + * + * WRS - no it doesnt... + */ + if (vp->v_op != layer_vnodeop_p) { + printf ("layer_checkvp: on non-layer-node\n"); +#ifdef notyet + while (layer_checkvp_barrier) /*WAIT*/ ; +#endif + panic("layer_checkvp"); + } +#endif + if (a->layer_lowervp == NULL) { + /* Should never happen */ + int i; u_long *p; + printf("vp = %p, ZERO ptr\n", vp); + for (p = (u_long *) a, i = 0; i < 8; i++) + printf(" %lx", p[i]); + printf("\n"); + /* wait for debugger */ + panic("layer_checkvp"); + } + if (a->layer_lowervp->v_usecount < 1) { + int i; u_long *p; + printf("vp = %p, unref'ed lowervp\n", vp); + for (p = (u_long *) a, i = 0; i < 8; i++) + printf(" %lx", p[i]); + printf("\n"); + /* wait for debugger */ + panic ("layer with unref'ed lowervp"); + } +#ifdef notnow + printf("layer %p/%d -> %p/%d [%s, %d]\n", + LAYERTOV(a), LAYERTOV(a)->v_usecount, + a->layer_lowervp, a->layer_lowervp->v_usecount, + fil, lno); +#endif + return a->layer_lowervp; +} diff -ruN /backup/src.old/sys/miscfs/genfs/layer_vfsops.c sys/miscfs/genfs/layer_vfsops.c --- /backup/src.old/sys/miscfs/genfs/layer_vfsops.c Wed Dec 31 19:00:00 1969 +++ sys/miscfs/genfs/layer_vfsops.c Mon Dec 9 21:39:15 2002 @@ -0,0 +1,284 @@ +/* $NetBSD: layer_vfsops.c,v 1.5 2001/11/15 09:48:21 lukem Exp $ */ + +/* + * Copyright (c) 1999 National Aeronautics & Space Administration + * All rights reserved. + * + * This software was written by William Studenmund of the + * Numerical Aerospace Simulation Facility, NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the National Aeronautics & Space Administration + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB- + * UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1992, 1993, 1995 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software donated to Berkeley by + * Jan-Simon Pendry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp + * from: @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 + * @(#)null_vfsops.c 8.7 (Berkeley) 5/14/95 + */ + +/* + * generic layer vfs ops. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * VFS start. Nothing needed here - the start routine + * on the underlying filesystem will have been called + * when that filesystem was mounted. + */ +int +layerfs_start(mp, flags, p) + struct mount *mp; + int flags; + struct proc *p; +{ + + return (0); + /* return VFS_START(MOUNTTOLAYERMOUNT(mp)->layerm_vfs, flags, p); */ +} + +int +layerfs_root(mp, vpp) + struct mount *mp; + struct vnode **vpp; +{ + struct vnode *vp; + +#ifdef LAYERFS_DIAGNOSTIC + printf("layerfs_root(mp = %p, vp = %p->%p)\n", mp, + MOUNTTOLAYERMOUNT(mp)->layerm_rootvp, + LAYERVPTOLOWERVP(MOUNTTOLAYERMOUNT(mp)->layerm_rootvp)); +#endif + + /* + * Return locked reference to root. + */ + vp = MOUNTTOLAYERMOUNT(mp)->layerm_rootvp; + if (vp == NULL) { + *vpp = NULL; + return (EINVAL); + } + VREF(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curproc); + *vpp = vp; + return 0; +} + +int +layerfs_quotactl(mp, cmd, uid, arg, p) + struct mount *mp; + int cmd; + uid_t uid; + caddr_t arg; + struct proc *p; +{ + + return VFS_QUOTACTL(MOUNTTOLAYERMOUNT(mp)->layerm_vfs, + cmd, uid, arg, p); +} + +int +layerfs_statfs(mp, sbp, p) + struct mount *mp; + struct statfs *sbp; + struct proc *p; +{ + int error; + struct statfs mstat; + +#ifdef LAYERFS_DIAGNOSTIC + printf("layerfs_statfs(mp = %p, vp = %p->%p)\n", mp, + MOUNTTOLAYERMOUNT(mp)->layerm_rootvp, + LAYERVPTOLOWERVP(MOUNTTOLAYERMOUNT(mp)->layerm_rootvp)); +#endif + + memset(&mstat, 0, sizeof(mstat)); + + error = VFS_STATFS(MOUNTTOLAYERMOUNT(mp)->layerm_vfs, &mstat, p); + if (error) + return (error); + + /* now copy across the "interesting" information and fake the rest */ + sbp->f_flags = mstat.f_flags; + sbp->f_bsize = mstat.f_bsize; + sbp->f_iosize = mstat.f_iosize; + sbp->f_blocks = mstat.f_blocks; + sbp->f_bfree = mstat.f_bfree; + sbp->f_bavail = mstat.f_bavail; + sbp->f_files = mstat.f_files; + sbp->f_ffree = mstat.f_ffree; + if (sbp != &mp->mnt_stat) { + memcpy(&sbp->f_fsid, &mp->mnt_stat.f_fsid, sizeof(sbp->f_fsid)); + memcpy(sbp->f_mntonname, mp->mnt_stat.f_mntonname, MNAMELEN); + memcpy(sbp->f_mntfromname, mp->mnt_stat.f_mntfromname, MNAMELEN); + } + strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); + return (0); +} + +int +layerfs_sync(mp, waitfor, cred, p) + struct mount *mp; + int waitfor; + struct ucred *cred; + struct proc *p; +{ + + /* + * XXX - Assumes no data cached at layer. + */ + return (0); +} + +int +layerfs_vget(mp, ino, vpp) + struct mount *mp; + ino_t ino; + struct vnode **vpp; +{ + int error; + struct vnode *vp; + + if ((error = VFS_VGET(MOUNTTOLAYERMOUNT(mp)->layerm_vfs, ino, &vp))) { + *vpp = NULL; + return (error); + } + if ((error = layer_node_create(mp, vp, vpp))) { + vput(vp); + *vpp = NULL; + return (error); + } + + return (0); +} + +int +layerfs_fhtovp(mp, fidp, vpp) + struct mount *mp; + struct fid *fidp; + struct vnode **vpp; +{ + int error; + struct vnode *vp; + + if ((error = VFS_FHTOVP(MOUNTTOLAYERMOUNT(mp)->layerm_vfs, fidp, &vp))) + return (error); + + if ((error = layer_node_create(mp, vp, vpp))) { + vput(vp); + *vpp = NULL; + return (error); + } + + return (0); +} + +int +layerfs_checkexp(mp, nam, exflagsp, credanonp) + struct mount *mp; + struct mbuf *nam; + int *exflagsp; + struct ucred**credanonp; +{ + struct netcred *np; + struct layer_mount *lmp = MOUNTTOLAYERMOUNT(mp); + + /* + * get the export permission structure for this tuple. + */ + if ((np = vfs_export_lookup(mp, &lmp->layerm_export, nam)) == NULL) + return (EACCES); + + *exflagsp = np->netc_exflags; + *credanonp = &np->netc_anon; + return (0); +} + +int +layerfs_vptofh(vp, fhp) + struct vnode *vp; + struct fid *fhp; +{ + + return (VFS_VPTOFH(LAYERVPTOLOWERVP(vp), fhp)); +} + +int +layerfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; + struct proc *p; +{ + return (EOPNOTSUPP); +} diff -ruN /backup/src.old/sys/miscfs/genfs/layer_vnops.c sys/miscfs/genfs/layer_vnops.c --- /backup/src.old/sys/miscfs/genfs/layer_vnops.c Wed Dec 31 19:00:00 1969 +++ sys/miscfs/genfs/layer_vnops.c Mon Dec 9 21:39:15 2002 @@ -0,0 +1,942 @@ +/* $NetBSD: layer_vnops.c,v 1.10 2001/12/06 04:29:23 chs Exp $ */ + +/* + * Copyright (c) 1999 National Aeronautics & Space Administration + * All rights reserved. + * + * This software was written by William Studenmund of the + * Numerical Aerospace Simulation Facility, NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the National Aeronautics & Space Administration + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB- + * UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * John Heidemann of the UCLA Ficus project. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)null_vnops.c 8.6 (Berkeley) 5/27/95 + * + * Ancestors: + * @(#)lofs_vnops.c 1.2 (Berkeley) 6/18/92 + * $Id: layer_vnops.c,v 1.10 2001/12/06 04:29:23 chs Exp $ + * ...and... + * @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project + */ + +/* + * Null Layer vnode routines. + * + * (See mount_null(8) for more information.) + * + * The layer.h, layer_extern.h, layer_vfs.c, and layer_vnops.c files provide + * the core implimentation of the null file system and most other stacked + * fs's. The description below refers to the null file system, but the + * services provided by the layer* files are useful for all layered fs's. + * + * The null layer duplicates a portion of the file system + * name space under a new name. In this respect, it is + * similar to the loopback file system. It differs from + * the loopback fs in two respects: it is implemented using + * a stackable layers techniques, and it's "null-node"s stack above + * all lower-layer vnodes, not just over directory vnodes. + * + * The null layer has two purposes. First, it serves as a demonstration + * of layering by proving a layer which does nothing. (It actually + * does everything the loopback file system does, which is slightly + * more than nothing.) Second, the null layer can serve as a prototype + * layer. Since it provides all necessary layer framework, + * new file system layers can be created very easily be starting + * with a null layer. + * + * The remainder of the man page examines the null layer as a basis + * for constructing new layers. + * + * + * INSTANTIATING NEW NULL LAYERS + * + * New null layers are created with mount_null(8). + * Mount_null(8) takes two arguments, the pathname + * of the lower vfs (target-pn) and the pathname where the null + * layer will appear in the namespace (alias-pn). After + * the null layer is put into place, the contents + * of target-pn subtree will be aliased under alias-pn. + * + * It is conceivable that other overlay filesystems will take different + * parameters. For instance, data migration or access controll layers might + * only take one pathname which will serve both as the target-pn and + * alias-pn described above. + * + * + * OPERATION OF A NULL LAYER + * + * The null layer is the minimum file system layer, + * simply bypassing all possible operations to the lower layer + * for processing there. The majority of its activity centers + * on the bypass routine, though which nearly all vnode operations + * pass. + * + * The bypass routine accepts arbitrary vnode operations for + * handling by the lower layer. It begins by examing vnode + * operation arguments and replacing any layered nodes by their + * lower-layer equivlants. It then invokes the operation + * on the lower layer. Finally, it replaces the layered nodes + * in the arguments and, if a vnode is return by the operation, + * stacks a layered node on top of the returned vnode. + * + * The bypass routine in this file, layer_bypass(), is suitable for use + * by many different layered filesystems. It can be used by multiple + * filesystems simultaneously. Alternatively, a layered fs may provide + * its own bypass routine, in which case layer_bypass() should be used as + * a model. For instance, the main functionality provided by umapfs, the user + * identity mapping file system, is handled by a custom bypass routine. + * + * Typically a layered fs registers its selected bypass routine as the + * default vnode operation in its vnodeopv_entry_desc table. Additionally + * the filesystem must store the bypass entry point in the layerm_bypass + * field of struct layer_mount. All other layer routines in this file will + * use the layerm_bypass routine. + * + * Although the bypass routine handles most operations outright, a number + * of operations are special cased, and handled by the layered fs. One + * group, layer_setattr, layer_getattr, layer_access, layer_open, and + * layer_fsync, perform layer-specific manipulation in addition to calling + * the bypass routine. The other group + + * Although bypass handles most operations, vop_getattr, vop_lock, + * vop_unlock, vop_inactive, vop_reclaim, and vop_print are not + * bypassed. Vop_getattr must change the fsid being returned. + * Vop_lock and vop_unlock must handle any locking for the + * current vnode as well as pass the lock request down. + * Vop_inactive and vop_reclaim are not bypassed so that + * they can handle freeing null-layer specific data. Vop_print + * is not bypassed to avoid excessive debugging information. + * Also, certain vnode operations change the locking state within + * the operation (create, mknod, remove, link, rename, mkdir, rmdir, + * and symlink). Ideally these operations should not change the + * lock state, but should be changed to let the caller of the + * function unlock them. Otherwise all intermediate vnode layers + * (such as union, umapfs, etc) must catch these functions to do + * the necessary locking at their layer. + * + * + * INSTANTIATING VNODE STACKS + * + * Mounting associates the null layer with a lower layer, + * effect stacking two VFSes. Vnode stacks are instead + * created on demand as files are accessed. + * + * The initial mount creates a single vnode stack for the + * root of the new null layer. All other vnode stacks + * are created as a result of vnode operations on + * this or other null vnode stacks. + * + * New vnode stacks come into existance as a result of + * an operation which returns a vnode. + * The bypass routine stacks a null-node above the new + * vnode before returning it to the caller. + * + * For example, imagine mounting a null layer with + * "mount_null /usr/include /dev/layer/null". + * Changing directory to /dev/layer/null will assign + * the root null-node (which was created when the null layer was mounted). + * Now consider opening "sys". A vop_lookup would be + * done on the root null-node. This operation would bypass through + * to the lower layer which would return a vnode representing + * the UFS "sys". layer_bypass then builds a null-node + * aliasing the UFS "sys" and returns this to the caller. + * Later operations on the null-node "sys" will repeat this + * process when constructing other vnode stacks. + * + * + * CREATING OTHER FILE SYSTEM LAYERS + * + * One of the easiest ways to construct new file system layers is to make + * a copy of the null layer, rename all files and variables, and + * then begin modifing the copy. Sed can be used to easily rename + * all variables. + * + * The umap layer is an example of a layer descended from the + * null layer. + * + * + * INVOKING OPERATIONS ON LOWER LAYERS + * + * There are two techniques to invoke operations on a lower layer + * when the operation cannot be completely bypassed. Each method + * is appropriate in different situations. In both cases, + * it is the responsibility of the aliasing layer to make + * the operation arguments "correct" for the lower layer + * by mapping an vnode arguments to the lower layer. + * + * The first approach is to call the aliasing layer's bypass routine. + * This method is most suitable when you wish to invoke the operation + * currently being hanldled on the lower layer. It has the advantage + * that the bypass routine already must do argument mapping. + * An example of this is null_getattrs in the null layer. + * + * A second approach is to directly invoked vnode operations on + * the lower layer with the VOP_OPERATIONNAME interface. + * The advantage of this method is that it is easy to invoke + * arbitrary operations on the lower layer. The disadvantage + * is that vnodes arguments must be manualy mapped. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * This is the 08-June-99 bypass routine, based on the 10-Apr-92 bypass + * routine by John Heidemann. + * The new element for this version is that the whole nullfs + * system gained the concept of locks on the lower node, and locks on + * our nodes. When returning from a call to the lower layer, we may + * need to update lock state ONLY on our layer. The LAYERFS_UPPER*LOCK() + * macros provide this functionality. + * The 10-Apr-92 version was optimized for speed, throwing away some + * safety checks. It should still always work, but it's not as + * robust to programmer errors. + * Define SAFETY to include some error checking code. + * + * In general, we map all vnodes going down and unmap them on the way back. + * + * Also, some BSD vnode operations have the side effect of vrele'ing + * their arguments. With stacking, the reference counts are held + * by the upper node, not the lower one, so we must handle these + * side-effects here. This is not of concern in Sun-derived systems + * since there are no such side-effects. + * + * New for the 08-June-99 version: we also handle operations which unlock + * the passed-in node (typically they vput the node). + * + * This makes the following assumptions: + * - only one returned vpp + * - no INOUT vpp's (Sun's vop_open has one of these) + * - the vnode operation vector of the first vnode should be used + * to determine what implementation of the op should be invoked + * - all mapped vnodes are of our vnode-type (NEEDSWORK: + * problems on rmdir'ing mount points and renaming?) + */ +int +layer_bypass(v) + void *v; +{ + struct vop_generic_args /* { + struct vnodeop_desc *a_desc; + + } */ *ap = v; + int (**our_vnodeop_p)(void *); + struct vnode **this_vp_p; + int error, error1; + struct vnode *old_vps[VDESC_MAX_VPS], *vp0; + struct vnode **vps_p[VDESC_MAX_VPS]; + struct vnode ***vppp; + struct vnodeop_desc *descp = ap->a_desc; + int reles, i, flags; + +#ifdef SAFETY + /* + * We require at least one vp. + */ + if (descp->vdesc_vp_offsets == NULL || + descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET) + panic ("layer_bypass: no vp's in map.\n"); +#endif + + vps_p[0] = VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[0],ap); + vp0 = *vps_p[0]; + flags = MOUNTTOLAYERMOUNT(vp0->v_mount)->layerm_flags; + our_vnodeop_p = vp0->v_op; + + if (flags & LAYERFS_MBYPASSDEBUG) + printf ("layer_bypass: %s\n", descp->vdesc_name); + + /* + * Map the vnodes going in. + * Later, we'll invoke the operation based on + * the first mapped vnode's operation vector. + */ + reles = descp->vdesc_flags; + for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { + if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) + break; /* bail out at end of list */ + vps_p[i] = this_vp_p = + VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap); + /* + * We're not guaranteed that any but the first vnode + * are of our type. Check for and don't map any + * that aren't. (We must always map first vp or vclean fails.) + */ + if (i && (*this_vp_p == NULL || + (*this_vp_p)->v_op != our_vnodeop_p)) { + old_vps[i] = NULL; + } else { + old_vps[i] = *this_vp_p; + *(vps_p[i]) = LAYERVPTOLOWERVP(*this_vp_p); + /* + * XXX - Several operations have the side effect + * of vrele'ing their vp's. We must account for + * that. (This should go away in the future.) + */ + if (reles & VDESC_VP0_WILLRELE) + VREF(*this_vp_p); + } + + } + + /* + * Call the operation on the lower layer + * with the modified argument structure. + */ + error = VCALL(*vps_p[0], descp->vdesc_offset, ap); + + /* + * Maintain the illusion of call-by-value + * by restoring vnodes in the argument structure + * to their original value. + */ + reles = descp->vdesc_flags; + for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { + if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) + break; /* bail out at end of list */ + if (old_vps[i]) { + *(vps_p[i]) = old_vps[i]; + if (reles & VDESC_VP0_WILLUNLOCK) + LAYERFS_UPPERUNLOCK(*(vps_p[i]), 0, error1); + if (reles & VDESC_VP0_WILLRELE) + vrele(*(vps_p[i])); + } + } + + /* + * Map the possible out-going vpp + * (Assumes that the lower layer always returns + * a VREF'ed vpp unless it gets an error.) + */ + if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET && + !(descp->vdesc_flags & VDESC_NOMAP_VPP) && + !error) { + /* + * XXX - even though some ops have vpp returned vp's, + * several ops actually vrele this before returning. + * We must avoid these ops. + * (This should go away when these ops are regularized.) + */ + if (descp->vdesc_flags & VDESC_VPP_WILLRELE) + goto out; + vppp = VOPARG_OFFSETTO(struct vnode***, + descp->vdesc_vpp_offset,ap); + /* + * Only vop_lookup, vop_create, vop_makedir, vop_bmap, + * vop_mknod, and vop_symlink return vpp's. vop_bmap + * doesn't call bypass as the lower vpp is fine (we're just + * going to do i/o on it). vop_loookup doesn't call bypass + * as a lookup on "." would generate a locking error. + * So all the calls which get us here have a locked vpp. :-) + */ + error = layer_node_create(old_vps[0]->v_mount, **vppp, *vppp); + } + + out: + return (error); +} + +/* + * We have to carry on the locking protocol on the layer vnodes + * as we progress through the tree. We also have to enforce read-only + * if this layer is mounted read-only. + */ +int +layer_lookup(v) + void *v; +{ + struct vop_lookup_args /* { + struct vnodeop_desc *a_desc; + struct vnode * a_dvp; + struct vnode ** a_vpp; + struct componentname * a_cnp; + } */ *ap = v; + struct componentname *cnp = ap->a_cnp; + int flags = cnp->cn_flags; + struct vnode *dvp, *vp, *ldvp; + int error, r; + + dvp = ap->a_dvp; + + if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && + (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) + return (EROFS); + + ldvp = LAYERVPTOLOWERVP(dvp); + ap->a_dvp = ldvp; + error = VCALL(ldvp, ap->a_desc->vdesc_offset, ap); + vp = *ap->a_vpp; + + if (error == EJUSTRETURN && (flags & ISLASTCN) && + (dvp->v_mount->mnt_flag & MNT_RDONLY) && + (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)) + error = EROFS; + /* + * We must do the same locking and unlocking at this layer as + * is done in the layers below us. It used to be we would try + * to guess based on what was set with the flags and error codes. + * + * But that doesn't work. So now we have the underlying VOP_LOOKUP + * tell us if it released the parent vnode, and we adjust the + * upper node accordingly. We can't just look at the lock states + * of the lower nodes as someone else might have come along and + * locked the parent node after our call to VOP_LOOKUP locked it. + */ + if ((cnp->cn_flags & PDIRUNLOCK)) { + LAYERFS_UPPERUNLOCK(dvp, 0, r); + } + if (ldvp == vp) { + /* + * Did lookup on "." or ".." in the root node of a mount point. + * So we return dvp after a VREF. + */ + *ap->a_vpp = dvp; + VREF(dvp); + vrele(vp); + } else if (vp != NULL) { + error = layer_node_create(dvp->v_mount, vp, ap->a_vpp); + } + return (error); +} + +/* + * Setattr call. Disallow write attempts if the layer is mounted read-only. + */ +int +layer_setattr(v) + void *v; +{ + struct vop_setattr_args /* { + struct vnodeop_desc *a_desc; + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + struct vattr *vap = ap->a_vap; + + if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || + vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || + vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) && + (vp->v_mount->mnt_flag & MNT_RDONLY)) + return (EROFS); + if (vap->va_size != VNOVAL) { + switch (vp->v_type) { + case VDIR: + return (EISDIR); + case VCHR: + case VBLK: + case VSOCK: + case VFIFO: + return (0); + case VREG: + case VLNK: + default: + /* + * Disallow write attempts if the filesystem is + * mounted read-only. + */ + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + } + } + return (LAYERFS_DO_BYPASS(vp, ap)); +} + +/* + * We handle getattr only to change the fsid. + */ +int +layer_getattr(v) + void *v; +{ + struct vop_getattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + int error; + + if ((error = LAYERFS_DO_BYPASS(vp, ap)) != 0) + return (error); + /* Requires that arguments be restored. */ + ap->a_vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; + return (0); +} + +int +layer_access(v) + void *v; +{ + struct vop_access_args /* { + struct vnode *a_vp; + int a_mode; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + mode_t mode = ap->a_mode; + + /* + * Disallow write attempts on read-only layers; + * unless the file is a socket, fifo, or a block or + * character device resident on the file system. + */ + if (mode & VWRITE) { + switch (vp->v_type) { + case VDIR: + case VLNK: + case VREG: + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + break; + default: + break; + } + } + return (LAYERFS_DO_BYPASS(vp, ap)); +} + +/* + * We must handle open to be able to catch MNT_NODEV and friends. + */ +int +layer_open(v) + void *v; +{ + struct vop_open_args *ap = v; + struct vnode *vp = ap->a_vp; + enum vtype lower_type = LAYERVPTOLOWERVP(vp)->v_type; + + if (((lower_type == VBLK) || (lower_type == VCHR)) && + (vp->v_mount->mnt_flag & MNT_NODEV)) + return ENXIO; + + return LAYERFS_DO_BYPASS(vp, ap); +} + +/* + * We need to process our own vnode lock and then clear the + * interlock flag as it applies only to our vnode, not the + * vnodes below us on the stack. + */ +int +layer_lock(v) + void *v; +{ + struct vop_lock_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap = v; + struct vnode *vp = ap->a_vp, *lowervp; + int flags = ap->a_flags, error; + struct proc *p = ap->a_p; + + if (vp->v_vnlock != NULL) { + /* + * The lower level has exported a struct lock to us. Use + * it so that all vnodes in the stack lock and unlock + * simultaneously. Note: we don't DRAIN the lock as DRAIN + * decommissions the lock - just because our vnode is + * going away doesn't mean the struct lock below us is. + * LK_EXCLUSIVE is fine. + */ + if ((flags & LK_TYPE_MASK) == LK_DRAIN) { + return(lockmgr(vp->v_vnlock, + (flags & ~LK_TYPE_MASK) | LK_EXCLUSIVE, + &vp->v_interlock, p)); + } else + return(lockmgr(vp->v_vnlock, flags, &vp->v_interlock, p)); + } else { + /* + * Ahh well. It would be nice if the fs we're over would + * export a struct lock for us to use, but it doesn't. + * + * To prevent race conditions involving doing a lookup + * on "..", we have to lock the lower node, then lock our + * node. Most of the time it won't matter that we lock our + * node (as any locking would need the lower one locked + * first). But we can LK_DRAIN the upper lock as a step + * towards decomissioning it. + */ + lowervp = LAYERVPTOLOWERVP(vp); + if (flags & LK_INTERLOCK) { + simple_unlock(&vp->v_interlock); + flags &= ~LK_INTERLOCK; + } + if ((flags & LK_TYPE_MASK) == LK_DRAIN) { + error = VOP_LOCK(lowervp, + (flags & ~LK_TYPE_MASK) | LK_EXCLUSIVE, p); + } else + error = VOP_LOCK(lowervp, flags, p); + if (error) + return (error); + if ((error = lockmgr(&vp->v_lock, flags, &vp->v_interlock, p))) { + VOP_UNLOCK(lowervp, 0, p); + } + return (error); + } +} + +/* + */ +int +layer_unlock(v) + void *v; +{ + struct vop_unlock_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + int flags = ap->a_flags; + struct proc *p = ap->a_p; + + if (vp->v_vnlock != NULL) { + return (lockmgr(vp->v_vnlock, ap->a_flags | LK_RELEASE, + &vp->v_interlock, p)); + } else { + if (flags & LK_INTERLOCK) { + simple_unlock(&vp->v_interlock); + flags &= ~LK_INTERLOCK; + } + VOP_UNLOCK(LAYERVPTOLOWERVP(vp), flags, p); + return (lockmgr(&vp->v_lock, ap->a_flags | LK_RELEASE, + &vp->v_interlock, p)); + } +} + +/* + * As long as genfs_nolock is in use, don't call VOP_ISLOCKED(lowervp) + * if vp->v_vnlock == NULL as genfs_noislocked will always report 0. + */ +int +layer_islocked(v) + void *v; +{ + struct vop_islocked_args /* { + struct vnode *a_vp; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + + if (vp->v_vnlock != NULL) + return (lockstatus(vp->v_vnlock)); + else + return (lockstatus(&vp->v_lock)); +} + +/* + * If vinvalbuf is calling us, it's a "shallow fsync" -- don't bother + * syncing the underlying vnodes, since they'll be fsync'ed when + * reclaimed; otherwise, + * pass it through to the underlying layer. + * + * XXX Do we still need to worry about shallow fsync? + */ + +int +layer_fsync(v) + void *v; +{ + struct vop_fsync_args /* { + struct vnode *a_vp; + struct ucred *a_cred; + int a_flags; + off_t offlo; + off_t offhi; + struct proc *a_p; + } */ *ap = v; + + return (LAYERFS_DO_BYPASS(ap->a_vp, ap)); +} + + +int +layer_inactive(v) + void *v; +{ + struct vop_inactive_args /* { + struct vnode *a_vp; + struct proc *a_p; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + struct proc *p = ap->a_p; + + /* + * Do nothing (and _don't_ bypass). + * Wait to vrele lowervp until reclaim, + * so that until then our layer_node is in the + * cache and reusable. + * + * NEEDSWORK: Someday, consider inactive'ing + * the lowervp and then trying to reactivate it + * with capabilities (v_id) + * like they do in the name lookup cache code. + * That's too much work for now. + */ + VOP_UNLOCK(vp, 0, p); + + /* ..., but don't cache the device node. */ + if (vp->v_type == VBLK || vp->v_type == VCHR) + vgone(vp); + return (0); +} + +int +layer_reclaim(v) + void *v; +{ + struct vop_reclaim_args /* { + struct vnode *a_vp; + struct proc *a_p; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + struct layer_mount *lmp = MOUNTTOLAYERMOUNT(vp->v_mount); + struct layer_node *xp = VTOLAYER(vp); + struct vnode *lowervp = xp->layer_lowervp; + + /* + * Note: in vop_reclaim, the node's struct lock has been + * decomissioned, so we have to be careful about calling + * VOP's on ourself. Even if we turned a LK_DRAIN into an + * LK_EXCLUSIVE in layer_lock, we still must be careful as VXLOCK is + * set. + */ + /* After this assignment, this node will not be re-used. */ + if ((vp == lmp->layerm_rootvp)) { + /* + * Oops! We no longer have a root node. Most likely reason is + * that someone forcably unmunted the underlying fs. + * + * Now getting the root vnode will fail. We're dead. :-( + */ + lmp->layerm_rootvp = NULL; + } + xp->layer_lowervp = NULL; + simple_lock(&lmp->layerm_hashlock); + LIST_REMOVE(xp, layer_hash); + simple_unlock(&lmp->layerm_hashlock); + FREE(vp->v_data, M_TEMP); + vp->v_data = NULL; + vrele (lowervp); + return (0); +} + +/* + * We just feed the returned vnode up to the caller - there's no need + * to build a layer node on top of the node on which we're going to do + * i/o. :-) + */ +int +layer_bmap(v) + void *v; +{ + struct vop_bmap_args /* { + struct vnode *a_vp; + daddr_t a_bn; + struct vnode **a_vpp; + daddr_t *a_bnp; + int *a_runp; + } */ *ap = v; + struct vnode *vp; + + ap->a_vp = vp = LAYERVPTOLOWERVP(ap->a_vp); + + return (VCALL(vp, ap->a_desc->vdesc_offset, ap)); +} + +int +layer_print(v) + void *v; +{ + struct vop_print_args /* { + struct vnode *a_vp; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + printf ("\ttag VT_LAYERFS, vp=%p, lowervp=%p\n", vp, LAYERVPTOLOWERVP(vp)); + return (0); +} + +/* + * XXX - vop_strategy must be hand coded because it has no + * vnode in its arguments. + * This goes away with a merged VM/buffer cache. + */ +int +layer_strategy(v) + void *v; +{ + struct vop_strategy_args /* { + struct buf *a_bp; + } */ *ap = v; + struct buf *bp = ap->a_bp; + int error; + struct vnode *savedvp; + + savedvp = bp->b_vp; + bp->b_vp = LAYERVPTOLOWERVP(bp->b_vp); + + error = VOP_STRATEGY(bp); + + bp->b_vp = savedvp; + + return (error); +} + +/* + * XXX - like vop_strategy, vop_bwrite must be hand coded because it has no + * vnode in its arguments. + * This goes away with a merged VM/buffer cache. + */ +int +layer_bwrite(v) + void *v; +{ + struct vop_bwrite_args /* { + struct buf *a_bp; + } */ *ap = v; + struct buf *bp = ap->a_bp; + int error; + struct vnode *savedvp; + + savedvp = bp->b_vp; + bp->b_vp = LAYERVPTOLOWERVP(bp->b_vp); + + error = VOP_BWRITE(bp); + + bp->b_vp = savedvp; + + return (error); +} + +#if 0 +int +layer_getpages(v) + void *v; +{ + struct vop_getpages_args /* { + struct vnode *a_vp; + voff_t a_offset; + struct vm_page **a_m; + int *a_count; + int a_centeridx; + vm_prot_t a_access_type; + int a_advice; + int a_flags; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + int error; + + /* + * just pass the request on to the underlying layer. + */ + + if (ap->a_flags & PGO_LOCKED) { + return EBUSY; + } + ap->a_vp = LAYERVPTOLOWERVP(vp); + simple_unlock(&vp->v_interlock); + simple_lock(&ap->a_vp->v_interlock); + error = VCALL(ap->a_vp, VOFFSET(vop_getpages), ap); + return error; +} + +int +layer_putpages(v) + void *v; +{ + struct vop_putpages_args /* { + struct vnode *a_vp; + voff_t a_offlo; + voff_t a_offhi; + int a_flags; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + int error; + + /* + * just pass the request on to the underlying layer. + */ + + ap->a_vp = LAYERVPTOLOWERVP(vp); + simple_unlock(&vp->v_interlock); + simple_lock(&ap->a_vp->v_interlock); + error = VCALL(ap->a_vp, VOFFSET(vop_putpages), ap); + return error; +} +#endif diff -ruN /backup/src.old/sys/miscfs/kernfs/kernfs_vnops.c sys/miscfs/kernfs/kernfs_vnops.c --- /backup/src.old/sys/miscfs/kernfs/kernfs_vnops.c Mon Dec 9 21:34:20 2002 +++ sys/miscfs/kernfs/kernfs_vnops.c Mon Dec 9 21:39:15 2002 @@ -162,7 +162,6 @@ int kernfs_xread(struct kern_target *, int, char **, int); int kernfs_xwrite(struct kern_target *, char *, int); -int kernfs_freevp(struct vnode *, struct proc *); int (**kernfs_vnodeop_p)(void *); struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = { @@ -279,20 +278,6 @@ return(error); } -int -kernfs_freevp(vp, p) - struct vnode *vp; - struct proc *p; -{ - struct kernfs_node *kf = VTOKERN(vp); - - TAILQ_REMOVE(&kfshead, kf, list); - VOP_UNLOCK(vp, 0, p); - FREE(vp->v_data, M_TEMP); - vp->v_data = 0; - return(0); -} - struct kern_target * kernfs_findtarget(name, namlen) char *name; @@ -488,29 +473,32 @@ struct kern_target *kt; struct vnode *vp; int error; + int wantpunlock; #ifdef KERNFS_DIAGNOSTIC printf("kernfs_lookup(%p)\n", ap); printf("kernfs_lookup(dp = %p, vpp = %p, cnp = %p)\n", dvp, vpp, ap->a_cnp); printf("kernfs_lookup(%s)\n", pname); #endif - VOP_UNLOCK(dvp, 0, p); *vpp = NULLVP; + cnp->cn_flags &= ~PDIRUNLOCK; - if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) + if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { + /* dvp should be locked on error (regardless of cnp flags) */ return (EROFS); + } if (cnp->cn_namelen == 1 && *pname == '.') { *vpp = dvp; VREF(dvp); - vn_lock(dvp, LK_SHARED | LK_RETRY, p); return (0); } + wantpunlock = (~cnp->cn_flags & (LOCKPARENT | ISLASTCN)); + kt = kernfs_findtarget(pname, cnp->cn_namelen); if (kt == NULL) { /* not found */ - vn_lock(dvp, LK_SHARED | LK_RETRY, p); return(cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); } @@ -524,16 +512,27 @@ *vpp = vp; if (vget(vp, LK_EXCLUSIVE, p)) goto loop; + if (wantpunlock) { + VOP_UNLOCK(dvp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } return(0); } if ((error = kernfs_allocvp(kt, dvp->v_mount, vpp)) != 0) { - vn_lock(dvp, LK_SHARED | LK_RETRY, p); + if (wantpunlock) { + VOP_UNLOCK(dvp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } return(error); } - vn_lock(*vpp, LK_SHARED | LK_RETRY, p); + vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, p); + if (wantpunlock) { + VOP_UNLOCK(dvp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } return(error); } @@ -818,15 +817,18 @@ struct vnode *a_vp; } */ *ap = v; struct vnode *vp = ap->a_vp; - struct proc *p = curproc; -#ifdef KERNFS_DIAGNOSTIC - struct kernfs_node *kf; - - kf = VTOKERN(vp); + struct kernfs_node *kf = VTOKERN(vp); +#ifdef KERNFS_DIAGNOSTIC printf("kernfs_reclaim(%p) %s\n", vp, kf->kf_name); #endif - return(kernfs_freevp(vp, p)); + + TAILQ_REMOVE(&kfshead, kf, list); + if (vp->v_data) { + FREE(vp->v_data, M_TEMP); + vp->v_data = 0; + } + return(0); } /* diff -ruN /backup/src.old/sys/miscfs/nullfs/null.h sys/miscfs/nullfs/null.h --- /backup/src.old/sys/miscfs/nullfs/null.h Mon Dec 9 21:34:21 2002 +++ sys/miscfs/nullfs/null.h Mon Dec 9 21:39:16 2002 @@ -1,5 +1,37 @@ -/* $OpenBSD: null.h,v 1.11 2002/03/14 01:27:08 millert Exp $ */ -/* $NetBSD: null.h,v 1.7 1996/05/17 20:53:11 gwr Exp $ */ +/* $NetBSD: null.h,v 1.13 2001/11/07 04:56:09 enami Exp $ */ + +/* + * Copyright (c) 1999 National Aeronautics & Space Administration + * All rights reserved. + * + * This software was written by William Studenmund of the + * Numerical Aerospace Simulation Facility, NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the National Aeronautics & Space Administration + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB- + * UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ /* * Copyright (c) 1992, 1993 @@ -40,42 +72,58 @@ * @(#)null.h 8.2 (Berkeley) 1/21/94 */ +#include + struct null_args { - char *target; /* Target of loopback */ + struct layer_args la; /* generic layerfs args */ }; +#define nulla_target la.target +#define nulla_export la.export +#ifdef _KERNEL struct null_mount { - struct mount *nullm_vfs; - struct vnode *nullm_rootvp; /* Reference to root null_node */ + struct layer_mount lm; /* generic layerfs mount stuff */ }; +#define nullm_vfs lm.layerm_vfs +#define nullm_rootvp lm.layerm_rootvp +#define nullm_export lm.layerm_export +#define nullm_flags lm.layerm_flags +#define nullm_size lm.layerm_size +#define nullm_tag lm.layerm_tag +#define nullm_bypass lm.layerm_bypass +#define nullm_alloc lm.layerm_alloc +#define nullm_vnodeop_p lm.layerm_vnodeop_p +#define nullm_node_hashtbl lm.layerm_node_hashtbl +#define nullm_node_hash lm.layerm_node_hash +#define nullm_hashlock lm.layerm_hashlock -#ifdef _KERNEL /* * A cache of vnode references */ struct null_node { - LIST_ENTRY(null_node) null_hash; /* Hash list */ - struct vnode *null_lowervp; /* VREFed once */ - struct vnode *null_vnode; /* Back pointer */ + struct layer_node ln; }; +#define null_hash ln.layer_hash +#define null_lowervp ln.layer_lowervp +#define null_vnode ln.layer_vnode +#define null_flags ln.layer_flags -extern int null_node_create(struct mount *mp, struct vnode *target, struct vnode **vpp, int lockit); +int null_node_create(struct mount *, struct vnode *, + struct vnode **); #define MOUNTTONULLMOUNT(mp) ((struct null_mount *)((mp)->mnt_data)) #define VTONULL(vp) ((struct null_node *)(vp)->v_data) #define NULLTOV(xp) ((xp)->null_vnode) #ifdef NULLFS_DIAGNOSTIC -extern struct vnode *null_checkvp(struct vnode *vp, char *fil, int lno); -#define NULLVPTOLOWERVP(vp) null_checkvp((vp), __FILE__, __LINE__) +struct vnode *layer_checkvp(struct vnode *, char *, int); +#define NULLVPTOLOWERVP(vp) layer_checkvp((vp), __FILE__, __LINE__) #else #define NULLVPTOLOWERVP(vp) (VTONULL(vp)->null_lowervp) #endif extern int (**null_vnodeop_p)(void *); -extern struct vfsops null_vfsops; - -int nullfs_init(struct vfsconf *); -int null_bypass(void *); +extern struct vfsops nullfs_vfsops; +void nullfs_init(void); #endif /* _KERNEL */ diff -ruN /backup/src.old/sys/miscfs/nullfs/null_vfsops.c sys/miscfs/nullfs/null_vfsops.c --- /backup/src.old/sys/miscfs/nullfs/null_vfsops.c Mon Dec 9 21:34:21 2002 +++ sys/miscfs/nullfs/null_vfsops.c Mon Dec 9 21:39:16 2002 @@ -1,8 +1,39 @@ -/* $OpenBSD: null_vfsops.c,v 1.13 2002/03/14 01:27:08 millert Exp $ */ -/* $NetBSD: null_vfsops.c,v 1.11 1996/05/10 22:50:56 jtk Exp $ */ +/* $NetBSD: null_vfsops.c,v 1.38 2002/09/21 18:09:29 christos Exp $ */ /* - * Copyright (c) 1992, 1993 + * Copyright (c) 1999 National Aeronautics & Space Administration + * All rights reserved. + * + * This software was written by William Studenmund of the + * Numerical Aerospace Simulation Facility, NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the National Aeronautics & Space Administration + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB- + * UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1992, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software donated to Berkeley by @@ -38,7 +69,7 @@ * * from: Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp * from: @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 - * @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94 + * @(#)null_vfsops.c 8.7 (Berkeley) 5/14/95 */ /* @@ -46,29 +77,23 @@ * (See null_vnops.c for a description of what this does.) */ + #include #include -#include #include -#include +#include #include #include #include #include + #include +#include int nullfs_mount(struct mount *, const char *, void *, - struct nameidata *, struct proc *); -int nullfs_start(struct mount *, int, struct proc *); + struct nameidata *, struct proc *); int nullfs_unmount(struct mount *, int, struct proc *); -int nullfs_root(struct mount *, struct vnode **); -int nullfs_quotactl(struct mount *, int, uid_t, caddr_t, - struct proc *); -int nullfs_statfs(struct mount *, struct statfs *, struct proc *); -int nullfs_sync(struct mount *, int, struct ucred *, struct proc *); -int nullfs_vget(struct mount *, ino_t, struct vnode **); -int nullfs_fhtovp(struct mount *, struct fid *, struct vnode **); -int nullfs_vptofh(struct vnode *, struct fid *); + /* * Mount null layer */ @@ -80,37 +105,50 @@ struct nameidata *ndp; struct proc *p; { - int error = 0; struct null_args args; struct vnode *lowerrootvp, *vp; - struct vnode *nullm_rootvp; - struct null_mount *xmp; + struct null_mount *nmp; + struct layer_mount *lmp; size_t size; + int error = 0; #ifdef NULLFS_DIAGNOSTIC printf("nullfs_mount(mp = %p)\n", mp); #endif - - /* - * Update is a no-op - */ - if (mp->mnt_flag & MNT_UPDATE) { - return (EOPNOTSUPP); - /* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/ +#if 0 + if (mp->mnt_flag & MNT_GETARGS) { + lmp = MOUNTTOLAYERMOUNT(mp); + if (lmp == NULL) + return EIO; + args.la.target = NULL; + vfs_showexport(mp, &args.la.export, &lmp->layerm_export); + return copyout(&args, data, sizeof(args)); } - +#endif /* * Get argument */ - error = copyin(data, &args, sizeof(struct null_args)); + error = copyin(data, (caddr_t)&args, sizeof(struct null_args)); if (error) return (error); /* + * Update only does export updating. + */ + if (mp->mnt_flag & MNT_UPDATE) { + lmp = MOUNTTOLAYERMOUNT(mp); + if (args.nulla_target == NULL) + return (vfs_export(mp, &lmp->layerm_export, + &args.la.export)); + else + return (EOPNOTSUPP); + } + + /* * Find lower node */ - NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF, - UIO_USERSPACE, args.target, p); + NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, + UIO_USERSPACE, args.la.target, p); if ((error = namei(ndp)) != 0) return (error); @@ -119,81 +157,71 @@ */ lowerrootvp = ndp->ni_vp; - vrele(ndp->ni_dvp); - ndp->ni_dvp = NULL; - - if (lowerrootvp->v_type != VDIR) { - vput(lowerrootvp); - return (EINVAL); - } - - xmp = (struct null_mount *) malloc(sizeof(struct null_mount), - M_UFSMNT, M_WAITOK); /* XXX */ - /* - * Save reference to underlying FS + * First cut at fixing up upper mount point */ - xmp->nullm_vfs = lowerrootvp->v_mount; + nmp = (struct null_mount *) malloc(sizeof(struct null_mount), + M_UFSMNT, M_WAITOK); /* XXX */ + memset((caddr_t)nmp, 0, sizeof(struct null_mount)); + + mp->mnt_data = (qaddr_t)nmp; + nmp->nullm_vfs = lowerrootvp->v_mount; + if (nmp->nullm_vfs->mnt_flag & MNT_LOCAL) + mp->mnt_flag |= MNT_LOCAL; /* - * Save reference. Each mount also holds - * a reference on the root vnode. + * Make sure that the mount point is sufficiently initialized + * that the node create call will work. */ - error = null_node_create(mp, lowerrootvp, &vp, 1); + vfs_getnewfsid(mp); + + nmp->nullm_size = sizeof(struct null_node); + nmp->nullm_tag = VT_NULL; + nmp->nullm_bypass = layer_bypass; + nmp->nullm_alloc = layer_node_alloc; /* the default alloc is fine */ + nmp->nullm_vnodeop_p = null_vnodeop_p; + simple_lock_init(&nmp->nullm_hashlock); + nmp->nullm_node_hashtbl = hashinit(desiredvnodes, M_CACHE, + M_WAITOK, &nmp->nullm_node_hash); + /* - * Unlock the node (either the lower or the alias) + * Fix up null node for root vnode */ - VOP_UNLOCK(vp, 0, p); + error = layer_node_create(mp, lowerrootvp, &vp); /* - * Make sure the node alias worked + * Make sure the fixup worked */ if (error) { - vrele(lowerrootvp); - free(xmp, M_UFSMNT); /* XXX */ + vput(lowerrootvp); + free(nmp->nullm_node_hashtbl, M_CACHE); + free(nmp, M_UFSMNT); /* XXX */ return (error); } + /* + * Unlock the node + */ + VOP_UNLOCK(vp, 0, p); /* * Keep a held reference to the root vnode. * It is vrele'd in nullfs_unmount. */ - nullm_rootvp = vp; - nullm_rootvp->v_flag |= VROOT; - xmp->nullm_rootvp = nullm_rootvp; - if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) - mp->mnt_flag |= MNT_LOCAL; - mp->mnt_data = (qaddr_t) xmp; - vfs_getnewfsid(mp); + vp->v_flag |= VROOT; + nmp->nullm_rootvp = vp; (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); - bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); - (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, - &size); - bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); + memset(mp->mnt_stat.f_mntonname + size, 0, MNAMELEN - size); + (void) copyinstr(args.la.target, mp->mnt_stat.f_mntfromname, + MNAMELEN - 1, &size); + memset(mp->mnt_stat.f_mntfromname + size, 0, MNAMELEN - size); #ifdef NULLFS_DIAGNOSTIC printf("nullfs_mount: lower %s, alias at %s\n", - mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); + mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); #endif return (0); } /* - * VFS start. Nothing needed here - the start routine - * on the underlying filesystem will have been called - * when that filesystem was mounted. - */ -int -nullfs_start(mp, flags, p) - struct mount *mp; - int flags; - struct proc *p; -{ - - return (0); - /* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */ -} - -/* * Free reference to null layer */ int @@ -202,7 +230,8 @@ int mntflags; struct proc *p; { - struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; + struct null_mount *nmp = MOUNTTONULLMOUNT(mp); + struct vnode *null_rootvp = nmp->nullm_rootvp; int error; int flags = 0; @@ -210,9 +239,8 @@ printf("nullfs_unmount(mp = %p)\n", mp); #endif - if (mntflags & MNT_FORCE) { + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } /* * Clear out buffer cache. I don't think we @@ -220,172 +248,56 @@ * moment, but who knows... */ #if 0 - mntflushbuf(mp, 0); + mntflushbuf(mp, 0); if (mntinvalbuf(mp, 1)) return (EBUSY); #endif - if (nullm_rootvp->v_usecount > 1) + if (null_rootvp->v_usecount > 1) return (EBUSY); - if ((error = vflush(mp, nullm_rootvp, flags)) != 0) + if ((error = vflush(mp, null_rootvp, flags)) != 0) return (error); #ifdef NULLFS_DIAGNOSTIC - vprint("alias root of lower", nullm_rootvp); -#endif + vprint("alias root of lower", null_rootvp); +#endif /* * Release reference on underlying root vnode */ - vrele(nullm_rootvp); + vrele(null_rootvp); + /* * And blow it away for future re-use */ - vgone(nullm_rootvp); + vgone(null_rootvp); + /* * Finally, throw away the null_mount structure */ + free(nmp->nullm_node_hashtbl, M_CACHE); free(mp->mnt_data, M_UFSMNT); /* XXX */ - mp->mnt_data = 0; - return 0; -} - -int -nullfs_root(mp, vpp) - struct mount *mp; - struct vnode **vpp; -{ - struct vnode *vp; - struct proc *p = curproc; - -#ifdef NULLFS_DIAGNOSTIC - printf("nullfs_root(mp = %p, vp = %p->%p)\n", mp, - MOUNTTONULLMOUNT(mp)->nullm_rootvp, - NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) - ); -#endif - - /* - * Return locked reference to root. - */ - vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; - VREF(vp); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - *vpp = vp; - return 0; -} - -int -nullfs_quotactl(mp, cmd, uid, arg, p) - struct mount *mp; - int cmd; - uid_t uid; - caddr_t arg; - struct proc *p; -{ - - return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p); -} - -int -nullfs_statfs(mp, sbp, p) - struct mount *mp; - struct statfs *sbp; - struct proc *p; -{ - int error; - struct statfs mstat; - -#ifdef NULLFS_DIAGNOSTIC - printf("nullfs_statfs(mp = %p, vp = %p->%p)\n", mp, - MOUNTTONULLMOUNT(mp)->nullm_rootvp, - NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) - ); -#endif - - bzero(&mstat, sizeof(mstat)); - - error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p); - if (error) - return (error); - - /* now copy across the "interesting" information and fake the rest */ - sbp->f_flags = mstat.f_flags; - sbp->f_bsize = mstat.f_bsize; - sbp->f_iosize = mstat.f_iosize; - sbp->f_blocks = mstat.f_blocks; - sbp->f_bfree = mstat.f_bfree; - sbp->f_bavail = mstat.f_bavail; - sbp->f_files = mstat.f_files; - sbp->f_ffree = mstat.f_ffree; - if (sbp != &mp->mnt_stat) { - bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); - bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); - } - strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); + mp->mnt_data = NULL; return (0); } -int -nullfs_sync(mp, waitfor, cred, p) - struct mount *mp; - int waitfor; - struct ucred *cred; - struct proc *p; -{ - - /* - * XXX - Assumes no data cached at null layer. - */ - return (0); -} - -int -nullfs_vget(mp, ino, vpp) - struct mount *mp; - ino_t ino; - struct vnode **vpp; -{ - - return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp); -} - -int -nullfs_fhtovp(mp, fidp, vpp) - struct mount *mp; - struct fid *fidp; - struct vnode **vpp; -{ - - return (EOPNOTSUPP); -} - -int -nullfs_vptofh(vp, fhp) - struct vnode *vp; - struct fid *fhp; -{ - - return (EOPNOTSUPP); -} - -#define nullfs_sysctl ((int (*)(int *, u_int, void *, size_t *, void *, \ - size_t, struct proc *))eopnotsupp) +extern const struct vnodeopv_desc null_vnodeop_opv_desc; -#define nullfs_checkexp ((int (*)(struct mount *, struct mbuf *, \ - int *, struct ucred **))eopnotsupp) +const struct vnodeopv_desc * const nullfs_vnodeopv_descs[] = { + &null_vnodeop_opv_desc, + NULL, +}; -struct vfsops null_vfsops = { +struct vfsops nullfs_vfsops = { nullfs_mount, - nullfs_start, + layerfs_start, nullfs_unmount, - nullfs_root, - nullfs_quotactl, - nullfs_statfs, - nullfs_sync, - nullfs_vget, - nullfs_fhtovp, - nullfs_vptofh, - nullfs_init, - nullfs_sysctl, - nullfs_checkexp + layerfs_root, + layerfs_quotactl, + layerfs_statfs, + layerfs_sync, + layerfs_vget, + layerfs_fhtovp, + layerfs_vptofh, + layerfs_init, + layerfs_sysctl, + layerfs_checkexp }; diff -ruN /backup/src.old/sys/miscfs/nullfs/null_vnops.c sys/miscfs/nullfs/null_vnops.c --- /backup/src.old/sys/miscfs/nullfs/null_vnops.c Mon Dec 9 21:34:21 2002 +++ sys/miscfs/nullfs/null_vnops.c Mon Dec 9 21:41:14 2002 @@ -1,7 +1,38 @@ -/* $OpenBSD: null_vnops.c,v 1.15 2002/03/14 01:27:08 millert Exp $ */ -/* $NetBSD: null_vnops.c,v 1.7 1996/05/10 22:51:01 jtk Exp $ */ +/* $NetBSD: null_vnops.c,v 1.26 2002/09/10 02:52:40 jtk Exp $ */ /* + * Copyright (c) 1999 National Aeronautics & Space Administration + * All rights reserved. + * + * This software was written by William Studenmund of the + * Numerical Aerospace Simulation Facility, NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the National Aeronautics & Space Administration + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB- + * UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * @@ -36,11 +67,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)null_vnops.c 8.1 (Berkeley) 6/10/93 + * @(#)null_vnops.c 8.6 (Berkeley) 5/27/95 * * Ancestors: * @(#)lofs_vnops.c 1.2 (Berkeley) 6/18/92 - * Id: lofs_vnops.c,v 1.11 1992/05/30 10:05:43 jsp Exp + * Id: lofs_vnops.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp * ...and... * @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project */ @@ -54,25 +85,25 @@ * name space under a new name. In this respect, it is * similar to the loopback file system. It differs from * the loopback fs in two respects: it is implemented using - * a stackable layers techniques, and it's "null-node"s stack above + * a stackable layers technique, and its "null-nodes" stack above * all lower-layer vnodes, not just over directory vnodes. * * The null layer has two purposes. First, it serves as a demonstration - * of layering by proving a layer which does nothing. (It actually + * of layering by providing a layer which does nothing (it actually * does everything the loopback file system does, which is slightly - * more than nothing.) Second, the null layer can serve as a prototype + * more than nothing). Second, the null layer can serve as a prototype * layer. Since it provides all necessary layer framework, - * new file system layers can be created very easily be starting + * new file system layers can be created very easily by starting * with a null layer. * - * The remainder of this man page examines the null layer as a basis + * The remainder of this comment examines the null layer as a basis * for constructing new layers. * * * INSTANTIATING NEW NULL LAYERS * * New null layers are created with mount_null(8). - * Mount_null(8) takes two arguments, the pathname + * mount_null(8) takes two arguments, the pathname * of the lower vfs (target-pn) and the pathname where the null * layer will appear in the namespace (alias-pn). After * the null layer is put into place, the contents @@ -84,38 +115,38 @@ * The null layer is the minimum file system layer, * simply bypassing all possible operations to the lower layer * for processing there. The majority of its activity centers - * on the bypass routine, though which nearly all vnode operations + * on the bypass routine, through which nearly all vnode operations * pass. * * The bypass routine accepts arbitrary vnode operations for - * handling by the lower layer. It begins by examing vnode + * handling by the lower layer. It begins by examining vnode * operation arguments and replacing any null-nodes by their - * lower-layer equivlants. It then invokes the operation + * lower-layer equivalents. It then invokes the operation * on the lower layer. Finally, it replaces the null-nodes - * in the arguments and, if a vnode is return by the operation, + * in the arguments and, if a vnode is returned by the operation, * stacks a null-node on top of the returned vnode. * - * Although bypass handles most operations, - * vop_getattr, _inactive, _reclaim, and _print are not bypassed. - * Vop_getattr must change the fsid being returned. - * Vop_lock and vop_unlock must handle any locking for the + * Although bypass handles most operations, vop_getattr, vop_lock, + * vop_unlock, vop_inactive, vop_reclaim, and vop_print are not + * bypassed. vop_getattr must change the fsid being returned. + * vop_lock and vop_unlock must handle any locking for the * current vnode as well as pass the lock request down. - * Vop_inactive and vop_reclaim are not bypassed so that - * the can handle freeing null-layer specific data. Vop_print + * vop_inactive and vop_reclaim are not bypassed so that + * they can handle freeing null-layer specific data. vop_print * is not bypassed to avoid excessive debugging information. - * Also, certain vnod eoperations change the locking state within + * Also, certain vnode operations change the locking state within * the operation (create, mknod, remove, link, rename, mkdir, rmdir, - * and symlink). Ideally, these operations should not change the + * and symlink). Ideally these operations should not change the * lock state, but should be changed to let the caller of the - * function unlock them.Otherwise all intermediate vnode layers - * (such as union, umapfs, etc) must catch these functions - * to the necessary locking at their layer + * function unlock them. Otherwise all intermediate vnode layers + * (such as union, umapfs, etc) must catch these functions to do + * the necessary locking at their layer. * * * INSTANTIATING VNODE STACKS * * Mounting associates the null layer with a lower layer, - * effect stacking two VFSes. Vnode stacks are instead + * in effect stacking two VFSes. Vnode stacks are instead * created on demand as files are accessed. * * The initial mount creates a single vnode stack for the @@ -123,7 +154,7 @@ * are created as a result of vnode operations on * this or other null vnode stacks. * - * New vnode stacks come into existance as a result of + * New vnode stacks come into existence as a result of * an operation which returns a vnode. * The bypass routine stacks a null-node above the new * vnode before returning it to the caller. @@ -135,7 +166,7 @@ * Now consider opening "sys". A vop_lookup would be * done on the root null-node. This operation would bypass through * to the lower layer which would return a vnode representing - * the UFS "sys". Null_bypass then builds a null-node + * the UFS "sys". null_bypass then builds a null-node * aliasing the UFS "sys" and returns this to the caller. * Later operations on the null-node "sys" will repeat this * process when constructing other vnode stacks. @@ -145,7 +176,7 @@ * * One of the easiest ways to construct new file system layers is to make * a copy of the null layer, rename all files and variables, and - * then begin modifing the copy. Sed can be used to easily rename + * then begin modifying the copy. sed(1) can be used to easily rename * all variables. * * The umap layer is an example of a layer descended from the @@ -159,479 +190,62 @@ * is appropriate in different situations. In both cases, * it is the responsibility of the aliasing layer to make * the operation arguments "correct" for the lower layer - * by mapping an vnode arguments to the lower layer. + * by mapping any vnode arguments to the lower layer. * * The first approach is to call the aliasing layer's bypass routine. * This method is most suitable when you wish to invoke the operation - * currently being hanldled on the lower layer. It has the advantage + * currently being handled on the lower layer. It has the advantage * that the bypass routine already must do argument mapping. * An example of this is null_getattrs in the null layer. * - * A second approach is to directly invoked vnode operations on + * A second approach is to directly invoke vnode operations on * the lower layer with the VOP_OPERATIONNAME interface. * The advantage of this method is that it is easy to invoke * arbitrary operations on the lower layer. The disadvantage - * is that vnodes arguments must be manualy mapped. + * is that vnode arguments must be manually mapped. * */ + #include #include #include #include -#include #include #include #include #include #include +#include #include - - -int null_bug_bypass = 0; /* for debugging: enables bypass printf'ing */ - -int null_getattr(void *); -int null_inactive(void *); -int null_reclaim(void *); -int null_print(void *); -int null_strategy(void *); -int null_bwrite(void *); -int null_lock(void *); -int null_unlock(void *); -int null_islocked(void *); -int null_lookup(void *); -int null_open(void *); - -/* - * This is the 10-Apr-92 bypass routine. - * This version has been optimized for speed, throwing away some - * safety checks. It should still always work, but it's not as - * robust to programmer errors. - * Define SAFETY to include some error checking code. - * - * In general, we map all vnodes going down and unmap them on the way back. - * As an exception to this, vnodes can be marked "unmapped" by setting - * the Nth bit in operation's vdesc_flags. - * - * Also, some BSD vnode operations have the side effect of vrele'ing - * their arguments. With stacking, the reference counts are held - * by the upper node, not the lower one, so we must handle these - * side-effects here. This is not of concern in Sun-derived systems - * since there are no such side-effects. - * - * This makes the following assumptions: - * - only one returned vpp - * - no INOUT vpp's (Sun's vop_open has one of these) - * - the vnode operation vector of the first vnode should be used - * to determine what implementation of the op should be invoked - * - all mapped vnodes are of our vnode-type (NEEDSWORK: - * problems on rmdir'ing mount points and renaming?) - */ -int -null_bypass(v) - void *v; -{ - struct vop_generic_args /* { - struct vnodeop_desc *a_desc; - - } */ *ap = v; - register struct vnode **this_vp_p; - int error; - struct vnode *old_vps[VDESC_MAX_VPS]; - struct vnode **vps_p[VDESC_MAX_VPS]; - struct vnode ***vppp; - struct vnodeop_desc *descp = ap->a_desc; - int reles, i; - - if (null_bug_bypass) - printf ("null_bypass: %s\n", descp->vdesc_name); - -#ifdef SAFETY - /* - * We require at least one vp. - */ - if (descp->vdesc_vp_offsets == NULL || - descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET) - panic ("null_bypass: no vp's in map."); -#endif - - /* - * Map the vnodes going in. - * Later, we'll invoke the operation based on - * the first mapped vnode's operation vector. - */ - reles = descp->vdesc_flags; - for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { - if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) - break; /* bail out at end of list */ - vps_p[i] = this_vp_p = - VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap); - /* - * We're not guaranteed that any but the first vnode - * are of our type. Check for and don't map any - * that aren't. (We must always map first vp or vclean fails.) - */ - if (i && (*this_vp_p == NULLVP || - (*this_vp_p)->v_op != null_vnodeop_p)) { - old_vps[i] = NULLVP; - } else { - old_vps[i] = *this_vp_p; - *(vps_p[i]) = NULLVPTOLOWERVP(*this_vp_p); - /* - * XXX - Several operations have the side effect - * of vrele'ing their vp's. We must account for - * that. (This should go away in the future.) - */ - if (reles & 1) - VREF(*this_vp_p); - } - - } - - /* - * Call the operation on the lower layer - * with the modified argument structure. - */ - error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap); - - /* - * Maintain the illusion of call-by-value - * by restoring vnodes in the argument structure - * to their original value. - */ - reles = descp->vdesc_flags; - for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { - if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) - break; /* bail out at end of list */ - if (old_vps[i] != NULLVP) { - *(vps_p[i]) = old_vps[i]; - if (reles & 1) { - vrele(*(vps_p[i])); - } - } - - /* - * Map the possible out-going vpp - * (Assumes that the lower layer always returns - * a VREF'ed vpp unless it gets an error.) - */ - if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET && - !(descp->vdesc_flags & VDESC_NOMAP_VPP) && - !error) { - /* - * XXX - even though some ops have vpp returned vp's, - * several ops actually vrele this before returning. - * We must avoid these ops. - * (This should go away when these ops are regularized.) - */ - if (descp->vdesc_flags & VDESC_VPP_WILLRELE) - goto out; - vppp = VOPARG_OFFSETTO(struct vnode***, - descp->vdesc_vpp_offset,ap); - /* - * This assumes that **vppp is a locked vnode (it is always - * so as of this writing, NetBSD-current 1995/02/16) - * - * (don't want to lock it if being called on behalf - * of lookup--it plays weird locking games depending - * on whether or not it's looking up ".", "..", etc. - */ - error = null_node_create(old_vps[0]->v_mount, **vppp, *vppp, - descp == &vop_lookup_desc ? 0 : 1); - } - } - - out: - return (error); - -} - -/* - * We handle getattr only to change the fsid. - */ -int -null_getattr(v) - void *v; -{ - struct vop_getattr_args /* { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap = v; - int error; - if ((error = null_bypass(ap)) != NULL) - return (error); - /* Requires that arguments be restored. */ - ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; - return (0); -} - -/* - * We must handle open to be able to catch MNT_NODEV and friends. - */ -int -null_open(v) - void *v; -{ - struct vop_open_args *ap = v; - struct vnode *vp = ap->a_vp; - enum vtype lower_type = VTONULL(vp)->null_lowervp->v_type; - - - if (((lower_type == VBLK) || (lower_type == VCHR)) && - (vp->v_mount->mnt_flag & MNT_NODEV)) - return ENXIO; - - return null_bypass(ap); -} - -int -null_inactive(v) - void *v; -{ - struct vop_inactive_args *ap = v; - - /* - * Do nothing (and _don't_ bypass). - * Wait to vrele lowervp until reclaim, - * so that until then our null_node is in the - * cache and reusable. - * - * NEEDSWORK: Someday, consider inactive'ing - * the lowervp and then trying to reactivate it - * with capabilities (v_id) - * like they do in the name lookup cache code. - * That's too much work for now. - */ - VOP_UNLOCK(ap->a_vp, 0, ap->a_p); - - return (0); -} - -int -null_reclaim(v) - void *v; -{ - struct vop_reclaim_args /* { - struct vnode *a_vp; - } */ *ap = v; - struct vnode *vp = ap->a_vp; - struct null_node *xp = VTONULL(vp); - struct vnode *lowervp = xp->null_lowervp; - - /* - * Note: in vop_reclaim, vp->v_op == dead_vnodeop_p, - * so we can't call VOPs on ourself. - */ - /* After this assignment, this node will not be re-used. */ - xp->null_lowervp = NULL; - LIST_REMOVE(xp, null_hash); - FREE(vp->v_data, M_TEMP); - vp->v_data = NULL; - vrele (lowervp); - return (0); -} - - -int -null_print(v) - void *v; -{ - struct vop_print_args /* { - struct vnode *a_vp; - } */ *ap = v; - register struct vnode *vp = ap->a_vp; - - printf ("\ttag VT_NULLFS, vp=%p, lowervp=%p\n", vp, NULLVPTOLOWERVP(vp)); - vprint("nullfs lowervp", NULLVPTOLOWERVP(vp)); - return (0); -} - - -/* - * XXX - vop_strategy must be hand coded because it has no - * vnode in its arguments. - */ -int -null_strategy(v) - void *v; -{ - struct vop_strategy_args /* { - struct buf *a_bp; - } */ *ap = v; - struct buf *bp = ap->a_bp; - int error; - struct vnode *savedvp; - - savedvp = bp->b_vp; - bp->b_vp = NULLVPTOLOWERVP(bp->b_vp); - - error = VOP_STRATEGY(bp); - - bp->b_vp = savedvp; - - return (error); -} - - -/* - * XXX - like vop_strategy, vop_bwrite must be hand coded because it has no - * vnode in its arguments. - */ -int -null_bwrite(v) - void *v; -{ - struct vop_bwrite_args /* { - struct buf *a_bp; - } */ *ap = v; - struct buf *bp = ap->a_bp; - int error; - struct vnode *savedvp; - - savedvp = bp->b_vp; - bp->b_vp = NULLVPTOLOWERVP(bp->b_vp); - - error = VOP_BWRITE(bp); - - bp->b_vp = savedvp; - - return (error); -} - -/* - * We need a separate null lock routine, to avoid deadlocks at reclaim time. - * If a process holds the lower-vnode locked when it tries to reclaim - * the null upper-vnode, _and_ null_bypass is used as the locking operation, - * then a process can end up locking against itself. - * This has been observed when a null mount is set up to "tunnel" beneath a - * union mount (that setup is useful if you still wish to be able to access - * the non-union version of either the above or below union layer) - */ -int -null_lock(v) - void *v; -{ - struct vop_lock_args *ap = v; - -#if 0 - vop_generic_lock(ap); -#endif - if ((ap->a_flags & LK_TYPE_MASK) == LK_DRAIN) - return (0); - ap->a_flags &= ~LK_INTERLOCK; - - return (null_bypass((struct vop_generic_args *)ap)); -} - -int -null_unlock(v) - void *v; -{ - struct vop_unlock_args *ap = v; -#if 0 - vop_generic_unlock(ap); -#endif - ap->a_flags &= ~LK_INTERLOCK; - - return (null_bypass((struct vop_generic_args *)ap)); -} - -int -null_islocked(v) - void *v; -{ - /* XXX */ - return (0); -} - -int -null_lookup(v) - void *v; -{ - register struct vop_lookup_args /* { - struct vnodeop_desc *a_desc; - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - } */ *ap = v; - register int error; - int flags = ap->a_cnp->cn_flags; - struct componentname *cnp = ap->a_cnp; -#if 0 - register struct vnode *dvp, *vp; - struct proc *p = cnp->cn_proc; - struct vop_unlock_args unlockargs; - struct vop_lock_args lockargs; -#endif - -#ifdef NULLFS_DIAGNOSTIC - printf("null_lookup: dvp=%lx, name='%s'\n", - ap->a_dvp, cnp->cn_nameptr); -#endif - - if ((flags & ISLASTCN) && (ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY) && - (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) - return (EROFS); - error = null_bypass((struct vop_generic_args *)ap); - if (error == EJUSTRETURN && (flags & ISLASTCN) && - (ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY) && - (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)) - error = EROFS; - -#if 0 - /* - * We must do the same locking and unlocking at this layer as - * is done in the layers below us. We could figure this out - * based on the error return and the LASTCN, LOCKPARENT, and - * LOCKLEAF flags. However, it is more expidient to just find - * out the state of the lower level vnodes and set ours to the - * same state. - */ - dvp = ap->a_dvp; - vp = *ap->a_vpp; - if (dvp == vp) - return (error); - if (!VOP_ISLOCKED(dvp)) { - unlockargs.a_vp = dvp; - unlockargs.a_flags = 0; - unlockargs.a_p = p; - vop_generic_unlock(&unlockargs); - } - if (vp != NULLVP && VOP_ISLOCKED(vp)) { - lockargs.a_vp = vp; - lockargs.a_flags = LK_SHARED; - lockargs.a_p = p; - vop_generic_lock(&lockargs); - } -#endif - return (error); -} +#include /* * Global vfs data structures */ int (**null_vnodeop_p)(void *); struct vnodeopv_entry_desc null_vnodeop_entries[] = { - { &vop_default_desc, null_bypass }, - - { &vop_getattr_desc, null_getattr }, - { &vop_inactive_desc, null_inactive }, - { &vop_reclaim_desc, null_reclaim }, - { &vop_print_desc, null_print }, - - { &vop_open_desc, null_open }, /* mount option handling */ - - { &vop_lock_desc, null_lock }, - { &vop_unlock_desc, null_unlock }, - { &vop_islocked_desc, null_islocked }, - { &vop_lookup_desc, null_lookup }, /* special locking frob */ + { &vop_default_desc, layer_bypass }, - { &vop_strategy_desc, null_strategy }, - { &vop_bwrite_desc, null_bwrite }, + { &vop_lookup_desc, layer_lookup }, + { &vop_setattr_desc, layer_setattr }, + { &vop_getattr_desc, layer_getattr }, + { &vop_access_desc, layer_access }, + { &vop_lock_desc, layer_lock }, + { &vop_unlock_desc, layer_unlock }, + { &vop_islocked_desc, layer_islocked }, + { &vop_fsync_desc, layer_fsync }, + { &vop_inactive_desc, layer_inactive }, + { &vop_reclaim_desc, layer_reclaim }, + { &vop_print_desc, layer_print }, + + { &vop_open_desc, layer_open }, /* mount option handling */ + + { &vop_strategy_desc, layer_strategy }, + { &vop_bwrite_desc, layer_bwrite }, + { &vop_bmap_desc, layer_bmap }, - { NULL, NULL } + { NULL, NULL } }; -struct vnodeopv_desc null_vnodeop_opv_desc = +const struct vnodeopv_desc null_vnodeop_opv_desc = { &null_vnodeop_p, null_vnodeop_entries }; diff -ruN /backup/src.old/sys/miscfs/portal/portal_vnops.c sys/miscfs/portal/portal_vnops.c --- /backup/src.old/sys/miscfs/portal/portal_vnops.c Mon Dec 9 21:34:21 2002 +++ sys/miscfs/portal/portal_vnops.c Mon Dec 9 21:39:16 2002 @@ -186,6 +186,7 @@ struct componentname *cnp = ap->a_cnp; struct vnode **vpp = ap->a_vpp; struct vnode *dvp = ap->a_dvp; + struct proc *p = cnp->cn_proc; char *pname = cnp->cn_nameptr; struct portalnode *pt; int error; @@ -228,7 +229,13 @@ pt->pt_fileid = portal_fileid++; *vpp = fvp; - /*VOP_LOCK(fvp);*/ + VOP_LOCK(fvp, LK_EXCLUSIVE, p); + + if ((cnp->cn_flags & LOCKPARENT) == 0) { + VOP_UNLOCK(dvp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } + return (0); bad:; diff -ruN /backup/src.old/sys/miscfs/procfs/procfs_vnops.c sys/miscfs/procfs/procfs_vnops.c --- /backup/src.old/sys/miscfs/procfs/procfs_vnops.c Mon Dec 9 21:34:21 2002 +++ sys/miscfs/procfs/procfs_vnops.c Mon Dec 9 21:39:16 2002 @@ -358,8 +358,10 @@ struct vop_inactive_args /* { struct vnode *a_vp; } */ *ap = v; + struct proc *p = curproc; struct pfsnode *pfs = VTOPFS(ap->a_vp); + VOP_UNLOCK(ap->a_vp, 0, p); if (pfind(pfs->pfs_pid) == 0) vgone(ap->a_vp); @@ -751,9 +753,10 @@ pid_t pid; struct pfsnode *pfs; struct proc *p = NULL; - int i, error, iscurproc = 0, isself = 0; + int i, error, wantpunlock, iscurproc = 0, isself = 0; *vpp = NULL; + cnp->cn_flags &= ~PDIRUNLOCK; if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) return (EROFS); @@ -765,6 +768,7 @@ return (0); } + wantpunlock = (~cnp->cn_flags & (LOCKPARENT | ISLASTCN)); pfs = VTOPFS(dvp); switch (pfs->pfs_type) { case Proot: @@ -777,12 +781,10 @@ if (iscurproc || isself) { error = procfs_allocvp(dvp->v_mount, vpp, 0, iscurproc ? Pcurproc : Pself); -#if 0 if ((error == 0) && (wantpunlock)) { - VOP_UNLOCK(dvp, 0); + VOP_UNLOCK(dvp, 0, curp); cnp->cn_flags |= PDIRUNLOCK; } -#endif return (error); } @@ -798,12 +800,10 @@ if (i != nproc_root_targets) { error = procfs_allocvp(dvp->v_mount, vpp, 0, pt->pt_pfstype); -#if 0 if ((error == 0) && (wantpunlock)) { - VOP_UNLOCK(dvp, 0); + VOP_UNLOCK(dvp, 0, curp); cnp->cn_flags |= PDIRUNLOCK; } -#endif return (error); } @@ -815,11 +815,24 @@ if (p == 0) break; - return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc)); + error = procfs_allocvp(dvp->v_mount, vpp, pid, Pproc); + if ((error == 0) && (wantpunlock)) { + VOP_UNLOCK(dvp, 0, curp); + cnp->cn_flags |= PDIRUNLOCK; + } + return(error); + case Pproc: - if (cnp->cn_flags & ISDOTDOT) - return (procfs_root(dvp->v_mount, vpp)); + if (cnp->cn_flags & ISDOTDOT) { + VOP_UNLOCK(dvp, 0, curp); + cnp->cn_flags |= PDIRUNLOCK; + error = procfs_root(dvp->v_mount, vpp); + if ((error == 0) && (wantpunlock == 0) && + ((error = vn_lock(dvp, LK_EXCLUSIVE, curp)) == 0)) + cnp->cn_flags &= ~PDIRUNLOCK; + return(error); + } p = pfind(pfs->pfs_pid); if (p == 0) @@ -840,12 +853,21 @@ /* We already checked that it exists. */ VREF(fvp); vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, curp); + if (wantpunlock) { + VOP_UNLOCK(dvp, 0, curp); + cnp->cn_flags |= PDIRUNLOCK; + } *vpp = fvp; return (0); } - return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, - pt->pt_pfstype)); + error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, + pt->pt_pfstype); + if ((error == 0) && (wantpunlock)) { + VOP_UNLOCK(dvp, 0, curp); + cnp->cn_flags |= PDIRUNLOCK; + } + return(error); default: return (ENOTDIR); diff -ruN /backup/src.old/sys/miscfs/umapfs/umap.h sys/miscfs/umapfs/umap.h --- /backup/src.old/sys/miscfs/umapfs/umap.h Mon Dec 9 21:34:21 2002 +++ sys/miscfs/umapfs/umap.h Mon Dec 9 21:39:16 2002 @@ -1,5 +1,4 @@ -/* $OpenBSD: umap.h,v 1.9 2002/03/14 01:27:08 millert Exp $ */ -/* $NetBSD: umap.h,v 1.6 1996/02/09 22:41:00 christos Exp $ */ +/* $NetBSD: umap.h,v 1.9 1999/07/08 01:19:06 wrstuden Exp $ */ /* * Copyright (c) 1992, 1993 @@ -37,63 +36,80 @@ * SUCH DAMAGE. * * from: @(#)null_vnops.c 1.5 (Berkeley) 7/10/92 - * @(#)umap.h 8.3 (Berkeley) 1/21/94 + * @(#)umap.h 8.4 (Berkeley) 8/20/94 */ -#define UMAPFILEENTRIES 64 +#include + +#define MAPFILEENTRIES 64 #define GMAPFILEENTRIES 16 #define NOBODY 32767 #define NULLGROUP 65534 -typedef u_int32_t id_t; -typedef id_t (*id_map_t)[2]; - struct umap_args { - char *target; /* Target of loopback */ - int unentries; /* # of entries in user map array */ - int gnentries; /* # of entries in group map array */ - id_map_t umapdata; /* pointer to array of user mappings */ - id_map_t gmapdata; /* pointer to array of group mappings */ + struct layer_args la; /* generic layerfs args. Includes + * target and export info */ +#define umap_target la.target +#define umap_export la.export + int nentries; /* # of entries in user map array */ + int gnentries; /* # of entries in group map array */ + u_long (*mapdata)[2]; /* pointer to array of user mappings */ + u_long (*gmapdata)[2]; /* pointer to array of group mappings */ }; +#ifdef _KERNEL + struct umap_mount { - struct mount *umapm_vfs; - struct vnode *umapm_rootvp; /* Reference to root umap_node */ - int info_unentries; /* number of uid mappings */ + struct layer_mount lm; + int info_nentries; /* number of uid mappings */ int info_gnentries; /* number of gid mappings */ - id_t info_umapdata[UMAPFILEENTRIES][2]; /* mapping data for + u_long info_mapdata[MAPFILEENTRIES][2]; /* mapping data for user mapping in ficus */ - id_t info_gmapdata[GMAPFILEENTRIES][2]; /*mapping data for + u_long info_gmapdata[GMAPFILEENTRIES][2]; /*mapping data for group mapping in ficus */ }; +#define umapm_vfs lm.layerm_vfs +#define umapm_rootvp lm.layerm_rootvp +#define umapm_export lm.layerm_export +#define umapm_flags lm.layerm_flags +#define umapm_size lm.layerm_size +#define umapm_tag lm.layerm_tag +#define umapm_bypass lm.layerm_bypass +#define umapm_alloc lm.layerm_alloc +#define umapm_vnodeop_p lm.layerm_vnodeop_p +#define umapm_node_hashtbl lm.layerm_node_hashtbl +#define umapm_node_hash lm.layerm_node_hash +#define umapm_hashlock lm.layerm_hashlock -#ifdef _KERNEL /* * A cache of vnode references */ struct umap_node { - LIST_ENTRY(umap_node) umap_hash; /* Hash list */ - struct vnode *umap_lowervp; /* Aliased vnode - VREFed once */ - struct vnode *umap_vnode; /* Back pointer to vnode/umap_node */ + struct layer_node ln; }; -extern int umap_node_create(struct mount *mp, struct vnode *target, struct vnode **vpp); -extern id_t umap_reverse_findid(id_t id, id_map_t, int nentries); -extern void umap_mapids(struct mount *v_mount, struct ucred *credp); +u_long umap_reverse_findid(u_long id, u_long map[][2], int nentries); +void umap_mapids(struct mount *v_mount, struct ucred *credp); + +#define umap_hash ln.layer_hash +#define umap_lowervp ln.layer_lowervp +#define umap_vnode ln.layer_vnode +#define umap_flags ln.layer_flags #define MOUNTTOUMAPMOUNT(mp) ((struct umap_mount *)((mp)->mnt_data)) #define VTOUMAP(vp) ((struct umap_node *)(vp)->v_data) #define UMAPTOV(xp) ((xp)->umap_vnode) #ifdef UMAPFS_DIAGNOSTIC -extern struct vnode *umap_checkvp(struct vnode *vp, char *fil, int lno); -#define UMAPVPTOLOWERVP(vp) umap_checkvp((vp), __FILE__, __LINE__) +#define UMAPVPTOLOWERVP(vp) layer_checkvp((vp), __FILE__, __LINE__) #else #define UMAPVPTOLOWERVP(vp) (VTOUMAP(vp)->umap_lowervp) #endif extern int (**umap_vnodeop_p)(void *); -extern struct vfsops umap_vfsops; +extern struct vfsops umapfs_vfsops; + +int umap_bypass(void *); -int umapfs_init(struct vfsconf *); +#define NUMAPNODECACHE 16 #endif /* _KERNEL */ diff -ruN /backup/src.old/sys/miscfs/umapfs/umap_subr.c sys/miscfs/umapfs/umap_subr.c --- /backup/src.old/sys/miscfs/umapfs/umap_subr.c Mon Dec 9 21:34:21 2002 +++ sys/miscfs/umapfs/umap_subr.c Mon Dec 9 21:39:16 2002 @@ -1,8 +1,39 @@ -/* $OpenBSD: umap_subr.c,v 1.14 2002/06/14 21:35:00 todd Exp $ */ -/* $NetBSD: umap_subr.c,v 1.8 1996/03/05 02:35:39 thorpej Exp $ */ +/* $NetBSD: umap_subr.c,v 1.19 2001/11/15 09:48:23 lukem Exp $ */ /* - * Copyright (c) 1992, 1993 + * Copyright (c) 1999 National Aeronautics & Space Administration + * All rights reserved. + * + * This software was written by William Studenmund of the + * Numerical Aerospace Simulation Facility, NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the National Aeronautics & Space Administration + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB- + * UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1992, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software donated to Berkeley by @@ -37,14 +68,14 @@ * SUCH DAMAGE. * * from: Id: lofs_subr.c, v 1.11 1992/05/30 10:05:43 jsp Exp - * @(#)umap_subr.c 8.6 (Berkeley) 1/26/94 + * @(#)umap_subr.c 8.9 (Berkeley) 5/14/95 */ + #include #include #include #include -#include #include #include #include @@ -52,54 +83,22 @@ #include #include -#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ -#define NUMAPNODECACHE 16 - -/* - * Null layer cache: - * Each cache entry holds a reference to the target vnode - * along with a pointer to the alias vnode. When an - * entry is added the target vnode is VREF'd. When the - * alias is removed the target vnode is vrele'd. - */ - -#define UMAP_NHASH(vp) \ - (&umap_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & umap_node_hash]) -LIST_HEAD(umap_node_hashhead, umap_node) *umap_node_hashtbl; -u_long umap_node_hash; - -static id_t umap_findid(id_t, id_map_t, int); -static struct vnode *umap_node_find(struct mount *, struct vnode *); -static int umap_node_alloc(struct mount *, struct vnode *, - struct vnode **); - -/* - * Initialise cache headers - */ -int -umapfs_init(struct vfsconf *vfsp) -{ - -#ifdef UMAPFS_DIAGNOSTIC - printf("umapfs_init\n"); /* printed during system boot */ -#endif - umap_node_hashtbl = hashinit(NUMAPNODECACHE, M_CACHE, M_WAITOK, &umap_node_hash); - return (0); -} +u_long umap_findid(u_long, u_long [][2], int); +int umap_node_alloc(struct mount *, struct vnode *, struct vnode **); /* * umap_findid is called by various routines in umap_vnodeops.c to * find a user or group id in a map. */ -static id_t +u_long umap_findid(id, map, nentries) - id_t id; - id_map_t map; - int nentries; + u_long id; + u_long map[][2]; + int nentries; { int i; - /* Find {g,u}id entry in map */ + /* Find uid entry in map */ i = 0; while ((ilh_first; a != 0; a = a->umap_hash.le_next) { - if (a->umap_lowervp == targetvp && - a->umap_vnode->v_mount == mp) { - vp = UMAPTOV(a); - /* - * We need vget for the VXLOCK - * stuff, but we don't want to lock - * the lower node. - */ - if (vget(vp, 0, p)) { -#ifdef UMAPFS_DIAGNOSTIC - printf ("umap_node_find: vget failed.\n"); -#endif - goto loop; - } - return (vp); - } - } - -#ifdef UMAPFS_DIAGNOSTIC - printf("umap_node_find(%p, %p): NOT found\n", mp, targetvp); -#endif - - return (0); -} - -/* - * Make a new umap_node node. - * Vp is the alias vnode, lowervp is the target vnode. - * Maintain a reference to lowervp. - */ -static int -umap_node_alloc(mp, lowervp, vpp) - struct mount *mp; - struct vnode *lowervp; - struct vnode **vpp; -{ - struct umap_node_hashhead *hd; - struct umap_node *xp; - struct vnode *vp, *nvp; - int error; - struct proc *p = curproc; - extern int (**dead_vnodeop_p)(void *); - - if ((error = getnewvnode(VT_UMAP, mp, umap_vnodeop_p, &vp)) != 0) - return (error); - vp->v_type = lowervp->v_type; - - MALLOC(xp, struct umap_node *, sizeof(struct umap_node), M_TEMP, - M_WAITOK); - if (vp->v_type == VBLK || vp->v_type == VCHR) { - MALLOC(vp->v_specinfo, struct specinfo *, - sizeof(struct specinfo), M_VNODE, M_WAITOK); - vp->v_rdev = lowervp->v_rdev; - } - - vp->v_data = xp; - xp->umap_vnode = vp; - xp->umap_lowervp = lowervp; - /* - * Before we insert our new node onto the hash chains, - * check to see if someone else has beaten us to it. - * (We could have slept in MALLOC.) - */ - if ((nvp = umap_node_find(mp, lowervp)) != NULL) { - *vpp = nvp; - - /* free the substructures we've allocated. */ - FREE(xp, M_TEMP); - if (vp->v_type == VBLK || vp->v_type == VCHR) - FREE(vp->v_specinfo, M_VNODE); - - vp->v_type = VBAD; /* node is discarded */ - vp->v_op = dead_vnodeop_p; /* so ops will still work */ - vrele(vp); /* get rid of it. */ - return (0); - } - - /* - * XXX if it's a device node, it needs to be checkalias()ed. - * however, for locking reasons, that's just not possible. - * so we have to do most of the dirty work inline. Note that - * this is a limited case; we know that there's going to be - * an alias, and we know that that alias will be a "real" - * device node, i.e. not tagged VT_NON. - */ - if (vp->v_type == VBLK || vp->v_type == VCHR) { - struct vnode *cvp, **cvpp; - - cvpp = &speclisth[SPECHASH(vp->v_rdev)]; -loop: - for (cvp = *cvpp; cvp; cvp = cvp->v_specnext) { - if (vp->v_rdev != cvp->v_rdev || - vp->v_type != cvp->v_type) - continue; - - /* - * Alias, but not in use, so flush it out. - */ - if (cvp->v_usecount == 0) { - vgone(cvp); - goto loop; - } - if (vget(cvp, 0, p)) /* can't lock; will die! */ - goto loop; - break; - } - - vp->v_hashchain = cvpp; - vp->v_specnext = *cvpp; - vp->v_specmountpoint = NULL; - *cvpp = vp; -#ifdef DIAGNOSTIC - if (cvp == NULLVP) - panic("umap_node_alloc: no alias for device"); -#endif - vp->v_flag |= VALIASED; - cvp->v_flag |= VALIASED; - vrele(cvp); - } - /* XXX end of transmogrified checkalias() */ - - *vpp = vp; - VREF(lowervp); /* Extra VREF will be vrele'd in umap_node_create */ - hd = UMAP_NHASH(lowervp); - LIST_INSERT_HEAD(hd, xp, umap_hash); - return (0); -} - - -/* - * Try to find an existing umap_node vnode referring - * to it, otherwise make a new umap_node vnode which - * contains a reference to the target vnode. - */ -int -umap_node_create(mp, targetvp, newvpp) - struct mount *mp; - struct vnode *targetvp; - struct vnode **newvpp; -{ - struct vnode *aliasvp; - - if ((aliasvp = umap_node_find(mp, targetvp)) != NULL) { - /* - * Take another reference to the alias vnode - */ -#ifdef UMAPFS_DIAGNOSTIC - vprint("umap_node_create: exists", aliasvp); -#endif - /* VREF(aliasvp); */ - } else { - int error; - - /* - * Get new vnode. - */ -#ifdef UMAPFS_DIAGNOSTIC - printf("umap_node_create: create new alias vnode\n"); -#endif - /* - * Make new vnode reference the umap_node. - */ - if ((error = umap_node_alloc(mp, targetvp, &aliasvp)) != 0) - return (error); - - /* - * aliasvp is already VREF'd by getnewvnode() - */ - } - - vrele(targetvp); - -#ifdef UMAPFS_DIAGNOSTIC - vprint("umap_node_create: alias", aliasvp); - vprint("umap_node_create: target", targetvp); -#endif - - *newvpp = aliasvp; - return (0); -} - -#ifdef UMAPFS_DIAGNOSTIC -int umap_checkvp_barrier = 1; -struct vnode * -umap_checkvp(vp, fil, lno) - struct vnode *vp; - char *fil; - int lno; -{ - struct umap_node *a = VTOUMAP(vp); -#ifdef notyet - /* - * Can't do this check because vop_reclaim runs - * with funny vop vector. - */ - if (vp->v_op != umap_vnodeop_p) { - printf ("umap_checkvp: on non-umap-node\n"); - while (umap_checkvp_barrier) /*WAIT*/ ; - panic("umap_checkvp"); - } -#endif - if (a->umap_lowervp == NULL) { - /* Should never happen */ - int i; u_long *p; - printf("vp = %p, ZERO ptr\n", vp); - for (p = (u_long *) a, i = 0; i < 8; i++) - printf(" %lx", p[i]); - printf("\n"); - /* wait for debugger */ - while (umap_checkvp_barrier) /*WAIT*/ ; - panic("umap_checkvp"); - } - if (a->umap_lowervp->v_usecount < 1) { - int i; u_long *p; - printf("vp = %p, unref'ed lowervp\n", vp); - for (p = (u_long *) a, i = 0; i < 8; i++) - printf(" %lx", p[i]); - printf("\n"); - /* wait for debugger */ - while (umap_checkvp_barrier) /*WAIT*/ ; - panic ("umap with unref'ed lowervp"); - } -#ifdef notyet - printf("umap %p/%d -> %p/%d [%s, %d]\n", - a->umap_vnode, a->umap_vnode->v_usecount, - a->umap_lowervp, a->umap_lowervp->v_usecount, - fil, lno); -#endif - return (a->umap_lowervp); -} -#endif - /* umap_mapids maps all of the ids in a credential, both user and group. */ void @@ -400,18 +141,18 @@ struct mount *v_mount; struct ucred *credp; { - int i, unentries, gnentries; - uid_t uid; - gid_t gid; - id_map_t usermap, groupmap; + int i, unentries, gnentries; + uid_t uid; + gid_t gid; + u_long (*usermap)[2], (*groupmap)[2]; if (credp == NOCRED) return; - unentries = MOUNTTOUMAPMOUNT(v_mount)->info_unentries; - usermap = MOUNTTOUMAPMOUNT(v_mount)->info_umapdata; + unentries = MOUNTTOUMAPMOUNT(v_mount)->info_nentries; + usermap = MOUNTTOUMAPMOUNT(v_mount)->info_mapdata; gnentries = MOUNTTOUMAPMOUNT(v_mount)->info_gnentries; - groupmap = MOUNTTOUMAPMOUNT(v_mount)->info_gmapdata; + groupmap = MOUNTTOUMAPMOUNT(v_mount)->info_gmapdata; /* Find uid entry in map */ @@ -438,7 +179,7 @@ /* Now we must map each of the set of groups in the cr_groups structure. */ - for ( i = 0 ; credp->cr_groups[i] != 0 ; i++ ) { + for(i=0; i < credp->cr_ngroups; i++) { gid = (gid_t) umap_findid(credp->cr_groups[i], groupmap, gnentries); diff -ruN /backup/src.old/sys/miscfs/umapfs/umap_vfsops.c sys/miscfs/umapfs/umap_vfsops.c --- /backup/src.old/sys/miscfs/umapfs/umap_vfsops.c Mon Dec 9 21:34:21 2002 +++ sys/miscfs/umapfs/umap_vfsops.c Mon Dec 9 21:39:16 2002 @@ -1,5 +1,4 @@ -/* $OpenBSD: umap_vfsops.c,v 1.18 2002/03/14 01:27:08 millert Exp $ */ -/* $NetBSD: umap_vfsops.c,v 1.9 1996/02/09 22:41:05 christos Exp $ */ +/* $NetBSD: umap_vfsops.c,v 1.35 2002/09/21 18:09:31 christos Exp $ */ /* * Copyright (c) 1992, 1993 @@ -37,7 +36,7 @@ * SUCH DAMAGE. * * from: @(#)null_vfsops.c 1.5 (Berkeley) 7/10/92 - * @(#)umap_vfsops.c 8.3 (Berkeley) 1/21/94 + * @(#)umap_vfsops.c 8.8 (Berkeley) 5/14/95 */ /* @@ -45,29 +44,21 @@ * (See mount_umap(8) for a description of this layer.) */ + #include #include -#include #include -#include +#include #include #include #include #include #include +#include int umapfs_mount(struct mount *, const char *, void *, - struct nameidata *, struct proc *); -int umapfs_start(struct mount *, int, struct proc *); + struct nameidata *, struct proc *); int umapfs_unmount(struct mount *, int, struct proc *); -int umapfs_root(struct mount *, struct vnode **); -int umapfs_quotactl(struct mount *, int, uid_t, caddr_t, - struct proc *); -int umapfs_statfs(struct mount *, struct statfs *, struct proc *); -int umapfs_sync(struct mount *, int, struct ucred *, struct proc *); -int umapfs_vget(struct mount *, ino_t, struct vnode **); -int umapfs_fhtovp(struct mount *, struct fid *, struct vnode **); -int umapfs_vptofh(struct vnode *, struct fid *); /* * Mount umap layer @@ -82,42 +73,57 @@ { struct umap_args args; struct vnode *lowerrootvp, *vp; - struct vnode *umapm_rootvp; struct umap_mount *amp; size_t size; int error; #ifdef UMAPFS_DIAGNOSTIC int i; +#endif +#if 0 + if (mp->mnt_flag & MNT_GETARGS) { + amp = MOUNTTOUMAPMOUNT(mp); + if (amp == NULL) + return EIO; + args.la.target = NULL; + vfs_showexport(mp, &args.la.export, &->umapm_export); + args.nentries = amp->info_nentries; + args.gnentries = amp->info_gnentries; + return copyout(&args, data, sizeof(args)); + } +#endif + + /* only for root */ + if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) + return error; +#ifdef UMAPFS_DIAGNOSTIC printf("umapfs_mount(mp = %p)\n", mp); #endif /* - * Don't allow users to play with umapfs (when usermount is true). + * Get argument */ - if (p->p_ucred->cr_uid != 0) - return EPERM; + error = copyin(data, (caddr_t)&args, sizeof(struct umap_args)); + if (error) + return (error); /* - * Update is a no-op + * Update only does export updating. */ if (mp->mnt_flag & MNT_UPDATE) { - return (EOPNOTSUPP); - /* return (VFS_MOUNT(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, path, data, ndp, p));*/ + amp = MOUNTTOUMAPMOUNT(mp); + if (args.umap_target == 0) + return (vfs_export(mp, &->umapm_export, + &args.umap_export)); + else + return (EOPNOTSUPP); } /* - * Get argument - */ - error = copyin(data, &args, sizeof(struct umap_args)); - if (error) - return (error); - - /* * Find lower node */ - NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF, - UIO_USERSPACE, args.target, p); + NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, + UIO_USERSPACE, args.umap_target, p); if ((error = namei(ndp)) != 0) return (error); @@ -128,8 +134,6 @@ #ifdef UMAPFS_DIAGNOSTIC printf("vp = %p, check for VDIR...\n", lowerrootvp); #endif - vrele(ndp->ni_dvp); - ndp->ni_dvp = 0; if (lowerrootvp->v_type != VDIR) { vput(lowerrootvp); @@ -142,83 +146,96 @@ amp = (struct umap_mount *) malloc(sizeof(struct umap_mount), M_UFSMNT, M_WAITOK); /* XXX */ + memset((caddr_t)amp, 0, sizeof(struct umap_mount)); - /* - * Save reference to underlying FS - */ + mp->mnt_data = (qaddr_t)amp; amp->umapm_vfs = lowerrootvp->v_mount; + if (amp->umapm_vfs->mnt_flag & MNT_LOCAL) + mp->mnt_flag |= MNT_LOCAL; /* * Now copy in the number of entries and maps for umap mapping. */ - if (args.unentries < 0 || args.unentries > UMAPFILEENTRIES || - args.gnentries < 0 || args.gnentries > GMAPFILEENTRIES) { + if (args.nentries > MAPFILEENTRIES || args.gnentries > GMAPFILEENTRIES) { vput(lowerrootvp); return (error); } - amp->info_unentries = args.unentries; + + amp->info_nentries = args.nentries; amp->info_gnentries = args.gnentries; - error = copyin(args.umapdata, (caddr_t)amp->info_umapdata, - 2*sizeof(**amp->info_umapdata)*args.unentries); - if (error) + error = copyin(args.mapdata, (caddr_t)amp->info_mapdata, + 2*sizeof(u_long)*args.nentries); + if (error) { + vput(lowerrootvp); return (error); + } #ifdef UMAPFS_DIAGNOSTIC - printf("umap_mount:unentries %d\n",args.unentries); - for (i = 0; i < args.unentries; i++) - printf(" %d maps to %d\n", amp->info_umapdata[i][0], - amp->info_umapdata[i][1]); + printf("umap_mount:nentries %d\n",args.nentries); + for (i = 0; i < args.nentries; i++) + printf(" %ld maps to %ld\n", amp->info_mapdata[i][0], + amp->info_mapdata[i][1]); #endif error = copyin(args.gmapdata, (caddr_t)amp->info_gmapdata, - 2*sizeof(**amp->info_gmapdata)*args.gnentries); - if (error) + 2*sizeof(u_long)*args.gnentries); + if (error) { + vput(lowerrootvp); return (error); + } #ifdef UMAPFS_DIAGNOSTIC printf("umap_mount:gnentries %d\n",args.gnentries); for (i = 0; i < args.gnentries; i++) - printf(" group %d maps to %d\n", + printf("\tgroup %ld maps to %ld\n", amp->info_gmapdata[i][0], amp->info_gmapdata[i][1]); #endif - /* - * Save reference. Each mount also holds - * a reference on the root vnode. + * Make sure the mount point's sufficiently initialized + * that the node create call will work. */ - error = umap_node_create(mp, lowerrootvp, &vp); + vfs_getnewfsid(mp); + amp->umapm_size = sizeof(struct umap_node); + amp->umapm_tag = VT_UMAP; + amp->umapm_bypass = umap_bypass; + amp->umapm_alloc = layer_node_alloc; /* the default alloc is fine */ + amp->umapm_vnodeop_p = umap_vnodeop_p; + simple_lock_init(&->umapm_hashlock); + amp->umapm_node_hashtbl = hashinit(NUMAPNODECACHE, M_CACHE, + M_WAITOK, &->umapm_node_hash); + + /* - * Unlock the node (either the lower or the alias) + * fix up umap node for root vnode. */ - VOP_UNLOCK(vp, 0, p); + error = layer_node_create(mp, lowerrootvp, &vp); /* * Make sure the node alias worked */ if (error) { - vrele(lowerrootvp); + vput(lowerrootvp); free(amp, M_UFSMNT); /* XXX */ return (error); } + /* + * Unlock the node (either the lower or the alias) + */ + VOP_UNLOCK(vp, 0, p); /* * Keep a held reference to the root vnode. * It is vrele'd in umapfs_unmount. */ - umapm_rootvp = vp; - umapm_rootvp->v_flag |= VROOT; - amp->umapm_rootvp = umapm_rootvp; - if (UMAPVPTOLOWERVP(umapm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) - mp->mnt_flag |= MNT_LOCAL; - mp->mnt_data = (qaddr_t) amp; - vfs_getnewfsid(mp); + vp->v_flag |= VROOT; + amp->umapm_rootvp = vp; (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); - bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); - (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, - &size); - bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); + memset(mp->mnt_stat.f_mntonname + size, 0, MNAMELEN - size); + (void) copyinstr(args.umap_target, mp->mnt_stat.f_mntfromname, + MNAMELEN - 1, &size); + memset(mp->mnt_stat.f_mntfromname + size, 0, MNAMELEN - size); #ifdef UMAPFS_DIAGNOSTIC printf("umapfs_mount: lower %s, alias at %s\n", mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); @@ -227,21 +244,6 @@ } /* - * VFS start. Nothing needed here - the start routine - * on the underlying filesystem will have been called - * when that filesystem was mounted. - */ -int -umapfs_start(mp, flags, p) - struct mount *mp; - int flags; - struct proc *p; -{ - - return (0); -} - -/* * Free reference to umap layer */ int @@ -250,7 +252,7 @@ int mntflags; struct proc *p; { - struct vnode *umapm_rootvp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp; + struct vnode *rootvp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp; int error; int flags = 0; @@ -258,9 +260,8 @@ printf("umapfs_unmount(mp = %p)\n", mp); #endif - if (mntflags & MNT_FORCE) { + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } /* * Clear out buffer cache. I don't think we @@ -272,22 +273,22 @@ if (mntinvalbuf(mp, 1)) return (EBUSY); #endif - if (umapm_rootvp->v_usecount > 1 && !(flags & FORCECLOSE)) + if (rootvp->v_usecount > 1) return (EBUSY); - if ((error = vflush(mp, umapm_rootvp, flags)) != 0) + if ((error = vflush(mp, rootvp, flags)) != 0) return (error); #ifdef UMAPFS_DIAGNOSTIC - vprint("alias root of lower", umapm_rootvp); + vprint("alias root of lower", rootvp); #endif /* * Release reference on underlying root vnode */ - vrele(umapm_rootvp); + vrele(rootvp); /* * And blow it away for future re-use */ - vgone(umapm_rootvp); + vgone(rootvp); /* * Finally, throw away the umap_mount structure */ @@ -296,138 +297,25 @@ return (0); } -int -umapfs_root(mp, vpp) - struct mount *mp; - struct vnode **vpp; -{ - struct proc *p = curproc; - struct vnode *vp; - -#ifdef UMAPFS_DIAGNOSTIC - printf("umapfs_root(mp = %p, vp = %p->%p)\n", mp, - MOUNTTOUMAPMOUNT(mp)->umapm_rootvp, - UMAPVPTOLOWERVP(MOUNTTOUMAPMOUNT(mp)->umapm_rootvp) - ); -#endif - - /* - * Return locked reference to root. - */ - vp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp; - VREF(vp); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - *vpp = vp; - return (0); -} - -int -umapfs_quotactl(mp, cmd, uid, arg, p) - struct mount *mp; - int cmd; - uid_t uid; - caddr_t arg; - struct proc *p; -{ - return VFS_QUOTACTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd, uid, arg, p); -} - -int -umapfs_statfs(mp, sbp, p) - struct mount *mp; - struct statfs *sbp; - struct proc *p; -{ - int error; - struct statfs mstat; - -#ifdef UMAPFS_DIAGNOSTIC - printf("umapfs_statfs(mp = %p, vp = %p->%p)\n", mp, - MOUNTTOUMAPMOUNT(mp)->umapm_rootvp, - UMAPVPTOLOWERVP(MOUNTTOUMAPMOUNT(mp)->umapm_rootvp) - ); -#endif - - bzero(&mstat, sizeof(mstat)); - - error = VFS_STATFS(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, &mstat, p); - if (error) - return (error); - - /* now copy across the "interesting" information and fake the rest */ - sbp->f_flags = mstat.f_flags; - sbp->f_bsize = mstat.f_bsize; - sbp->f_iosize = mstat.f_iosize; - sbp->f_blocks = mstat.f_blocks; - sbp->f_bfree = mstat.f_bfree; - sbp->f_bavail = mstat.f_bavail; - sbp->f_files = mstat.f_files; - sbp->f_ffree = mstat.f_ffree; - if (sbp != &mp->mnt_stat) { - bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); - bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); - } - strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); - return (0); -} - -int -umapfs_sync(mp, waitfor, cred, p) - struct mount *mp; - int waitfor; - struct ucred *cred; - struct proc *p; -{ - /* - * XXX - Assumes no data cached at umap layer. - */ - return (0); -} - -int -umapfs_vget(mp, ino, vpp) - struct mount *mp; - ino_t ino; - struct vnode **vpp; -{ - return VFS_VGET(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, ino, vpp); -} - -int -umapfs_fhtovp(mp, fidp, vpp) - struct mount *mp; - struct fid *fidp; - struct vnode **vpp; -{ - return VFS_FHTOVP(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, fidp, vpp); -} - -int -umapfs_vptofh(vp, fhp) - struct vnode *vp; - struct fid *fhp; -{ - return VFS_VPTOFH(UMAPVPTOLOWERVP(vp), fhp); -} +extern const struct vnodeopv_desc umapfs_vnodeop_opv_desc; -#define umapfs_sysctl ((int (*)(int *, u_int, void *, size_t *, void *, \ - size_t, struct proc *))eopnotsupp) -#define umapfs_checkexp ((int (*)(struct mount *, struct mbuf *, \ - int *, struct ucred **))eopnotsupp) +const struct vnodeopv_desc * const umapfs_vnodeopv_descs[] = { + &umapfs_vnodeop_opv_desc, + NULL, +}; -struct vfsops umap_vfsops = { +struct vfsops umapfs_vfsops = { umapfs_mount, - umapfs_start, + layerfs_start, umapfs_unmount, - umapfs_root, - umapfs_quotactl, - umapfs_statfs, - umapfs_sync, - umapfs_vget, - umapfs_fhtovp, - umapfs_vptofh, - umapfs_init, - umapfs_sysctl, - umapfs_checkexp + layerfs_root, + layerfs_quotactl, + layerfs_statfs, + layerfs_sync, + layerfs_vget, + layerfs_fhtovp, + layerfs_vptofh, + layerfs_init, + layerfs_sysctl, + layerfs_checkexp, }; diff -ruN /backup/src.old/sys/miscfs/umapfs/umap_vnops.c sys/miscfs/umapfs/umap_vnops.c --- /backup/src.old/sys/miscfs/umapfs/umap_vnops.c Mon Dec 9 21:34:21 2002 +++ sys/miscfs/umapfs/umap_vnops.c Mon Dec 9 21:39:16 2002 @@ -1,5 +1,4 @@ -/* $OpenBSD: umap_vnops.c,v 1.15 2002/06/23 03:07:22 deraadt Exp $ */ -/* $NetBSD: umap_vnops.c,v 1.5.4.1 1996/05/25 22:13:35 jtc Exp $ */ +/* $NetBSD: umap_vnops.c,v 1.22 2002/01/04 07:19:34 chs Exp $ */ /* * Copyright (c) 1992, 1993 @@ -36,38 +35,30 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)umap_vnops.c 8.3 (Berkeley) 1/5/94 + * @(#)umap_vnops.c 8.6 (Berkeley) 5/22/95 */ /* * Umap Layer */ + #include #include #include -#include #include #include #include #include #include -#include #include +#include +#include - -int umap_bug_bypass = 0; /* for debugging: enables bypass printf'ing */ - -int umap_bypass(void *); +int umap_lookup(void *); int umap_getattr(void *); -int umap_inactive(void *); -int umap_reclaim(void *); int umap_print(void *); int umap_rename(void *); -int umap_strategy(void *); -int umap_bwrite(void *); -int umap_unlock(void *); -int umap_lock(void *); /* * Global vfs data structures @@ -79,26 +70,34 @@ */ int (**umap_vnodeop_p)(void *); struct vnodeopv_entry_desc umap_vnodeop_entries[] = { - { &vop_default_desc, umap_bypass }, - - { &vop_getattr_desc, umap_getattr }, - { &vop_inactive_desc, umap_inactive }, - { &vop_reclaim_desc, umap_reclaim }, - { &vop_print_desc, umap_print }, - { &vop_rename_desc, umap_rename }, - { &vop_lock_desc, umap_lock }, - { &vop_unlock_desc, umap_unlock }, - { &vop_strategy_desc, umap_strategy }, - { &vop_bwrite_desc, umap_bwrite }, + { &vop_default_desc, umap_bypass }, + { &vop_lookup_desc, umap_lookup }, + { &vop_getattr_desc, umap_getattr }, + { &vop_print_desc, umap_print }, + { &vop_rename_desc, umap_rename }, + + { &vop_lock_desc, layer_lock }, + { &vop_unlock_desc, layer_unlock }, + { &vop_islocked_desc, layer_islocked }, + { &vop_fsync_desc, layer_fsync }, + { &vop_inactive_desc, layer_inactive }, + { &vop_reclaim_desc, layer_reclaim }, + { &vop_open_desc, layer_open }, + { &vop_setattr_desc, layer_setattr }, + { &vop_access_desc, layer_access }, + + { &vop_strategy_desc, layer_strategy }, + { &vop_bwrite_desc, layer_bwrite }, + { &vop_bmap_desc, layer_bmap }, { NULL, NULL } }; -struct vnodeopv_desc umap_vnodeop_opv_desc = +const struct vnodeopv_desc umapfs_vnodeop_opv_desc = { &umap_vnodeop_p, umap_vnodeop_entries }; /* - * This is the 10-Apr-92 bypass routine. - * See null_vnops.c:null_bypass for more details. + * This is the 08-June-1999 bypass routine. + * See layer_vnops.c:layer_bypass for more details. */ int umap_bypass(v) @@ -112,26 +111,31 @@ struct ucred *savecredp = 0, *savecompcredp = 0; struct ucred *compcredp = 0; struct vnode **this_vp_p; - int error = 0; - struct vnode *old_vps[VDESC_MAX_VPS]; - struct vnode *vp1 = 0; + int error, error1; + int (**our_vnodeop_p)(void *); + struct vnode *old_vps[VDESC_MAX_VPS], *vp0; struct vnode **vps_p[VDESC_MAX_VPS]; struct vnode ***vppp; struct vnodeop_desc *descp = ap->a_desc; - int reles, i; + int reles, i, flags; struct componentname **compnamepp = 0; - if (umap_bug_bypass) - printf ("umap_bypass: %s\n", descp->vdesc_name); - #ifdef SAFETY /* * We require at least one vp. */ if (descp->vdesc_vp_offsets == NULL || descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET) - panic ("umap_bypass: no vp's in map."); + panic ("umap_bypass: no vp's in map.\n"); #endif + vps_p[0] = VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[0], + ap); + vp0 = *vps_p[0]; + flags = MOUNTTOUMAPMOUNT(vp0->v_mount)->umapm_flags; + our_vnodeop_p = vp0->v_op; + + if (flags & LAYERFS_MBYPASSDEBUG) + printf("umap_bypass: %s\n", descp->vdesc_name); /* * Map the vnodes going in. @@ -145,18 +149,14 @@ vps_p[i] = this_vp_p = VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[i], ap); - if (i == 0) { - vp1 = *vps_p[0]; - } - /* * We're not guaranteed that any but the first vnode * are of our type. Check for and don't map any * that aren't. (Must map first vp or vclean fails.) */ - if (i && (*this_vp_p == NULLVP || - (*this_vp_p)->v_op != umap_vnodeop_p)) { + if (i && ((*this_vp_p)==NULL || + (*this_vp_p)->v_op != our_vnodeop_p)) { old_vps[i] = NULL; } else { old_vps[i] = *this_vp_p; @@ -171,26 +171,28 @@ * Fix the credentials. (That's the purpose of this layer.) */ - if (descp->vdesc_cred_offset != VDESC_NO_OFFSET - && *(credpp = VOPARG_OFFSETTO(struct ucred**, - descp->vdesc_cred_offset, ap)) != NOCRED ) { + if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) { + + credpp = VOPARG_OFFSETTO(struct ucred**, + descp->vdesc_cred_offset, ap); /* Save old values */ savecredp = *credpp; - *credpp = crdup(savecredp); + if (savecredp != NOCRED) + *credpp = crdup(savecredp); credp = *credpp; - if (umap_bug_bypass && credp->cr_uid != 0) - printf("umap_bypass: user was %u, group %u\n", + if ((flags & LAYERFS_MBYPASSDEBUG) && credp->cr_uid != 0) + printf("umap_bypass: user was %d, group %d\n", credp->cr_uid, credp->cr_gid); /* Map all ids in the credential structure. */ - umap_mapids(vp1->v_mount, credp); + umap_mapids(vp0->v_mount, credp); - if (umap_bug_bypass && credp->cr_uid != 0) - printf("umap_bypass: user now %u, group %u\n", + if ((flags & LAYERFS_MBYPASSDEBUG) && credp->cr_uid != 0) + printf("umap_bypass: user now %d, group %d\n", credp->cr_uid, credp->cr_gid); } @@ -198,24 +200,26 @@ * for speed. If there is one, it better get mapped, too. */ - if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET - && (*(compnamepp = VOPARG_OFFSETTO(struct componentname**, - descp->vdesc_componentname_offset, ap)))->cn_cred != NOCRED ) { + if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) { + + compnamepp = VOPARG_OFFSETTO(struct componentname**, + descp->vdesc_componentname_offset, ap); savecompcredp = (*compnamepp)->cn_cred; - (*compnamepp)->cn_cred = crdup(savecompcredp); + if (savecompcredp != NOCRED) + (*compnamepp)->cn_cred = crdup(savecompcredp); compcredp = (*compnamepp)->cn_cred; - if (umap_bug_bypass && compcredp->cr_uid != 0) - printf("umap_bypass: component credit user was %u, group %u\n", + if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp->cr_uid != 0) + printf("umap_bypass: component credit user was %d, group %d\n", compcredp->cr_uid, compcredp->cr_gid); /* Map all ids in the credential structure. */ - umap_mapids(vp1->v_mount, compcredp); + umap_mapids(vp0->v_mount, compcredp); - if (umap_bug_bypass && compcredp->cr_uid != 0) - printf("umap_bypass: component credit user now %u, group %u\n", + if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp->cr_uid != 0) + printf("umap_bypass: component credit user now %d, group %d\n", compcredp->cr_uid, compcredp->cr_gid); } @@ -234,12 +238,14 @@ for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) break; /* bail out at end of list */ - if (old_vps[i] != NULLVP) { + if (old_vps[i]) { *(vps_p[i]) = old_vps[i]; - if (reles & 1) + if (reles & VDESC_VP0_WILLUNLOCK) + LAYERFS_UPPERUNLOCK(*(vps_p[i]), 0, error1); + if (reles & VDESC_VP0_WILLRELE) vrele(*(vps_p[i])); - }; - }; + } + } /* * Map the possible out-going vpp @@ -249,47 +255,151 @@ if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET && !(descp->vdesc_flags & VDESC_NOMAP_VPP) && !error) { - if (!(descp->vdesc_flags & VDESC_VPP_WILLRELE)) { - vppp = VOPARG_OFFSETTO(struct vnode***, - descp->vdesc_vpp_offset, ap); - error = umap_node_create(old_vps[0]->v_mount, - **vppp, *vppp); + if (descp->vdesc_flags & VDESC_VPP_WILLRELE) + goto out; + vppp = VOPARG_OFFSETTO(struct vnode***, + descp->vdesc_vpp_offset, ap); + error = layer_node_create(old_vps[0]->v_mount, **vppp, *vppp); + } + + out: + /* + * Free duplicate cred structure and restore old one. + */ + if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) { + if ((flags & LAYERFS_MBYPASSDEBUG) && credp && + credp->cr_uid != 0) + printf("umap_bypass: returning-user was %d\n", + credp->cr_uid); + + if (savecredp != NOCRED) { + crfree(credp); + *credpp = savecredp; + if ((flags & LAYERFS_MBYPASSDEBUG) && credpp && + (*credpp)->cr_uid != 0) + printf("umap_bypass: returning-user now %d\n\n", + savecredp->cr_uid); + } + } + + if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) { + if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp && + compcredp->cr_uid != 0) + printf("umap_bypass: returning-component-user was %d\n", + compcredp->cr_uid); + + if (savecompcredp != NOCRED) { + crfree(compcredp); + (*compnamepp)->cn_cred = savecompcredp; + if ((flags & LAYERFS_MBYPASSDEBUG) && savecompcredp && + savecompcredp->cr_uid != 0) + printf("umap_bypass: returning-component-user now %d\n", + savecompcredp->cr_uid); } } + return (error); +} + +/* + * This is based on the 08-June-1999 bypass routine. + * See layer_vnops.c:layer_bypass for more details. + */ +int +umap_lookup(v) + void *v; +{ + struct vop_lookup_args /* { + struct vnodeop_desc *a_desc; + struct vnode * a_dvp; + struct vnode ** a_vpp; + struct componentname * a_cnp; + } */ *ap = v; + struct componentname *cnp = ap->a_cnp; + struct ucred *savecompcredp = NULL; + struct ucred *compcredp = NULL; + struct vnode *dvp, *vp, *ldvp; + struct mount *mp; + int error; + int i, flags, cnf = cnp->cn_flags; + + dvp = ap->a_dvp; + mp = dvp->v_mount; + + if ((cnf & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && + (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) + return (EROFS); + + flags = MOUNTTOUMAPMOUNT(mp)->umapm_flags; + ldvp = UMAPVPTOLOWERVP(dvp); + + if (flags & LAYERFS_MBYPASSDEBUG) + printf("umap_lookup\n"); + + /* + * Fix the credentials. (That's the purpose of this layer.) + * + * BSD often keeps a credential in the componentname structure + * for speed. If there is one, it better get mapped, too. + */ + + if ((savecompcredp = cnp->cn_cred)) { + compcredp = crdup(savecompcredp); + cnp->cn_cred = compcredp; + + if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp->cr_uid != 0) + printf("umap_lookup: component credit user was %d, group %d\n", + compcredp->cr_uid, compcredp->cr_gid); + + /* Map all ids in the credential structure. */ + umap_mapids(mp, compcredp); + } + + if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp->cr_uid != 0) + printf("umap_lookup: component credit user now %d, group %d\n", + compcredp->cr_uid, compcredp->cr_gid); + + ap->a_dvp = ldvp; + error = VCALL(ldvp, ap->a_desc->vdesc_offset, ap); + vp = *ap->a_vpp; + + if (error == EJUSTRETURN && (cnf & ISLASTCN) && + (dvp->v_mount->mnt_flag & MNT_RDONLY) && + (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)) + error = EROFS; + + /* Do locking fixup as appropriate. See layer_lookup() for info */ + if ((cnp->cn_flags & PDIRUNLOCK)) { + LAYERFS_UPPERUNLOCK(dvp, 0, i); + } + if (ldvp == vp) { + *ap->a_vpp = dvp; + VREF(dvp); + vrele(vp); + } else if (vp != NULL) { + error = layer_node_create(mp, vp, ap->a_vpp); + } + /* * Free duplicate cred structure and restore old one. */ - if (descp->vdesc_cred_offset != VDESC_NO_OFFSET - && *credpp != NOCRED) { - if (umap_bug_bypass && credp && credp->cr_uid != 0) - printf("umap_bypass: returning-user was %u\n", - credp->cr_uid); - - crfree(credp); - *credpp = savecredp; - if (umap_bug_bypass && credpp && (*credpp)->cr_uid != 0) - printf("umap_bypass: returning-user now %u\n\n", - savecredp->cr_uid); - } - - if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET - && savecompcredp != NOCRED ) { - if (umap_bug_bypass && compcredp && compcredp->cr_uid != 0) - printf("umap_bypass: returning-component-user was %u\n", - compcredp->cr_uid); + if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp && + compcredp->cr_uid != 0) + printf("umap_lookup: returning-component-user was %d\n", + compcredp->cr_uid); + if (savecompcredp != NOCRED) { crfree(compcredp); - (*compnamepp)->cn_cred = savecompcredp; - if (umap_bug_bypass && credpp && (*credpp)->cr_uid != 0) - printf("umap_bypass: returning-component-user now %u\n", + cnp->cn_cred = savecompcredp; + if ((flags & LAYERFS_MBYPASSDEBUG) && savecompcredp && + savecompcredp->cr_uid != 0) + printf("umap_lookup: returning-component-user now %d\n", savecompcredp->cr_uid); } return (error); } - /* * We handle getattr to change the fsid. */ @@ -303,18 +413,20 @@ struct ucred *a_cred; struct proc *a_p; } */ *ap = v; - uid_t uid; - gid_t gid; - int error, tmpid, unentries, gnentries; - id_map_t umapdata, gmapdata; - struct vnode **vp1p; - struct vnodeop_desc *descp = ap->a_desc; + uid_t uid; + gid_t gid; + int error, tmpid, nentries, gnentries, flags; + u_long (*mapdata)[2]; + u_long (*gmapdata)[2]; + struct vnode **vp1p; + const struct vnodeop_desc *descp = ap->a_desc; if ((error = umap_bypass(ap)) != 0) return (error); /* Requires that arguments be restored. */ ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; + flags = MOUNTTOUMAPMOUNT(ap->a_vp->v_mount)->umapm_flags; /* * Umap needs to map the uid and gid returned by a stat * into the proper values for this site. This involves @@ -330,25 +442,25 @@ uid = ap->a_vap->va_uid; gid = ap->a_vap->va_gid; - if (umap_bug_bypass) - printf("umap_getattr: mapped uid = %u, mapped gid = %u\n", uid, + if ((flags & LAYERFS_MBYPASSDEBUG)) + printf("umap_getattr: mapped uid = %d, mapped gid = %d\n", uid, gid); vp1p = VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[0], ap); - unentries = MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_unentries; - umapdata = (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_umapdata); + nentries = MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_nentries; + mapdata = (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_mapdata); gnentries = MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gnentries; - gmapdata = (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gmapdata); + gmapdata = (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gmapdata); /* Reverse map the uid for the vnode. Since it's a reverse map, we can't use umap_mapids() to do it. */ - tmpid = umap_reverse_findid(uid, umapdata, unentries); + tmpid = umap_reverse_findid(uid, mapdata, nentries); if (tmpid != -1) { ap->a_vap->va_uid = (uid_t) tmpid; - if (umap_bug_bypass) - printf("umap_getattr: original uid = %u\n", uid); + if ((flags & LAYERFS_MBYPASSDEBUG)) + printf("umap_getattr: original uid = %d\n", uid); } else ap->a_vap->va_uid = (uid_t) NOBODY; @@ -358,145 +470,14 @@ if (tmpid != -1) { ap->a_vap->va_gid = (gid_t) tmpid; - if (umap_bug_bypass) - printf("umap_getattr: original gid = %u\n", gid); + if ((flags & LAYERFS_MBYPASSDEBUG)) + printf("umap_getattr: original gid = %d\n", gid); } else ap->a_vap->va_gid = (gid_t) NULLGROUP; return (0); } -/*ARGSUSED*/ -int -umap_inactive(v) - void *v; -{ - struct vop_inactive_args /* { - struct vnode *a_vp; - struct proc *a_p; - } */ *ap = v; - /* - * Do nothing (and _don't_ bypass). - * Wait to vrele lowervp until reclaim, - * so that until then our umap_node is in the - * cache and reusable. - * - */ - VOP_UNLOCK(ap->a_vp, 0, ap->a_p); - return (0); -} - -/* - * We need to process our own vnode lock and then clear the - * interlock flag as it applies only to our vnode, not the - * vnodes below us on the stack. - */ -int -umap_lock(v) - void *v; -{ - struct vop_lock_args /* { - struct vnode *a_vp; - int a_flags; - struct proc *a_p; - } */ *ap = v; - -#if 0 - vop_generic_lock(ap); -#endif - if ((ap->a_flags & LK_TYPE_MASK) == LK_DRAIN) - return (0); - ap->a_flags &= ~LK_INTERLOCK; - return (umap_bypass(ap)); -} - -/* - * We need to process our own vnode unlock and then clear the - * interlock flag as it applies only to our vnode, not the - * vnodes below us on the stack. - */ -int -umap_unlock(v) - void *v; -{ - struct vop_unlock_args /* { - struct vnode *a_vp; - int a_flags; - struct proc *a_p; - } */ *ap = v; - -#if 0 - vop_generic_unlock(ap); -#endif - ap->a_flags &= ~LK_INTERLOCK; - return (umap_bypass(ap)); -} - - - -int -umap_reclaim(v) - void *v; -{ - struct vop_reclaim_args /* { - struct vnode *a_vp; - } */ *ap = v; - struct vnode *vp = ap->a_vp; - struct umap_node *xp = VTOUMAP(vp); - struct vnode *lowervp = xp->umap_lowervp; - - /* After this assignment, this node will not be re-used. */ - xp->umap_lowervp = NULL; - LIST_REMOVE(xp, umap_hash); - FREE(vp->v_data, M_TEMP); - vp->v_data = NULL; - vrele(lowervp); - return (0); -} - -int -umap_strategy(v) - void *v; -{ - struct vop_strategy_args /* { - struct buf *a_bp; - } */ *ap = v; - struct buf *bp = ap->a_bp; - int error; - struct vnode *savedvp; - - savedvp = bp->b_vp; - bp->b_vp = UMAPVPTOLOWERVP(bp->b_vp); - - error = VOP_STRATEGY(ap->a_bp); - - bp->b_vp = savedvp; - - return (error); -} - -int -umap_bwrite(v) - void *v; -{ - struct vop_bwrite_args /* { - struct buf *a_bp; - } */ *ap = v; - struct buf *bp = ap->a_bp; - int error; - struct vnode *savedvp; - - savedvp = bp->b_vp; - bp->b_vp = UMAPVPTOLOWERVP(bp->b_vp); - - error = VOP_BWRITE(ap->a_bp); - - bp->b_vp = savedvp; - - return (error); -} - - int umap_print(v) void *v; @@ -522,34 +503,35 @@ struct vnode *a_tvp; struct componentname *a_tcnp; } */ *ap = v; - int error; + int error, flags; struct componentname *compnamep; struct ucred *compcredp, *savecompcredp; struct vnode *vp; /* * Rename is irregular, having two componentname structures. - * We need to map the cred in the second structure, + * We need to map the cre in the second structure, * and then bypass takes care of the rest. */ vp = ap->a_fdvp; + flags = MOUNTTOUMAPMOUNT(vp->v_mount)->umapm_flags; compnamep = ap->a_tcnp; compcredp = compnamep->cn_cred; savecompcredp = compcredp; compcredp = compnamep->cn_cred = crdup(savecompcredp); - if (umap_bug_bypass && compcredp->cr_uid != 0) - printf("umap_rename: rename component credit user was %u, group %u\n", + if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp->cr_uid != 0) + printf("umap_rename: rename component credit user was %d, group %d\n", compcredp->cr_uid, compcredp->cr_gid); /* Map all ids in the credential structure. */ umap_mapids(vp->v_mount, compcredp); - if (umap_bug_bypass && compcredp->cr_uid != 0) - printf("umap_rename: rename component credit user now %u, group %u\n", + if ((flags & LAYERFS_MBYPASSDEBUG) && compcredp->cr_uid != 0) + printf("umap_rename: rename component credit user now %d, group %d\n", compcredp->cr_uid, compcredp->cr_gid); error = umap_bypass(ap); @@ -561,4 +543,3 @@ return error; } - diff -ruN /backup/src.old/sys/miscfs/union/union.h sys/miscfs/union/union.h --- /backup/src.old/sys/miscfs/union/union.h Mon Dec 9 21:34:21 2002 +++ sys/miscfs/union/union.h Mon Dec 9 21:39:16 2002 @@ -1,5 +1,4 @@ -/* $OpenBSD: union.h,v 1.7 2002/03/14 01:27:08 millert Exp $ */ -/* $NetBSD: union.h,v 1.9 1996/02/09 22:41:08 christos Exp $ */ +/* $NetBSD: union.h,v 1.13 2002/09/21 18:09:31 christos Exp $ */ /* * Copyright (c) 1994 The Regents of the University of California. @@ -40,8 +39,6 @@ * @(#)union.h 8.9 (Berkeley) 12/10/94 */ -struct vfsconf; - struct union_args { char *target; /* Target of loopback */ int mntflags; /* Options on the mount */ @@ -52,6 +49,9 @@ #define UNMNT_REPLACE 0x0003 /* Target replaces mount point */ #define UNMNT_OPMASK 0x0003 +#define UNMNT_BITS "\177\20" \ + "b\00above\0b\01below\0b\02replace" + struct union_mount { struct vnode *um_uppervp; struct vnode *um_lowervp; @@ -65,8 +65,8 @@ /* * DEFDIRMODE is the mode bits used to create a shadow directory. */ -#define UN_DIRMODE (S_IRWXU|S_IRWXG|S_IRWXO) -#define UN_FILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) +#define UN_DIRMODE (S_IRWXU|S_IRWXG|S_IRWXO) +#define UN_FILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /* * A cache of vnode references @@ -95,26 +95,27 @@ #define UN_ULOCK 0x04 /* Upper node is locked */ #define UN_KLOCK 0x08 /* Keep upper node locked on vput */ #define UN_CACHED 0x10 /* In union cache */ +#define UN_DRAINING 0x20 /* upper node lock is draining */ +#define UN_DRAINED 0x40 /* upper node lock is drained */ extern int union_allocvp(struct vnode **, struct mount *, - struct vnode *, struct vnode *, - struct componentname *, struct vnode *, - struct vnode *, int); + struct vnode *, struct vnode *, struct componentname *, + struct vnode *, struct vnode *, int); extern int union_copyfile(struct vnode *, struct vnode *, - struct ucred *, struct proc *); + struct ucred *, struct proc *); extern int union_copyup(struct union_node *, int, struct ucred *, - struct proc *); + struct proc *); extern void union_diruncache(struct union_node *); extern int union_dowhiteout(struct union_node *, struct ucred *, - struct proc *); + struct proc *); extern int union_mkshadow(struct union_mount *, struct vnode *, - struct componentname *, struct vnode **); + struct componentname *, struct vnode **); extern int union_mkwhiteout(struct union_mount *, struct vnode *, - struct componentname *, char *); + struct componentname *, char *); extern int union_vn_create(struct vnode **, struct union_node *, - struct proc *); + struct proc *); extern int union_cn_close(struct vnode *, int, struct ucred *, - struct proc *); + struct proc *); extern void union_removed_upper(struct union_node *un); extern struct vnode *union_lowervp(struct vnode *); extern void union_newlower(struct union_node *, struct vnode *); @@ -132,6 +133,7 @@ extern struct vfsops union_vfsops; int union_init(struct vfsconf *); +void union_done(void); int union_freevp(struct vnode *); #endif /* _KERNEL */ diff -ruN /backup/src.old/sys/miscfs/union/union_subr.c sys/miscfs/union/union_subr.c --- /backup/src.old/sys/miscfs/union/union_subr.c Mon Dec 9 21:34:21 2002 +++ sys/miscfs/union/union_subr.c Mon Dec 9 21:39:16 2002 @@ -1,5 +1,4 @@ -/* $OpenBSD: union_subr.c,v 1.12 2002/06/08 18:43:34 art Exp $ */ -/* $NetBSD: union_subr.c,v 1.18 1996/02/09 22:41:10 christos Exp $ */ +/* $NetBSD: union_subr.c,v 1.41 2001/11/10 13:33:45 lukem Exp $ */ /* * Copyright (c) 1994 Jan-Simon Pendry @@ -37,9 +36,10 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)union_subr.c 8.16 (Berkeley) 12/10/94 + * @(#)union_subr.c 8.20 (Berkeley) 5/20/95 */ + #include #include #include @@ -53,7 +53,9 @@ #include #include #include -#include /* for vnode_pager_setsize */ + +#include + #include #ifdef DIAGNOSTIC @@ -74,85 +76,32 @@ static void union_list_unlock(int); void union_updatevp(struct union_node *, struct vnode *, struct vnode *); static int union_relookup(struct union_mount *, struct vnode *, - struct vnode **, struct componentname *, - struct componentname *, char *, int); + struct vnode **, struct componentname *, + struct componentname *, const char *, int); int union_vn_close(struct vnode *, int, struct ucred *, struct proc *); static void union_dircache_r(struct vnode *, struct vnode ***, int *); struct vnode *union_dircache(struct vnode *, struct proc *); -/* - * This variable is used to hold a pointer to a function - * that is called from vfs_syscalls.c and vfs_syscalls_43.c - * - by keeping a pointer to the function we enable the real - * union filesystem code to replace the stub value provided - * by vfs_syscalls.c and thus vfs_syscalls.c no longer needs - * to know if UNION is built in, lkm'ed, or not even there. - */ -extern -int (*union_check_p)(struct proc *, struct vnode **, - struct file *, struct uio, int *); - -int union_check(struct proc *, struct vnode **, struct file *, - struct uio, int *); - -int union_check(p, vpp, fp, auio, error) - struct proc *p; - struct vnode **vpp; - struct file *fp; - struct uio auio; - int *error; -{ - if ((*vpp)->v_op == union_vnodeop_p) { - struct vnode *lvp; - - lvp = union_dircache(*vpp, p); - if (lvp != NULLVP) { - struct vattr va; - - /* - * If the directory is opaque, - * then don't show lower entries - */ - *error = VOP_GETATTR(*vpp, &va, fp->f_cred, p); - if (va.va_flags & OPAQUE) { - vput(lvp); - lvp = NULL; - } - } - - if (lvp != NULLVP) { - *error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); - VOP_UNLOCK(lvp, 0, p); - - if (*error) { - vrele(lvp); - return (0); - } - fp->f_data = (caddr_t) lvp; - fp->f_offset = 0; - *error = vn_close(*vpp, FREAD, fp->f_cred, p); - if (*error) - return (0); - *vpp = lvp; - return (1); - } - } - return (0); -}; - int -union_init(vfsp) - struct vfsconf *vfsp; +union_init(struct vfsconf *vfsp) { int i; for (i = 0; i < NHASH; i++) LIST_INIT(&unhead[i]); - bzero((caddr_t) unvplock, sizeof(unvplock)); - union_check_p = union_check; + memset((caddr_t) unvplock, 0, sizeof(unvplock)); return (0); } +/* + * Free global unionfs resources. + */ +void +union_done() +{ + /* Nothing */ +} + static int union_list_lock(ix) int ix; @@ -160,7 +109,7 @@ if (unvplock[ix] & UN_LOCKED) { unvplock[ix] |= UN_WANTED; - tsleep((caddr_t) &unvplock[ix], PINOD, "unlstlk", 0); + (void) tsleep(&unvplock[ix], PINOD, "unionlk", 0); return (1); } @@ -191,19 +140,26 @@ int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp); int nhash = UNION_HASH(uppervp, lowervp); int docache = (lowervp != NULLVP || uppervp != NULLVP); + int lhash, uhash; /* * Ensure locking is ordered from lower to higher * to avoid deadlocks. */ - if (nhash < ohash) - while (union_list_lock(nhash)) + if (nhash < ohash) { + lhash = nhash; + uhash = ohash; + } else { + lhash = ohash; + uhash = nhash; + } + + if (lhash != uhash) + while (union_list_lock(lhash)) continue; - while (union_list_lock(ohash)) + + while (union_list_lock(uhash)) continue; - if (nhash > ohash) - while (union_list_lock(nhash)) - continue; if (ohash != nhash || !docache) { if (un->un_flags & UN_CACHED) { @@ -299,8 +255,8 @@ if (sz != VNOVAL) { #ifdef UNION_DIAGNOSTIC - printf("union: %s size now %ld\n", - uppersz != VNOVAL ? "upper" : "lower", (long) sz); + printf("union: %s size now %qd\n", + uppersz != VNOVAL ? "upper" : "lower", sz); #endif uvm_vnp_setsize(vp, sz); } @@ -365,7 +321,7 @@ } /* detect the root vnode (and aliases) */ - vflag = 0; + vflag = VLAYER; if ((uppervp == um->um_uppervp) && ((lowervp == NULLVP) || lowervp == um->um_lowervp)) { if (lowervp == NULLVP) { @@ -410,8 +366,7 @@ (un->un_uppervp == uppervp || un->un_uppervp == NULLVP) && (UNIONTOV(un)->v_mount == mp)) { - if (vget(UNIONTOV(un), 0, - cnp ? cnp->cn_proc : NULL)) { + if (vget(UNIONTOV(un), 0, curproc)) { union_list_unlock(hash); goto loop; } @@ -453,7 +408,8 @@ if (un->un_flags & UN_LOCKED) { vrele(UNIONTOV(un)); un->un_flags |= UN_WANTED; - tsleep((caddr_t)un, PINOD, "unallvp", 0); + (void) tsleep(&un->un_flags, PINOD, + "unionalloc", 0); goto loop; } un->un_flags |= UN_LOCKED; @@ -498,7 +454,7 @@ un->un_hash = cnp->cn_hash; un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); - bcopy(cnp->cn_nameptr, un->un_path, + memcpy(un->un_path, cnp->cn_nameptr, cnp->cn_namelen); un->un_path[cnp->cn_namelen] = '\0'; VREF(dvp); @@ -540,6 +496,7 @@ M_TEMP, M_WAITOK); (*vpp)->v_flag |= vflag; + (*vpp)->v_vnlock = NULL; /* Make upper layers call VOP_LOCK */ if (uppervp) (*vpp)->v_type = uppervp->v_type; else @@ -567,7 +524,7 @@ if (cnp && (lowervp != NULLVP)) { un->un_hash = cnp->cn_hash; un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); - bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen); + memcpy(un->un_path, cnp->cn_nameptr, cnp->cn_namelen); un->un_path[cnp->cn_namelen] = '\0'; VREF(dvp); un->un_dirvp = dvp; @@ -649,12 +606,12 @@ uio.uio_segflg = UIO_SYSSPACE; uio.uio_offset = 0; - VOP_UNLOCK(fvp, 0, p); /* XXX */ + VOP_UNLOCK(fvp, 0, p); /* XXX */ VOP_LEASE(fvp, p, cred, LEASE_READ); - vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p); - VOP_UNLOCK(tvp, 0, p); /* XXX */ + vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ + VOP_UNLOCK(tvp, 0, p); /* XXX */ VOP_LEASE(tvp, p, cred, LEASE_WRITE); - vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p); + vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK); @@ -706,6 +663,7 @@ { int error; struct vnode *lvp, *uvp; + struct vattr lvattr, uvattr; error = union_vn_create(&uvp, un, p); if (error) @@ -723,179 +681,190 @@ * from VOP_CLOSE */ vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, p); - error = VOP_OPEN(lvp, FREAD, cred, p); + + error = VOP_GETATTR(lvp, &lvattr, cred, p); + if (error == 0) + error = VOP_OPEN(lvp, FREAD, cred, p); if (error == 0) { error = union_copyfile(lvp, uvp, cred, p); - VOP_UNLOCK(lvp, 0, p); (void) VOP_CLOSE(lvp, FREAD, cred, p); } + if (error == 0) { + /* Copy permissions up too */ + VATTR_NULL(&uvattr); + uvattr.va_mode = lvattr.va_mode; + uvattr.va_flags = lvattr.va_flags; + error = VOP_SETATTR(uvp, &uvattr, cred, p); + } + VOP_UNLOCK(lvp, 0, p); #ifdef UNION_DIAGNOSTIC if (error == 0) uprintf("union: copied up %s\n", un->un_path); #endif } - un->un_flags &= ~UN_ULOCK; - VOP_UNLOCK(uvp, 0, p); union_vn_close(uvp, FWRITE, cred, p); - vn_lock(uvp, LK_EXCLUSIVE | LK_RETRY, p); - un->un_flags |= UN_ULOCK; - /* - * Subsequent IOs will go to the top layer, so - * call close on the lower vnode and open on the - * upper vnode to ensure that the filesystem keeps - * its references counts right. This doesn't do - * the right thing with (cred) and (FREAD) though. - * Ignoring error returns is not right, either. - */ - if (error == 0) { - int i; - - for (i = 0; i < un->un_openl; i++) { - (void) VOP_CLOSE(lvp, FREAD, cred, p); - (void) VOP_OPEN(uvp, FREAD, cred, p); - } - un->un_openl = 0; - } - - return (error); - - } - - static int - union_relookup(um, dvp, vpp, cnp, cn, path, pathlen) - struct union_mount *um; - struct vnode *dvp; - struct vnode **vpp; - struct componentname *cnp; - struct componentname *cn; - char *path; - int pathlen; - { - int error; - - /* - * A new componentname structure must be faked up because - * there is no way to know where the upper level cnp came - * from or what it is being used for. This must duplicate - * some of the work done by NDINIT, some of the work done - * by namei, some of the work done by lookup and some of - * the work done by VOP_LOOKUP when given a CREATE flag. - * Conclusion: Horrible. - * - * The pathname buffer will be FREEed by VOP_MKDIR. - */ - cn->cn_namelen = pathlen; - cn->cn_pnbuf = malloc(cn->cn_namelen+1, M_NAMEI, M_WAITOK); - bcopy(path, cn->cn_pnbuf, cn->cn_namelen); - cn->cn_pnbuf[cn->cn_namelen] = '\0'; - - cn->cn_nameiop = CREATE; - cn->cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN); - cn->cn_proc = cnp->cn_proc; - if (um->um_op == UNMNT_ABOVE) - cn->cn_cred = cnp->cn_cred; - else - cn->cn_cred = um->um_cred; - cn->cn_nameptr = cn->cn_pnbuf; - cn->cn_hash = cnp->cn_hash; - cn->cn_consume = cnp->cn_consume; - - VREF(dvp); - error = relookup(dvp, vpp, cn); - if (!error) - vrele(dvp); - else { - free(cn->cn_pnbuf, M_NAMEI); - cn->cn_pnbuf = 0; - } - - return (error); - } - - /* - * Create a shadow directory in the upper layer. - * The new vnode is returned locked. - * - * (um) points to the union mount structure for access to the - * the mounting process's credentials. - * (dvp) is the directory in which to create the shadow directory. - * it is unlocked on entry and exit. - * (cnp) is the componentname to be created. - * (vpp) is the returned newly created shadow directory, which - * is returned locked. - */ - int - union_mkshadow(um, dvp, cnp, vpp) - struct union_mount *um; - struct vnode *dvp; - struct componentname *cnp; - struct vnode **vpp; - { - int error; - struct vattr va; - struct proc *p = cnp->cn_proc; - struct componentname cn; - - error = union_relookup(um, dvp, vpp, cnp, &cn, - cnp->cn_nameptr, cnp->cn_namelen); - if (error) - return (error); - - if (*vpp) { - VOP_ABORTOP(dvp, &cn); - VOP_UNLOCK(dvp, 0, p); - vrele(*vpp); - *vpp = NULLVP; - return (EEXIST); - } - - /* - * policy: when creating the shadow directory in the - * upper layer, create it owned by the user who did - * the mount, group from parent directory, and mode - * 777 modified by umask (ie mostly identical to the - * mkdir syscall). (jsp, kb) - */ - - VATTR_NULL(&va); - va.va_type = VDIR; - va.va_mode = um->um_cmode; - - /* VOP_LEASE: dvp is locked */ - VOP_LEASE(dvp, p, cn.cn_cred, LEASE_WRITE); - - error = VOP_MKDIR(dvp, vpp, &cn, &va); - return (error); - } - - /* - * Create a whiteout entry in the upper layer. - * - * (um) points to the union mount structure for access to the - * the mounting process's credentials. - * (dvp) is the directory in which to create the whiteout. - * it is locked on entry and exit. - * (cnp) is the componentname to be created. - */ - int - union_mkwhiteout(um, dvp, cnp, path) - struct union_mount *um; - struct vnode *dvp; - struct componentname *cnp; - char *path; - { - int error; - struct proc *p = cnp->cn_proc; - struct vnode *wvp; - struct componentname cn; - - VOP_UNLOCK(dvp, 0, p); - error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path)); - if (error) { - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); - return (error); + /* + * Subsequent IOs will go to the top layer, so + * call close on the lower vnode and open on the + * upper vnode to ensure that the filesystem keeps + * its references counts right. This doesn't do + * the right thing with (cred) and (FREAD) though. + * Ignoring error returns is not right, either. + */ + if (error == 0) { + int i; + + vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, p); + for (i = 0; i < un->un_openl; i++) { + (void) VOP_CLOSE(lvp, FREAD, cred, p); + (void) VOP_OPEN(uvp, FREAD, cred, p); + } + un->un_openl = 0; + VOP_UNLOCK(lvp, 0, p); + } + + return (error); + +} + +static int +union_relookup(um, dvp, vpp, cnp, cn, path, pathlen) + struct union_mount *um; + struct vnode *dvp; + struct vnode **vpp; + struct componentname *cnp; + struct componentname *cn; + const char *path; + int pathlen; +{ + int error; + + /* + * A new componentname structure must be faked up because + * there is no way to know where the upper level cnp came + * from or what it is being used for. This must duplicate + * some of the work done by NDINIT, some of the work done + * by namei, some of the work done by lookup and some of + * the work done by VOP_LOOKUP when given a CREATE flag. + * Conclusion: Horrible. + */ + cn->cn_namelen = pathlen; + if ((cn->cn_namelen + 1) > MAXPATHLEN) + return (ENAMETOOLONG); + cn->cn_pnbuf = (caddr_t) malloc(cn->cn_namelen+1, M_NAMEI, M_WAITOK); + memcpy(cn->cn_pnbuf, path, cn->cn_namelen); + cn->cn_pnbuf[cn->cn_namelen] = '\0'; + + cn->cn_nameiop = CREATE; + cn->cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN); + cn->cn_proc = cnp->cn_proc; + if (um->um_op == UNMNT_ABOVE) + cn->cn_cred = cnp->cn_cred; + else + cn->cn_cred = um->um_cred; + cn->cn_nameptr = cn->cn_pnbuf; + cn->cn_hash = cnp->cn_hash; + cn->cn_consume = cnp->cn_consume; + + VREF(dvp); + error = relookup(dvp, vpp, cn); + if (!error) + vrele(dvp); + else { + free(cn->cn_pnbuf, M_NAMEI); + cn->cn_pnbuf = 0; + } + + return (error); +} + +/* + * Create a shadow directory in the upper layer. + * The new vnode is returned locked. + * + * (um) points to the union mount structure for access to the + * the mounting process's credentials. + * (dvp) is the directory in which to create the shadow directory. + * it is unlocked on entry and exit. + * (cnp) is the componentname to be created. + * (vpp) is the returned newly created shadow directory, which + * is returned locked. + * + * N.B. We still attempt to create shadow directories even if the union + * is mounted read-only, which is a little nonintuitive. + */ +int +union_mkshadow(um, dvp, cnp, vpp) + struct union_mount *um; + struct vnode *dvp; + struct componentname *cnp; + struct vnode **vpp; +{ + int error; + struct vattr va; + struct proc *p = cnp->cn_proc; + struct componentname cn; + + error = union_relookup(um, dvp, vpp, cnp, &cn, + cnp->cn_nameptr, cnp->cn_namelen); + if (error) + return (error); + + if (*vpp) { + VOP_ABORTOP(dvp, &cn); + VOP_UNLOCK(dvp, 0, p); + vrele(*vpp); + *vpp = NULLVP; + return (EEXIST); + } + + /* + * policy: when creating the shadow directory in the + * upper layer, create it owned by the user who did + * the mount, group from parent directory, and mode + * 777 modified by umask (ie mostly identical to the + * mkdir syscall). (jsp, kb) + */ + + VATTR_NULL(&va); + va.va_type = VDIR; + va.va_mode = um->um_cmode; + + /* VOP_LEASE: dvp is locked */ + VOP_LEASE(dvp, p, cn.cn_cred, LEASE_WRITE); + + error = VOP_MKDIR(dvp, vpp, &cn, &va); + return (error); +} + +/* + * Create a whiteout entry in the upper layer. + * + * (um) points to the union mount structure for access to the + * the mounting process's credentials. + * (dvp) is the directory in which to create the whiteout. + * it is locked on entry and exit. + * (cnp) is the componentname to be created. + */ +int +union_mkwhiteout(um, dvp, cnp, path) + struct union_mount *um; + struct vnode *dvp; + struct componentname *cnp; + char *path; +{ + int error; + struct proc *p = cnp->cn_proc; + struct vnode *wvp; + struct componentname cn; + + VOP_UNLOCK(dvp, 0, p); + error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path)); + if (error) { + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); + return (error); } if (wvp) { @@ -952,8 +921,10 @@ * copied in the first place). */ cn.cn_namelen = strlen(un->un_path); + if ((cn.cn_namelen + 1) > MAXPATHLEN) + return (ENAMETOOLONG); cn.cn_pnbuf = (caddr_t) malloc(cn.cn_namelen+1, M_NAMEI, M_WAITOK); - bcopy(un->un_path, cn.cn_pnbuf, cn.cn_namelen+1); + memcpy(cn.cn_pnbuf, un->un_path, cn.cn_namelen+1); cn.cn_nameiop = CREATE; cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN); cn.cn_proc = p; @@ -1021,8 +992,7 @@ union_removed_upper(un) struct union_node *un; { - struct proc *p = curproc; - +#if 1 /* * We do not set the uppervp to NULLVP here, because lowervp * may also be NULLVP, so this routine would end up creating @@ -1033,6 +1003,9 @@ * release it, union_inactive() will vgone() it. */ union_diruncache(un); +#else + union_newupper(un, NULLVP); +#endif if (un->un_flags & UN_CACHED) { un->un_flags &= ~UN_CACHED; @@ -1041,7 +1014,7 @@ if (un->un_flags & UN_ULOCK) { un->un_flags &= ~UN_ULOCK; - VOP_UNLOCK(un->un_uppervp, 0, p); + VOP_UNLOCK(un->un_uppervp, 0, curproc); } } @@ -1125,6 +1098,9 @@ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); dircache = VTOUNION(vp)->un_dircache; + + nvp = NULLVP; + if (dircache == 0) { cnt = 0; union_dircache_r(vp, 0, &cnt); diff -ruN /backup/src.old/sys/miscfs/union/union_vfsops.c sys/miscfs/union/union_vfsops.c --- /backup/src.old/sys/miscfs/union/union_vfsops.c Mon Dec 9 21:34:21 2002 +++ sys/miscfs/union/union_vfsops.c Mon Dec 9 21:39:16 2002 @@ -1,5 +1,4 @@ -/* $OpenBSD: union_vfsops.c,v 1.13 2002/03/14 01:27:08 millert Exp $ */ -/* $NetBSD: union_vfsops.c,v 1.10 1995/06/18 14:47:47 cgd Exp $ */ +/* $NetBSD: union_vfsops.c,v 1.32 2002/09/21 18:09:31 christos Exp $ */ /* * Copyright (c) 1994 The Regents of the University of California. @@ -37,17 +36,17 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)union_vfsops.c 8.13 (Berkeley) 12/10/94 + * @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95 */ /* * Union Layer */ + #include #include #include -#include #include #include #include @@ -60,11 +59,20 @@ #include int union_mount(struct mount *, const char *, void *, struct nameidata *, - struct proc *); + struct proc *); int union_start(struct mount *, int, struct proc *); int union_unmount(struct mount *, int, struct proc *); int union_root(struct mount *, struct vnode **); +int union_quotactl(struct mount *, int, uid_t, caddr_t, struct proc *); int union_statfs(struct mount *, struct statfs *, struct proc *); +int union_sync(struct mount *, int, struct ucred *, struct proc *); +int union_vget(struct mount *, ino_t, struct vnode **); +int union_fhtovp(struct mount *, struct fid *, struct vnode **); +int union_checkexp(struct mount *, struct mbuf *, int *, + struct ucred **); +int union_vptofh(struct vnode *, struct fid *); +int union_sysctl(int *, u_int, void *, size_t *, void *, size_t, + struct proc *); /* * Mount union filesystem @@ -90,7 +98,16 @@ #ifdef UNION_DIAGNOSTIC printf("union_mount(mp = %p)\n", mp); #endif - +#if 0 + if (mp->mnt_flag & MNT_GETARGS) { + um = MOUNTTOUNIONMOUNT(mp); + if (um == NULL) + return EIO; + args.target = NULL; + args.mntflags = um->um_op; + return copyout(&args, data, sizeof(args)); + } +#endif /* * Update is a no-op */ @@ -107,7 +124,7 @@ /* * Get argument */ - error = copyin(data, &args, sizeof(struct union_args)); + error = copyin(data, (caddr_t)&args, sizeof(struct union_args)); if (error) goto bad; @@ -117,15 +134,13 @@ /* * Find upper node. */ - NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT, + NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.target, p); if ((error = namei(ndp)) != 0) goto bad; upperrootvp = ndp->ni_vp; - vrele(ndp->ni_dvp); - ndp->ni_dvp = NULL; if (upperrootvp->v_type != VDIR) { error = EINVAL; @@ -211,7 +226,7 @@ vfs_getnewfsid(mp); (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); - bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); + memset(mp->mnt_stat.f_mntonname + size, 0, MNAMELEN - size); switch (um->um_op) { case UNMNT_ABOVE: @@ -231,17 +246,17 @@ break; } len = strlen(cp); - bcopy(cp, mp->mnt_stat.f_mntfromname, len); + memcpy(mp->mnt_stat.f_mntfromname, cp, len); cp = mp->mnt_stat.f_mntfromname + len; len = MNAMELEN - len; (void) copyinstr(args.target, cp, len - 1, &size); - bzero(cp + size, len - size); + memset(cp + size, 0, len - size); #ifdef UNION_DIAGNOSTIC printf("union_mount: from %s, on %s\n", - mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); + mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); #endif return (0); @@ -273,18 +288,6 @@ return (0); } - -int union_unmount_count_vnode(struct vnode *vp, void *args); - -int -union_unmount_count_vnode(struct vnode *vp, void *args) { - int *n = args; - - *n = *n + 1; - simple_unlock(&vp->v_interlock); - return (0); -} - /* * Free reference to union layer */ @@ -298,16 +301,11 @@ struct vnode *um_rootvp; int error; int freeing; - int flags = 0; #ifdef UNION_DIAGNOSTIC printf("union_unmount(mp = %p)\n", mp); #endif - if (mntflags & MNT_FORCE) { - flags |= FORCECLOSE; - } - if ((error = union_root(mp, &um_rootvp)) != 0) return (error); @@ -320,11 +318,15 @@ * (d) times, where (d) is the maximum tree depth * in the filesystem. */ - for (freeing = 0; vflush(mp, um_rootvp, flags) != 0;) { + for (freeing = 0; vflush(mp, um_rootvp, 0) != 0;) { + struct vnode *vp; int n; /* count #vnodes held on mount list */ - vfs_mount_foreach_vnode(mp, union_unmount_count_vnode, &n); + for (n = 0, vp = mp->mnt_vnodelist.lh_first; + vp != NULLVP; + vp = vp->v_mntvnodes.le_next) + n++; /* if this is unchanged then stop */ if (n == freeing) @@ -334,6 +336,14 @@ freeing = n; } + /* + * Ok, now that we've tried doing it gently, get out the hammer. + */ + + if (mntflags & MNT_FORCE) + vflush(mp, um_rootvp, FORCECLOSE); + + /* At this point the root vnode should have a single reference */ if (um_rootvp->v_usecount > 1) { vput(um_rootvp); @@ -398,10 +408,9 @@ 1); if (error) { - if (loselock) - vrele(um->um_uppervp); - else - vput(um->um_uppervp); + if (!loselock) + VOP_UNLOCK(um->um_uppervp, 0, p); + vrele(um->um_uppervp); if (um->um_lowervp) vrele(um->um_lowervp); } else { @@ -412,6 +421,19 @@ return (error); } +/*ARGSUSED*/ +int +union_quotactl(mp, cmd, uid, arg, p) + struct mount *mp; + int cmd; + uid_t uid; + caddr_t arg; + struct proc *p; +{ + + return (EOPNOTSUPP); +} + int union_statfs(mp, sbp, p) struct mount *mp; @@ -425,11 +447,10 @@ #ifdef UNION_DIAGNOSTIC printf("union_statfs(mp = %p, lvp = %p, uvp = %p)\n", mp, - um->um_lowervp, - um->um_uppervp); + um->um_lowervp, um->um_uppervp); #endif - bzero(&mstat, sizeof(mstat)); + memset(&mstat, 0, sizeof(mstat)); if (um->um_lowervp) { error = VFS_STATFS(um->um_lowervp->v_mount, &mstat, p); @@ -438,17 +459,9 @@ } /* now copy across the "interesting" information and fake the rest */ -#if 0 - sbp->f_flags = mstat.f_flags; - sbp->f_bsize = mstat.f_bsize; - sbp->f_iosize = mstat.f_iosize; -#endif lbsize = mstat.f_bsize; - sbp->f_blocks = mstat.f_blocks; - sbp->f_bfree = mstat.f_bfree; - sbp->f_bavail = mstat.f_bavail; - sbp->f_files = mstat.f_files; - sbp->f_ffree = mstat.f_ffree; + sbp->f_blocks = mstat.f_blocks - mstat.f_bfree; + sbp->f_files = mstat.f_files - mstat.f_ffree; error = VFS_STATFS(um->um_uppervp->v_mount, &mstat, p); if (error) @@ -459,45 +472,107 @@ sbp->f_iosize = mstat.f_iosize; /* - * if the lower and upper blocksizes differ, then frig the - * block counts so that the sizes reported by df make some - * kind of sense. none of this makes sense though. + * The "total" fields count total resources in all layers, + * the "free" fields count only those resources which are + * free in the upper layer (since only the upper layer + * is writeable). */ - if (mstat.f_bsize != lbsize) { + if (mstat.f_bsize != lbsize) sbp->f_blocks = sbp->f_blocks * lbsize / mstat.f_bsize; - sbp->f_bfree = sbp->f_bfree * lbsize / mstat.f_bsize; - sbp->f_bavail = sbp->f_bavail * lbsize / mstat.f_bsize; - } sbp->f_blocks += mstat.f_blocks; - sbp->f_bfree += mstat.f_bfree; - sbp->f_bavail += mstat.f_bavail; + sbp->f_bfree = mstat.f_bfree; + sbp->f_bavail = mstat.f_bavail; sbp->f_files += mstat.f_files; - sbp->f_ffree += mstat.f_ffree; + sbp->f_ffree = mstat.f_ffree; if (sbp != &mp->mnt_stat) { - bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); - bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); + memcpy(&sbp->f_fsid, &mp->mnt_stat.f_fsid, sizeof(sbp->f_fsid)); + memcpy(sbp->f_mntonname, mp->mnt_stat.f_mntonname, MNAMELEN); + memcpy(sbp->f_mntfromname, mp->mnt_stat.f_mntfromname, MNAMELEN); } strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); return (0); } -#define union_sync ((int (*)(struct mount *, int, struct ucred *, \ - struct proc *))nullop) +/*ARGSUSED*/ +int +union_sync(mp, waitfor, cred, p) + struct mount *mp; + int waitfor; + struct ucred *cred; + struct proc *p; +{ + + /* + * XXX - Assumes no data cached at union layer. + */ + return (0); +} + +/*ARGSUSED*/ +int +union_vget(mp, ino, vpp) + struct mount *mp; + ino_t ino; + struct vnode **vpp; +{ + + return (EOPNOTSUPP); +} + +/*ARGSUSED*/ +int +union_fhtovp(mp, fidp, vpp) + struct mount *mp; + struct fid *fidp; + struct vnode **vpp; +{ + + return (EOPNOTSUPP); +} + +/*ARGSUSED*/ +int +union_checkexp(mp, nam, exflagsp, credanonp) + struct mount *mp; + struct mbuf *nam; + int *exflagsp; + struct ucred **credanonp; +{ + + return (EOPNOTSUPP); +} + +/*ARGSUSED*/ +int +union_vptofh(vp, fhp) + struct vnode *vp; + struct fid *fhp; +{ + + return (EOPNOTSUPP); +} + +int +union_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; + struct proc *p; +{ + return (EOPNOTSUPP); +} + +extern const struct vnodeopv_desc union_vnodeop_opv_desc; -#define union_fhtovp ((int (*)(struct mount *, struct fid *, \ - struct vnode **))eopnotsupp) -#define union_quotactl ((int (*)(struct mount *, int, uid_t, caddr_t, \ - struct proc *))eopnotsupp) -#define union_sysctl ((int (*)(int *, u_int, void *, size_t *, void *, \ - size_t, struct proc *))eopnotsupp) -#define union_vget ((int (*)(struct mount *, ino_t, struct vnode **)) \ - eopnotsupp) -#define union_vptofh ((int (*)(struct vnode *, struct fid *))eopnotsupp) -#define union_checkexp ((int (*)(struct mount *, struct mbuf *, \ - int *, struct ucred **))eopnotsupp) +const struct vnodeopv_desc * const union_vnodeopv_descs[] = { + &union_vnodeop_opv_desc, + NULL, +}; struct vfsops union_vfsops = { union_mount, @@ -512,5 +587,5 @@ union_vptofh, union_init, union_sysctl, - union_checkexp + union_checkexp, }; diff -ruN /backup/src.old/sys/miscfs/union/union_vnops.c sys/miscfs/union/union_vnops.c --- /backup/src.old/sys/miscfs/union/union_vnops.c Mon Dec 9 21:34:21 2002 +++ sys/miscfs/union/union_vnops.c Mon Dec 9 21:39:16 2002 @@ -1,10 +1,9 @@ -/* $OpenBSD: union_vnops.c,v 1.19 2002/06/08 18:43:34 art Exp $ */ -/* $NetBSD: union_vnops.c,v 1.30.4.1 1996/05/25 22:10:14 jtc Exp $ */ +/* $NetBSD: union_vnops.c,v 1.59 2002/09/27 15:37:48 provos Exp $ */ /* - * Copyright (c) 1992, 1993, 1994 The Regents of the University of California. - * Copyright (c) 1992, 1993, 1994 Jan-Simon Pendry. - * All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry. + * Copyright (c) 1992, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Jan-Simon Pendry. @@ -37,27 +36,25 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)union_vnops.c 8.22 (Berkeley) 12/10/94 + * @(#)union_vnops.c 8.33 (Berkeley) 7/31/95 */ + #include #include #include #include #include #include -#include #include #include #include #include #include #include +#include #include - -/* - * Global vfs data structures - */ +#include int union_lookup(void *); int union_create(void *); @@ -72,14 +69,16 @@ int union_write(void *); int union_lease(void *); int union_ioctl(void *); -int union_select(void *); +int union_poll(void *); +int union_revoke(void *); +int union_mmap(void *); int union_fsync(void *); +int union_seek(void *); int union_remove(void *); int union_link(void *); int union_rename(void *); int union_mkdir(void *); int union_rmdir(void *); -int union_revoke(void *); int union_symlink(void *); int union_readdir(void *); int union_readlink(void *); @@ -94,7 +93,17 @@ int union_pathconf(void *); int union_advlock(void *); int union_strategy(void *); +int union_getpages(void *); +int union_putpages(void *); + +static void union_fixup(struct union_node *); +static int union_lookup1 __P((struct vnode *, struct vnode **, + struct vnode **, struct componentname *)); + +/* + * Global vfs data structures + */ int (**union_vnodeop_p)(void *); struct vnodeopv_entry_desc union_vnodeop_entries[] = { { &vop_default_desc, vn_default_error }, @@ -111,8 +120,7 @@ { &vop_write_desc, union_write }, /* write */ { &vop_lease_desc, union_lease }, /* lease */ { &vop_ioctl_desc, union_ioctl }, /* ioctl */ - { &vop_select_desc, union_select }, /* select */ - { &vop_fsync_desc, union_fsync }, /* fsync */ + { &vop_revoke_desc, union_revoke }, /* revoke */ { &vop_remove_desc, union_remove }, /* remove */ { &vop_link_desc, union_link }, /* link */ { &vop_rename_desc, union_rename }, /* rename */ @@ -121,7 +129,6 @@ { &vop_symlink_desc, union_symlink }, /* symlink */ { &vop_readdir_desc, union_readdir }, /* readdir */ { &vop_readlink_desc, union_readlink }, /* readlink */ - { &vop_revoke_desc, union_revoke }, /* revoke */ { &vop_abortop_desc, union_abortop }, /* abortop */ { &vop_inactive_desc, union_inactive }, /* inactive */ { &vop_reclaim_desc, union_reclaim }, /* reclaim */ @@ -133,27 +140,31 @@ { &vop_islocked_desc, union_islocked }, /* islocked */ { &vop_pathconf_desc, union_pathconf }, /* pathconf */ { &vop_advlock_desc, union_advlock }, /* advlock */ - { (struct vnodeop_desc*)NULL, (int(*)(void *))NULL } +#ifdef notdef + { &vop_blkatoff_desc, union_blkatoff }, /* blkatoff */ + { &vop_valloc_desc, union_valloc }, /* valloc */ + { &vop_vfree_desc, union_vfree }, /* vfree */ + { &vop_truncate_desc, union_truncate }, /* truncate */ + { &vop_update_desc, union_update }, /* update */ + { &vop_bwrite_desc, union_bwrite }, /* bwrite */ +#endif + { NULL, NULL } }; -struct vnodeopv_desc union_vnodeop_opv_desc = +const struct vnodeopv_desc union_vnodeop_opv_desc = { &union_vnodeop_p, union_vnodeop_entries }; -#define FIXUP(un, p) { \ +#define FIXUP(un) { \ if (((un)->un_flags & UN_ULOCK) == 0) { \ - union_fixup(un, p); \ + union_fixup(un); \ } \ } -static void union_fixup(struct union_node *, struct proc *); -static int union_lookup1(struct vnode *, struct vnode **, - struct vnode **, struct componentname *); - static void -union_fixup(un, p) +union_fixup(un) struct union_node *un; - struct proc *p; { - vn_lock(un->un_uppervp, LK_EXCLUSIVE | LK_RETRY, p); + + vn_lock(un->un_uppervp, LK_EXCLUSIVE | LK_RETRY, curproc); un->un_flags |= UN_ULOCK; } @@ -218,16 +229,15 @@ if (vfs_busy(mp, 0, 0, p)) continue; - + error = VFS_ROOT(mp, &tdvp); vfs_unbusy(mp, p); - - vput(dvp); - if (error) { + vput(dvp); return (error); } + vput(dvp); dvp = tdvp; } @@ -270,11 +280,16 @@ VREF(dvp); vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); if (!lockparent || !(cnp->cn_flags & ISLASTCN)) - VOP_UNLOCK(ap->a_dvp, 0, p, 0, p); + VOP_UNLOCK(ap->a_dvp, 0, p); return (0); } #endif + if ((cnp->cn_flags & ISLASTCN) && + (dvp->v_mount->mnt_flag & MNT_RDONLY) && + (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) + return (EROFS); + cnp->cn_flags |= LOCKPARENT; upperdvp = dun->un_uppervp; @@ -290,7 +305,7 @@ * on and just return that vnode. */ if (upperdvp != NULLVP) { - FIXUP(dun, p); + FIXUP(dun); /* * If we're doing `..' in the underlying filesystem, * we must drop our lock on the union node before @@ -300,18 +315,19 @@ * we would be hosed. */ if (cnp->cn_flags & ISDOTDOT) { - /* retain lock on underlying VP: */ + /* retain lock on underlying VP */ dun->un_flags |= UN_KLOCK; VOP_UNLOCK(dvp, 0, p); } uerror = union_lookup1(um->um_uppervp, &upperdvp, &uppervp, cnp); + if (cnp->cn_flags & ISDOTDOT) { if (dun->un_uppervp == upperdvp) { /* * we got the underlying bugger back locked... * now take back the union node lock. Since we - * hold the uppervp lock, we can diddle union + * hold the uppervp lock, we can diddle union * locking flags at will. :) */ dun->un_flags |= UN_ULOCK; @@ -324,10 +340,6 @@ */ vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); } - - /*if (uppervp == upperdvp) - dun->un_flags |= UN_KLOCK;*/ - if (cnp->cn_consume != 0) { *ap->a_vpp = uppervp; if (!lockparent) @@ -339,8 +351,7 @@ iswhiteout = 1; } else if (lowerdvp != NULLVP) { lerror = VOP_GETATTR(upperdvp, &va, - cnp->cn_cred, - cnp->cn_proc); + cnp->cn_cred, cnp->cn_proc); if (lerror == 0 && (va.va_flags & OPAQUE)) iswhiteout = 1; } @@ -415,6 +426,19 @@ cnp->cn_flags &= ~LOCKPARENT; /* + * EJUSTRETURN is used by underlying filesystems to indicate that + * a directory modification op was started successfully. + * This will only happen in the upper layer, since + * the lower layer only does LOOKUPs. + * If this union is mounted read-only, bounce it now. + */ + + if ((uerror == EJUSTRETURN) && (cnp->cn_flags & ISLASTCN) && + (dvp->v_mount->mnt_flag & MNT_RDONLY) && + ((cnp->cn_nameiop == CREATE) || (cnp->cn_nameiop == RENAME))) + uerror = EROFS; + + /* * at this point, we have uerror and lerror indicating * possible errors with the lookups in the upper and lower * layers. additionally, uppervp and lowervp are (locked) @@ -440,6 +464,7 @@ *ap->a_vpp = NULLVP; + /* case 1. */ if ((uerror != 0) && (lerror != 0)) { return (uerror); @@ -485,12 +510,11 @@ if (!lockparent || !(cnp->cn_flags & ISLASTCN)) VOP_UNLOCK(dvp, 0, p); if (cnp->cn_namelen == 1 && - cnp->cn_nameptr[0] == '.' && - *ap->a_vpp != dvp) { - panic("union_lookup returning. (%x) not same as startdir (%x)", + cnp->cn_nameptr[0] == '.' && + *ap->a_vpp != dvp) { + panic("union_lookup -> . (%p) != startdir (%p)", ap->a_vpp, dvp); } - } return (error); @@ -507,16 +531,15 @@ struct vattr *a_vap; } */ *ap = v; struct union_node *un = VTOUNION(ap->a_dvp); - struct vnode *dvp; + struct vnode *dvp = un->un_uppervp; struct componentname *cnp = ap->a_cnp; - struct proc *p = cnp->cn_proc; - if ((dvp = un->un_uppervp) != NULLVP) { + if (dvp != NULLVP) { int error; struct vnode *vp; struct mount *mp; - FIXUP(un, p); + FIXUP(un); VREF(dvp); un->un_flags |= UN_KLOCK; @@ -526,15 +549,8 @@ if (error) return (error); - error = union_allocvp( - ap->a_vpp, - mp, - NULLVP, - NULLVP, - cnp, - vp, - NULLVP, - 1); + error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, cnp, vp, + NULLVP, 1); if (error) vput(vp); return (error); @@ -554,13 +570,13 @@ int a_flags; } */ *ap = v; struct union_node *un = VTOUNION(ap->a_dvp); - struct proc *p = curproc; + struct componentname *cnp = ap->a_cnp; if (un->un_uppervp == NULLVP) return (EOPNOTSUPP); - FIXUP(un, p); - return (VOP_WHITEOUT(un->un_uppervp, ap->a_cnp, ap->a_flags)); + FIXUP(un); + return (VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags)); } int @@ -574,37 +590,28 @@ struct vattr *a_vap; } */ *ap = v; struct union_node *un = VTOUNION(ap->a_dvp); - struct vnode *dvp; - struct proc *p = ap->a_cnp->cn_proc; + struct vnode *dvp = un->un_uppervp; + struct componentname *cnp = ap->a_cnp; - if ((dvp = un->un_uppervp) != NULLVP) { + if (dvp != NULLVP) { int error; struct vnode *vp; struct mount *mp; - FIXUP(un, p); + FIXUP(un); VREF(dvp); un->un_flags |= UN_KLOCK; mp = ap->a_dvp->v_mount; vput(ap->a_dvp); - error = VOP_MKNOD(dvp, &vp, ap->a_cnp, ap->a_vap); + error = VOP_MKNOD(dvp, &vp, cnp, ap->a_vap); if (error) return (error); - if (vp != NULLVP) { - error = union_allocvp( - ap->a_vpp, - mp, - NULLVP, - NULLVP, - ap->a_cnp, - vp, - NULLVP, - 1); - if (error) - vput(vp); - } + error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, + cnp, vp, NULLVP, 1); + if (error) + vput(vp); return (error); } @@ -649,8 +656,11 @@ } /* - * Just open the lower vnode + * Just open the lower vnode, but check for nodev mount flag */ + if ((tvp->v_type == VBLK || tvp->v_type == VCHR) && + (ap->a_vp->v_mount->mnt_flag & MNT_NODEV)) + return ENXIO; un->un_openl++; vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_OPEN(tvp, mode, cred, p); @@ -658,8 +668,14 @@ return (error); } + /* + * Just open the upper vnode, checking for nodev mount flag first + */ + if ((tvp->v_type == VBLK || tvp->v_type == VCHR) && + (ap->a_vp->v_mount->mnt_flag & MNT_NODEV)) + return ENXIO; - FIXUP(un, p); + FIXUP(un); error = VOP_OPEN(tvp, mode, cred, p); @@ -679,7 +695,8 @@ struct union_node *un = VTOUNION(ap->a_vp); struct vnode *vp; - if ((vp = un->un_uppervp) == NULLVP) { + vp = un->un_uppervp; + if (vp == NULLVP) { #ifdef UNION_DIAGNOSTIC if (un->un_openl <= 0) panic("union: un_openl cnt"); @@ -687,14 +704,11 @@ --un->un_openl; vp = un->un_lowervp; } -#ifdef UNION_DIAGNOSTIC - /* - * A stranded union node may end up here with both vnodes NULL, - * in which case we don't do anything. - */ + +#ifdef DIAGNOSTIC if (vp == NULLVP) { - vprint("empty union vnode", vp); - panic("union_close empty vnode"); + vprint("empty union vnode", vp); + panic("union_close empty vnode"); } #endif @@ -721,25 +735,52 @@ struct ucred *a_cred; struct proc *a_p; } */ *ap = v; - struct union_node *un = VTOUNION(ap->a_vp); + struct vnode *vp = ap->a_vp; + struct union_node *un = VTOUNION(vp); int error = EACCES; - struct vnode *vp; struct proc *p = ap->a_p; + struct union_mount *um = MOUNTTOUNIONMOUNT(vp->v_mount); + + /* + * Disallow write attempts on read-only file systems; + * unless the file is a socket, fifo, or a block or + * character device resident on the file system. + */ + if (ap->a_mode & VWRITE) { + switch (vp->v_type) { + case VDIR: + case VLNK: + case VREG: + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + break; + case VBAD: + case VBLK: + case VCHR: + case VSOCK: + case VFIFO: + case VNON: + default: + break; + } + } + if ((vp = un->un_uppervp) != NULLVP) { - FIXUP(un, p); - return (VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p)); + FIXUP(un); + ap->a_vp = vp; + return (VCALL(vp, VOFFSET(vop_access), ap)); } if ((vp = un->un_lowervp) != NULLVP) { vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p); + ap->a_vp = vp; + error = VCALL(vp, VOFFSET(vop_access), ap); if (error == 0) { - struct union_mount *um = MOUNTTOUNIONMOUNT(ap->a_vp->v_mount); - - if (um->um_op == UNMNT_BELOW) - error = VOP_ACCESS(vp, ap->a_mode, - um->um_cred, ap->a_p); + if (um->um_op == UNMNT_BELOW) { + ap->a_cred = um->um_cred; + error = VCALL(vp, VOFFSET(vop_access), ap); + } } VOP_UNLOCK(vp, 0, p); if (error) @@ -768,7 +809,7 @@ struct vnode *vp = un->un_uppervp; struct vattr *vap; struct vattr va; - struct proc *p = ap->a_p; + /* * Some programs walk the filesystem hierarchy by counting @@ -777,11 +818,17 @@ * The only way to do that is to call getattr on both layers * and fix up the link count. The link count will not necessarily * be accurate but will be large enough to defeat the tree walkers. + * + * To make life more interesting, some filesystems don't keep + * track of link counts in the expected way, and return a + * link count of `1' for those directories; if either of the + * component directories returns a link count of `1', we return a 1. */ vap = ap->a_vap; - if ((vp = un->un_uppervp) != NULLVP) { + vp = un->un_uppervp; + if (vp != NULLVP) { /* * It's not clear whether VOP_GETATTR is to be * called with the vnode locked or not. stat() calls @@ -791,7 +838,7 @@ * the union_node's lock flag. */ if (un->un_flags & UN_LOCKED) - FIXUP(un, p); + FIXUP(un); error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p); if (error) @@ -803,7 +850,8 @@ vp = un->un_lowervp; } else if (vp->v_type == VDIR) { vp = un->un_lowervp; - vap = &va; + if (vp != NULLVP) + vap = &va; } else { vp = NULLVP; } @@ -815,9 +863,22 @@ union_newsize(ap->a_vp, VNOVAL, vap->va_size); } - if ((vap != ap->a_vap) && (vap->va_type == VDIR)) - ap->a_vap->va_nlink += vap->va_nlink; - + if ((vap != ap->a_vap) && (vap->va_type == VDIR)) { + /* + * Link count manipulation: + * - If both return "2", return 2 (no subdirs) + * - If one or the other return "1", return "1" (ENOCLUE) + */ + if ((ap->a_vap->va_nlink == 2) && + (vap->va_nlink == 2)) + ; + else if (ap->a_vap->va_nlink != 1) { + if (vap->va_nlink == 1) + ap->a_vap->va_nlink = 1; + else + ap->a_vap->va_nlink += vap->va_nlink; + } + } ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; return (0); } @@ -832,10 +893,37 @@ struct ucred *a_cred; struct proc *a_p; } */ *ap = v; - struct union_node *un = VTOUNION(ap->a_vp); - struct proc *p = ap->a_p; + struct vattr *vap = ap->a_vap; + struct vnode *vp = ap->a_vp; + struct union_node *un = VTOUNION(vp); int error; + if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || + vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || + vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) && + (vp->v_mount->mnt_flag & MNT_RDONLY)) + return (EROFS); + if (vap->va_size != VNOVAL) { + switch (vp->v_type) { + case VDIR: + return (EISDIR); + case VCHR: + case VBLK: + case VSOCK: + case VFIFO: + break; + case VREG: + case VLNK: + default: + /* + * Disallow write attempts if the filesystem is + * mounted read-only. + */ + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + } + } + /* * Handle case of truncating lower object to zero size, * by creating a zero length upper object. This is to @@ -844,7 +932,7 @@ if ((un->un_uppervp == NULLVP) && /* assert(un->un_lowervp != NULLVP) */ (un->un_lowervp->v_type == VREG)) { - error = union_copyup(un, (ap->a_vap->va_size != 0), + error = union_copyup(un, (vap->va_size != 0), ap->a_cred, ap->a_p); if (error) return (error); @@ -855,11 +943,11 @@ * otherwise return read-only filesystem error. */ if (un->un_uppervp != NULLVP) { - FIXUP(un, p); - error = VOP_SETATTR(un->un_uppervp, ap->a_vap, + FIXUP(un); + error = VOP_SETATTR(un->un_uppervp, vap, ap->a_cred, ap->a_p); - if ((error == 0) && (ap->a_vap->va_size != VNOVAL)) - union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL); + if ((error == 0) && (vap->va_size != VNOVAL)) + union_newsize(ap->a_vp, vap->va_size, VNOVAL); } else { error = EROFS; } @@ -885,7 +973,7 @@ if (dolock) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_vp), p); + FIXUP(VTOUNION(ap->a_vp)); error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); if (dolock) VOP_UNLOCK(vp, 0, p); @@ -925,13 +1013,12 @@ int error; struct vnode *vp; struct union_node *un = VTOUNION(ap->a_vp); - struct proc *p = curproc; vp = UPPERVP(ap->a_vp); if (vp == NULLVP) panic("union: missing upper layer in write"); - FIXUP(un, p); + FIXUP(un); error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); /* @@ -958,10 +1045,10 @@ struct ucred *a_cred; int a_flag; } */ *ap = v; - register struct vnode *vp = OTHERVP(ap->a_vp); + struct vnode *ovp = OTHERVP(ap->a_vp); - ap->a_vp = vp; - return (VCALL(vp, VOFFSET(vop_lease), ap)); + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_lease), ap)); } int @@ -970,33 +1057,68 @@ { struct vop_ioctl_args /* { struct vnode *a_vp; - u_long a_command; + int a_command; caddr_t a_data; int a_fflag; struct ucred *a_cred; struct proc *a_p; } */ *ap = v; - register struct vnode *vp = OTHERVP(ap->a_vp); + struct vnode *ovp = OTHERVP(ap->a_vp); - ap->a_vp = vp; - return (VCALL(vp, VOFFSET(vop_ioctl), ap)); + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_ioctl), ap)); } +#if 0 +int +union_poll(v) + void *v; +{ + struct vop_poll_args /* { + struct vnode *a_vp; + int a_events; + struct proc *a_p; + } */ *ap = v; + struct vnode *ovp = OTHERVP(ap->a_vp); + + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_poll), ap)); +} +#endif int -union_select(v) +union_revoke(v) void *v; { - struct vop_select_args /* { + struct vop_revoke_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + + if (UPPERVP(vp)) + VOP_REVOKE(UPPERVP(vp), ap->a_flags); + if (LOWERVP(vp)) + VOP_REVOKE(LOWERVP(vp), ap->a_flags); + vgone(vp); + return (0); +} + +#if 0 +int +union_mmap(v) + void *v; +{ + struct vop_mmap_args /* { struct vnode *a_vp; - int a_which; int a_fflags; struct ucred *a_cred; struct proc *a_p; } */ *ap = v; - register struct vnode *vp = OTHERVP(ap->a_vp); + struct vnode *ovp = OTHERVP(ap->a_vp); - ap->a_vp = vp; - return (VCALL(vp, VOFFSET(vop_select), ap)); + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_mmap), ap)); } int @@ -1006,22 +1128,37 @@ struct vop_fsync_args /* { struct vnode *a_vp; struct ucred *a_cred; - int a_waitfor; + int a_flags; + off_t offhi; + off_t offlo; struct proc *a_p; } */ *ap = v; int error = 0; - struct vnode *targetvp = OTHERVP(ap->a_vp); - struct proc *p = ap->a_p; + struct proc *p; + struct vnode *targetvp; + /* + * If vinvalbuf is calling us, it's a "shallow fsync" -- don't + * bother syncing the underlying vnodes, since (a) they'll be + * fsync'ed when reclaimed and (b) we could deadlock if + * they're locked; otherwise, pass it through to the + * underlying layer. + */ + if (ap->a_flags & FSYNC_RECLAIM) + return 0; + + targetvp = OTHERVP(ap->a_vp); + p = ap->a_p; + if (targetvp != NULLVP) { int dolock = (targetvp == LOWERVP(ap->a_vp)); if (dolock) vn_lock(targetvp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_vp), p); - error = VOP_FSYNC(targetvp, ap->a_cred, - ap->a_waitfor, ap->a_p); + FIXUP(VTOUNION(ap->a_vp)); + error = VOP_FSYNC(targetvp, ap->a_cred, ap->a_flags, + ap->a_offlo, ap->a_offhi, p); if (dolock) VOP_UNLOCK(targetvp, 0, p); } @@ -1029,10 +1166,23 @@ return (error); } -/* a_dvp: directory in which to link - a_vp: new target of the link - a_cnp: name for the link - */ +int +union_seek(v) + void *v; +{ + struct vop_seek_args /* { + struct vnode *a_vp; + off_t a_oldoff; + off_t a_newoff; + struct ucred *a_cred; + } */ *ap = v; + struct vnode *ovp = OTHERVP(ap->a_vp); + + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_seek), ap)); +} +#endif + int union_remove(v) void *v; @@ -1045,7 +1195,7 @@ int error; struct union_node *dun = VTOUNION(ap->a_dvp); struct union_node *un = VTOUNION(ap->a_vp); - struct proc *p = ap->a_cnp->cn_proc; + struct componentname *cnp = ap->a_cnp; if (dun->un_uppervp == NULLVP) panic("union remove: null upper vnode"); @@ -1053,13 +1203,12 @@ if (un->un_uppervp != NULLVP) { struct vnode *dvp = dun->un_uppervp; struct vnode *vp = un->un_uppervp; - struct componentname *cnp = ap->a_cnp; - FIXUP(dun, p); + FIXUP(dun); VREF(dvp); dun->un_flags |= UN_KLOCK; vput(ap->a_dvp); - FIXUP(un, p); + FIXUP(un); VREF(vp); un->un_flags |= UN_KLOCK; vput(ap->a_vp); @@ -1070,7 +1219,7 @@ if (!error) union_removed_upper(un); } else { - FIXUP(dun, p); + FIXUP(dun); error = union_mkwhiteout( MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount), dun->un_uppervp, ap->a_cnp, un->un_path); @@ -1081,10 +1230,6 @@ return (error); } -/* a_dvp: directory in which to link - a_vp: new target of the link - a_cnp: name for the link - */ int union_link(v) void *v; @@ -1095,10 +1240,11 @@ struct componentname *a_cnp; } */ *ap = v; int error = 0; + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; struct union_node *dun; - struct vnode *dvp; struct vnode *vp; - struct proc *p = ap->a_cnp->cn_proc; + struct vnode *dvp; dun = VTOUNION(ap->a_dvp); @@ -1108,47 +1254,53 @@ error = EIO; /* need some error code for "caller is a bozo" */ } else #endif + + if (ap->a_dvp->v_op != ap->a_vp->v_op) { vp = ap->a_vp; } else { struct union_node *un = VTOUNION(ap->a_vp); - if (un->un_uppervp == NULLVP) { /* - * needs to be copied up before we can link it. + * Needs to be copied before we can link it. */ vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p); if (dun->un_uppervp == un->un_dirvp) { - VOP_UNLOCK(ap->a_dvp, 0, p); + dun->un_flags &= ~UN_ULOCK; + VOP_UNLOCK(dun->un_uppervp, 0, p); } - error = union_copyup(un, 1, ap->a_cnp->cn_cred, - ap->a_cnp->cn_proc); + error = union_copyup(un, 1, cnp->cn_cred, p); if (dun->un_uppervp == un->un_dirvp) { - /* During copyup, we dropped the lock on the + /* + * During copyup, we dropped the lock on the * dir and invalidated any saved namei lookup * state for the directory we'll be entering * the link in. We need to re-run the lookup * in that directory to reset any state needed * for VOP_LINK. - * Call relookup on the union-layer to - * reset the state. + * Call relookup on the union-layer to reset + * the state. */ vp = NULLVP; - if (dun->un_uppervp == NULLVP || - /* - * relookup starts with an unlocked node, - * and since LOCKPARENT is set returns - * the starting directory locked. - */ - (error = relookup(ap->a_dvp, - &dvp, ap->a_cnp))) { + if (dun->un_uppervp == NULLVP) + panic("union: null upperdvp?"); + /* + * relookup starts with an unlocked node, + * and since LOCKPARENT is set returns + * the starting directory locked. + */ + VOP_UNLOCK(ap->a_dvp, 0, p); + error = relookup(ap->a_dvp, &vp, ap->a_cnp); + if (error) { vrele(ap->a_dvp); VOP_UNLOCK(ap->a_vp, 0, p); - return EROFS; + return EROFS; /* ? */ } - if (dvp != NULLVP) { - /* The name we want to create has - mysteriously appeared (a race?) */ + if (vp != NULLVP) { + /* + * The name we want to create has + * mysteriously appeared (a race?) + */ error = EEXIST; VOP_UNLOCK(ap->a_vp, 0, p); goto croak; @@ -1169,12 +1321,12 @@ return (error); } - FIXUP(dun, p); + FIXUP(dun); VREF(dvp); dun->un_flags |= UN_KLOCK; vput(ap->a_dvp); - return (VOP_LINK(dvp, vp, ap->a_cnp)); + return (VOP_LINK(dvp, vp, cnp)); } int @@ -1195,7 +1347,6 @@ struct vnode *fvp = ap->a_fvp; struct vnode *tdvp = ap->a_tdvp; struct vnode *tvp = ap->a_tvp; - struct union_node *unfile = (struct union_node *)0; if (fdvp->v_op == union_vnodeop_p) { /* always true */ struct union_node *un = VTOUNION(fdvp); @@ -1216,19 +1367,19 @@ } if (fvp->v_op == union_vnodeop_p) { /* always true */ - unfile = VTOUNION(fvp); - if (unfile->un_uppervp == NULLVP) { + struct union_node *un = VTOUNION(fvp); + if (un->un_uppervp == NULLVP) { /* XXX: should do a copyup */ error = EXDEV; goto bad; } - if (unfile->un_lowervp != NULLVP) + if (un->un_lowervp != NULLVP) ap->a_fcnp->cn_flags |= DOWHITEOUT; - fvp = unfile->un_uppervp; + fvp = un->un_uppervp; VREF(fvp); - /* vrele(ap->a_fvp); */ /* hold for later */ + vrele(ap->a_fvp); } if (tdvp->v_op == union_vnodeop_p) { @@ -1241,7 +1392,7 @@ * directory. */ error = EXDEV; - goto badrele; + goto bad; } tdvp = un->un_uppervp; @@ -1258,24 +1409,11 @@ VREF(tvp); un->un_flags |= UN_KLOCK; } -#if 0 - /* XXX should we toss from the cache? */ - if (un->un_flags & UN_CACHED) { - un->un_flags &= ~UN_CACHED; - LIST_REMOVE(un, un_cache); - } -#endif vput(ap->a_tvp); } - error = VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp); - if (!error && unfile) - union_removed_upper(unfile); - vrele(ap->a_fvp); - return error; + return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp)); -badrele: - vrele(ap->a_fvp); bad: vrele(fdvp); vrele(fvp); @@ -1299,30 +1437,24 @@ struct union_node *un = VTOUNION(ap->a_dvp); struct vnode *dvp = un->un_uppervp; struct proc *p = ap->a_cnp->cn_proc; + struct componentname *cnp = ap->a_cnp; if (dvp != NULLVP) { int error; struct vnode *vp; - FIXUP(un, p); + FIXUP(un); VREF(dvp); un->un_flags |= UN_KLOCK; VOP_UNLOCK(ap->a_dvp, 0, p); - error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap); + error = VOP_MKDIR(dvp, &vp, cnp, ap->a_vap); if (error) { vrele(ap->a_dvp); return (error); } - error = union_allocvp( - ap->a_vpp, - ap->a_dvp->v_mount, - ap->a_dvp, - NULLVP, - ap->a_cnp, - vp, - NULLVP, - 1); + error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount, ap->a_dvp, + NULLVP, cnp, vp, NULLVP, 1); vrele(ap->a_dvp); if (error) vput(vp); @@ -1345,7 +1477,7 @@ int error; struct union_node *dun = VTOUNION(ap->a_dvp); struct union_node *un = VTOUNION(ap->a_vp); - struct proc *p = ap->a_cnp->cn_proc; + struct componentname *cnp = ap->a_cnp; if (dun->un_uppervp == NULLVP) panic("union rmdir: null upper vnode"); @@ -1353,24 +1485,23 @@ if (un->un_uppervp != NULLVP) { struct vnode *dvp = dun->un_uppervp; struct vnode *vp = un->un_uppervp; - struct componentname *cnp = ap->a_cnp; - FIXUP(dun, p); + FIXUP(dun); VREF(dvp); dun->un_flags |= UN_KLOCK; vput(ap->a_dvp); - FIXUP(un, p); + FIXUP(un); VREF(vp); un->un_flags |= UN_KLOCK; vput(ap->a_vp); if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc)) cnp->cn_flags |= DOWHITEOUT; - error = VOP_RMDIR(dvp, vp, cnp); + error = VOP_RMDIR(dvp, vp, ap->a_cnp); if (!error) union_removed_upper(un); } else { - FIXUP(dun, p); + FIXUP(dun); error = union_mkwhiteout( MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount), dun->un_uppervp, ap->a_cnp, un->un_path); @@ -1394,19 +1525,17 @@ } */ *ap = v; struct union_node *un = VTOUNION(ap->a_dvp); struct vnode *dvp = un->un_uppervp; - struct proc *p = ap->a_cnp->cn_proc; + struct componentname *cnp = ap->a_cnp; if (dvp != NULLVP) { int error; - struct vnode *vp; - FIXUP(un, p); + FIXUP(un); VREF(dvp); un->un_flags |= UN_KLOCK; vput(ap->a_dvp); - error = VOP_SYMLINK(dvp, &vp, ap->a_cnp, - ap->a_vap, ap->a_target); - *ap->a_vpp = NULLVP; + error = VOP_SYMLINK(dvp, ap->a_vpp, cnp, ap->a_vap, + ap->a_target); return (error); } @@ -1431,19 +1560,18 @@ struct uio *a_uio; struct ucred *a_cred; int *a_eofflag; - int *a_ncookies; - u_long **a_cookies; - + u_long *a_cookies; + int a_ncookies; } */ *ap = v; - register struct union_node *un = VTOUNION(ap->a_vp); - register struct vnode *vp; - struct proc *p = curproc; - if ((vp = un->un_uppervp) == NULLVP) + struct union_node *un = VTOUNION(ap->a_vp); + struct vnode *uvp = un->un_uppervp; + + if (uvp == NULLVP) return (0); - FIXUP(un, p); - ap->a_vp = vp; - return (VCALL(vp, VOFFSET(vop_readdir), ap)); + FIXUP(un); + ap->a_vp = uvp; + return (VCALL(uvp, VOFFSET(vop_readdir), ap)); } int @@ -1457,14 +1585,13 @@ } */ *ap = v; int error; struct vnode *vp = OTHERVP(ap->a_vp); - struct proc *p = curproc; - int dolock = (vp == LOWERVP(ap->a_vp)); + struct proc *p = curproc; if (dolock) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_vp), p); + FIXUP(VTOUNION(ap->a_vp)); ap->a_vp = vp; error = VCALL(vp, VOFFSET(vop_readlink), ap); if (dolock) @@ -1473,18 +1600,6 @@ return (error); } -/* - * When operations want to vput() a union node yet retain a lock on - * the upper VP (say, to do some further operations like link(), - * mkdir(), ...), they set UN_KLOCK on the union node, then call - * vput() which calls VOP_UNLOCK(, 0, p) and comes here. union_unlock() - * unlocks the union node (leaving the upper VP alone), clears the - * KLOCK flag, and then returns to vput(). The caller then does whatever - * is left to do with the upper VP, and insures that it gets unlocked. - * - * If UN_KLOCK isn't set, then the upper VP is unlocked here. - */ - int union_abortop(v) void *v; @@ -1497,7 +1612,6 @@ struct vnode *vp = OTHERVP(ap->a_dvp); struct union_node *un = VTOUNION(ap->a_dvp); struct proc *p = ap->a_cnp->cn_proc; - int islocked = un->un_flags & UN_LOCKED; int dolock = (vp == LOWERVP(ap->a_dvp)); @@ -1505,7 +1619,7 @@ if (dolock) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_dvp), p); + FIXUP(VTOUNION(ap->a_dvp)); } ap->a_dvp = vp; error = VCALL(vp, VOFFSET(vop_abortop), ap); @@ -1523,7 +1637,10 @@ struct vnode *a_vp; struct proc *a_p; } */ *ap = v; - struct union_node *un = VTOUNION(ap->a_vp); + struct vnode *vp = ap->a_vp; + struct union_node *un = VTOUNION(vp); + struct proc *p = ap->a_p; + struct vnode **vpp; /* * Do nothing (and _don't_ bypass). @@ -1538,19 +1655,17 @@ * That's too much work for now. */ -#ifdef UNION_DIAGNOSTIC - if (un->un_flags & UN_LOCKED) - panic("union: inactivating locked node"); - if (un->un_flags & UN_ULOCK) - panic("union: inactivating w/locked upper node"); -#endif - - union_diruncache(un); + if (un->un_dircache != 0) { + for (vpp = un->un_dircache; *vpp != NULLVP; vpp++) + vrele(*vpp); + free(un->un_dircache, M_TEMP); + un->un_dircache = 0; + } - VOP_UNLOCK(ap->a_vp, 0, ap->a_p); + VOP_UNLOCK(vp, 0, p); if ((un->un_flags & UN_CACHED) == 0) - vrecycle(ap->a_vp, (struct simplelock *)0, ap->a_p); + vgone(vp); return (0); } @@ -1572,12 +1687,18 @@ union_lock(v) void *v; { - struct vop_lock_args *ap = v; + struct vop_lock_args /* { + struct vnode *a_vp; + int a_flags; + } */ *ap = v; struct vnode *vp = ap->a_vp; + int flags = ap->a_flags; struct union_node *un; - struct proc *p = ap->a_p; - int flags = ap->a_flags; - int error = 0; + struct proc *p = ap->a_p; + int error; +#ifdef DIAGNOSTIC + int drain = 0; +#endif vop_generic_lock(ap); /* @@ -1591,12 +1712,42 @@ */ flags &= ~LK_INTERLOCK; + un = VTOUNION(vp); +#ifdef DIAGNOSTIC + if (un->un_flags & (UN_DRAINING|UN_DRAINED)) { + if (un->un_flags & UN_DRAINED) + panic("union: %p: warning: locking decommissioned lock", vp); + if ((flags & LK_TYPE_MASK) != LK_RELEASE) + panic("union: %p: non-release on draining lock: %d", + vp, flags & LK_TYPE_MASK); + un->un_flags &= ~UN_DRAINING; + if ((flags & LK_REENABLE) == 0) + un->un_flags |= UN_DRAINED; + } +#endif + + /* + * Don't pass DRAIN through to sub-vnode lock; keep track of + * DRAIN state at this level, and just get an exclusive lock + * on the underlying vnode. + */ + if ((flags & LK_TYPE_MASK) == LK_DRAIN) { +#ifdef DIAGNOSTIC + drain = 1; +#endif + flags = LK_EXCLUSIVE | (flags & ~LK_TYPE_MASK); + } start: - un = VTOUNION(vp); + un = VTOUNION(vp); if (un->un_uppervp != NULLVP) { if (((un->un_flags & UN_ULOCK) == 0) && (vp->v_usecount != 0)) { + /* + * We MUST always use the order of: take upper + * vp lock, manipulate union node flags, drop + * upper vp lock. This code must not be an + */ error = vn_lock(un->un_uppervp, flags, p); if (error) return (error); @@ -1605,11 +1756,12 @@ #ifdef DIAGNOSTIC if (un->un_flags & UN_KLOCK) { vprint("union: dangling klock", vp); - panic("union: dangling upper lock (%lx)", vp); + panic("union: dangling upper lock (%p)", vp); } #endif - } + } + /* XXX ignores LK_NOWAIT */ if (un->un_flags & UN_LOCKED) { #ifdef DIAGNOSTIC if (curproc && un->un_pid == curproc->p_pid && @@ -1617,7 +1769,7 @@ panic("union: locking against myself"); #endif un->un_flags |= UN_WANTED; - tsleep((caddr_t)un, PINOD, "unionlk", 0); + tsleep((caddr_t)&un->un_flags, PINOD, "unionlk2", 0); goto start; } @@ -1626,6 +1778,8 @@ un->un_pid = curproc->p_pid; else un->un_pid = -1; + if (drain) + un->un_flags |= UN_DRAINING; #endif un->un_flags |= UN_LOCKED; @@ -1634,21 +1788,23 @@ /* * When operations want to vput() a union node yet retain a lock on - * the upper VP (say, to do some further operations like link(), + * the upper vnode (say, to do some further operations like link(), * mkdir(), ...), they set UN_KLOCK on the union node, then call - * vput() which calls VOP_UNLOCK(, 0, p) and comes here. union_unlock() - * unlocks the union node (leaving the upper VP alone), clears the + * vput() which calls VOP_UNLOCK() and comes here. union_unlock() + * unlocks the union node (leaving the upper vnode alone), clears the * KLOCK flag, and then returns to vput(). The caller then does whatever - * is left to do with the upper VP, and insures that it gets unlocked. + * is left to do with the upper vnode, and ensures that it gets unlocked. * - * If UN_KLOCK isn't set, then the upper VP is unlocked here. + * If UN_KLOCK isn't set, then the upper vnode is unlocked here. */ - int union_unlock(v) void *v; { - struct vop_lock_args *ap = v; + struct vop_unlock_args /* { + struct vnode *a_vp; + int a_flags; + } */ *ap = v; struct union_node *un = VTOUNION(ap->a_vp); struct proc *p = ap->a_p; @@ -1658,6 +1814,8 @@ if (curproc && un->un_pid != curproc->p_pid && curproc->p_pid > -1 && un->un_pid > -1) panic("union: unlocking other process's union node"); + if (un->un_flags & UN_DRAINED) + panic("union: %p: warning: unlocking decommissioned lock", ap->a_vp); #endif un->un_flags &= ~UN_LOCKED; @@ -1669,14 +1827,17 @@ if (un->un_flags & UN_WANTED) { un->un_flags &= ~UN_WANTED; - wakeup((caddr_t)un); + wakeup((caddr_t) &un->un_flags); } #ifdef DIAGNOSTIC un->un_pid = 0; + if (un->un_flags & UN_DRAINING) { + un->un_flags |= UN_DRAINED; + un->un_flags &= ~UN_DRAINING; + } #endif - - vop_generic_unlock(v); + vop_generic_unlock(ap); return (0); } @@ -1700,7 +1861,7 @@ if (dolock) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_vp), p); + FIXUP(VTOUNION(ap->a_vp)); ap->a_vp = vp; error = VCALL(vp, VOFFSET(vop_bmap), ap); if (dolock) @@ -1719,17 +1880,17 @@ struct vnode *vp = ap->a_vp; printf("\ttag VT_UNION, vp=%p, uppervp=%p, lowervp=%p\n", - vp, UPPERVP(vp), LOWERVP(vp)); - if (UPPERVP(vp)) - vprint("uppervp", UPPERVP(vp)); - if (LOWERVP(vp)) - vprint("lowervp", LOWERVP(vp)); + vp, UPPERVP(vp), LOWERVP(vp)); + if (UPPERVP(vp) != NULLVP) + vprint("union: upper", UPPERVP(vp)); + if (LOWERVP(vp) != NULLVP) + vprint("union: lower", LOWERVP(vp)); if (VTOUNION(vp)->un_dircache) { struct vnode **vpp; - for (vpp = VTOUNION(vp)->un_dircache; *vpp != NULLVP; vpp++) vprint("dircache:", *vpp); } + return (0); } @@ -1751,7 +1912,7 @@ struct vop_pathconf_args /* { struct vnode *a_vp; int a_name; - register_t *a_retval; + int *a_retval; } */ *ap = v; int error; struct vnode *vp = OTHERVP(ap->a_vp); @@ -1761,7 +1922,7 @@ if (dolock) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_vp), p); + FIXUP(VTOUNION(ap->a_vp)); ap->a_vp = vp; error = VCALL(vp, VOFFSET(vop_pathconf), ap); if (dolock) @@ -1771,41 +1932,20 @@ } int -union_revoke(v) - void *v; -{ - struct vop_revoke_args /* { - struct vnode *a_vp; - int a_flags; - struct proc *a_p; - } */ *ap = v; - struct vnode *vp = ap->a_vp; - - if (UPPERVP(vp)) - VOP_REVOKE(UPPERVP(vp), ap->a_flags); - if (LOWERVP(vp)) - VOP_REVOKE(LOWERVP(vp), ap->a_flags); - vgone(vp); - - return (0); -} - -int union_advlock(v) void *v; { struct vop_advlock_args /* { - struct vnodeop_desc *a_desc; struct vnode *a_vp; caddr_t a_id; int a_op; struct flock *a_fl; int a_flags; } */ *ap = v; - register struct vnode *vp = OTHERVP(ap->a_vp); + struct vnode *ovp = OTHERVP(ap->a_vp); - ap->a_vp = vp; - return (VCALL(vp, VOFFSET(vop_advlock), ap)); + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_advlock), ap)); } @@ -1842,3 +1982,59 @@ return (error); } +#if 0 +int +union_getpages(v) + void *v; +{ + struct vop_getpages_args /* { + struct vnode *a_vp; + voff_t a_offset; + struct vm_page **a_m; + int *a_count; + int a_centeridx; + vm_prot_t a_access_type; + int a_advice; + int a_flags; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + int error; + + /* + * just pass the request on to the underlying layer. + */ + + if (ap->a_flags & PGO_LOCKED) { + return EBUSY; + } + ap->a_vp = OTHERVP(vp); + simple_unlock(&vp->v_interlock); + simple_lock(&ap->a_vp->v_interlock); + error = VCALL(ap->a_vp, VOFFSET(vop_getpages), ap); + return error; +} + +int +union_putpages(v) + void *v; +{ + struct vop_putpages_args /* { + struct vnode *a_vp; + voff_t a_offlo; + voff_t a_offhi; + int a_flags; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + int error; + + /* + * just pass the request on to the underlying layer. + */ + + ap->a_vp = OTHERVP(vp); + simple_unlock(&vp->v_interlock); + simple_lock(&ap->a_vp->v_interlock); + error = VCALL(ap->a_vp, VOFFSET(vop_putpages), ap); + return error; +} +#endif diff -ruN /backup/src.old/sys/msdosfs/msdosfs_lookup.c sys/msdosfs/msdosfs_lookup.c --- /backup/src.old/sys/msdosfs/msdosfs_lookup.c Mon Dec 9 21:34:22 2002 +++ sys/msdosfs/msdosfs_lookup.c Mon Dec 9 21:39:16 2002 @@ -110,7 +110,7 @@ struct buf *bp = 0; struct direntry *dep; u_char dosfilename[12]; - int flags = cnp->cn_flags; + int flags; int nameiop = cnp->cn_nameiop; int wincnt = 1; int chksum = -1; @@ -119,6 +119,9 @@ #ifdef MSDOSFS_DEBUG printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr); #endif + cnp->cn_flags &= ~PDIRUNLOCK; + flags = cnp->cn_flags; + dp = VTODE(vdp); pmp = dp->de_pmp; *vpp = NULL; @@ -163,14 +166,20 @@ error = 0; } else if (flags & ISDOTDOT) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; error = vget(vdp, LK_EXCLUSIVE, p); - if (!error && lockparent && (flags & ISLASTCN)) + if (!error && lockparent && (flags & ISLASTCN)) { error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p); + if (error == 0) + cnp->cn_flags &= ~PDIRUNLOCK; + } } else { error = vget(vdp, LK_EXCLUSIVE, p); - if (!lockparent || error || !(flags & ISLASTCN)) + if (!lockparent || error || !(flags & ISLASTCN)) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } } /* * Check that the capability number did not change @@ -185,11 +194,14 @@ return (0); } vput(vdp); - if (lockparent && pdp != vdp && (flags & ISLASTCN)) + if (lockparent && pdp != vdp && (flags & ISLASTCN)) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } } if ((error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p)) != 0) return (error); + cnp->cn_flags &= ~PDIRUNLOCK; vdp = pdp; dp = VTODE(vdp); *vpp = NULL; @@ -415,8 +427,10 @@ * information cannot be used. */ cnp->cn_flags |= SAVENAME; - if (!lockparent) + if (!lockparent) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } return (EJUSTRETURN); } /* @@ -504,8 +518,10 @@ if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) return (error); *vpp = DETOV(tdp); - if (!lockparent) + if (!lockparent) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } return (0); } @@ -535,8 +551,10 @@ return (error); *vpp = DETOV(tdp); cnp->cn_flags |= SAVENAME; - if (!lockparent) + if (!lockparent) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } return (0); } @@ -562,8 +580,11 @@ pdp = vdp; if (flags & ISDOTDOT) { VOP_UNLOCK(pdp, 0, p); /* race to get the inode */ + cnp->cn_flags |= PDIRUNLOCK; if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) { vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p); + if (error == 0) + cnp->cn_flags &= ~PDIRUNLOCK; return (error); } if (lockparent && (flags & ISLASTCN) && @@ -571,6 +592,7 @@ vput(DETOV(tdp)); return (error); } + cnp->cn_flags &= ~PDIRUNLOCK; *vpp = DETOV(tdp); } else if (dp->de_StartCluster == scn && isadir) { VREF(vdp); /* we want ourself, ie "." */ @@ -578,8 +600,10 @@ } else { if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) return (error); - if (!lockparent || !(flags & ISLASTCN)) + if (!lockparent || !(flags & ISLASTCN)) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } *vpp = DETOV(tdp); } diff -ruN /backup/src.old/sys/msdosfs/msdosfs_vnops.c sys/msdosfs/msdosfs_vnops.c --- /backup/src.old/sys/msdosfs/msdosfs_vnops.c Mon Dec 9 21:34:22 2002 +++ sys/msdosfs/msdosfs_vnops.c Mon Dec 9 21:39:16 2002 @@ -1810,7 +1810,7 @@ major(dep->de_dev), minor(dep->de_dev), VOP_ISLOCKED(ap->a_vp) ? "(LOCKED)" : ""); #ifdef DIAGNOSTIC - lockmgr_printinfo(&dep->de_lock); + lockmgr_printinfo(&ap->a_vp->v_lock); #endif return (0); diff -ruN /backup/src.old/sys/sys/namei.h sys/sys/namei.h --- /backup/src.old/sys/sys/namei.h Mon Dec 9 21:34:25 2002 +++ sys/sys/namei.h Mon Dec 9 21:39:16 2002 @@ -140,7 +140,8 @@ #define DOWHITEOUT 0x040000 /* do whiteouts */ #define REQUIREDIR 0x080000 /* must be a directory */ #define STRIPSLASHES 0x100000 /* strip trailing slashes */ -#define PARAMASK 0x1fff00 /* mask of parameter descriptors */ +#define PDIRUNLOCK 0x200000 +#define PARAMASK 0x2fff00 /* mask of parameter descriptors */ /* * Initialization of an nameidata structure. */ diff -ruN /backup/src.old/sys/sys/vnode.h sys/sys/vnode.h --- /backup/src.old/sys/sys/vnode.h Mon Dec 9 21:34:25 2002 +++ sys/sys/vnode.h Mon Dec 9 21:39:16 2002 @@ -113,6 +113,7 @@ } v_un; struct simplelock v_interlock; /* lock on usecount and flag */ + struct lock v_lock; struct lock *v_vnlock; /* used for non-locking fs's */ enum vtagtype v_tag; /* type of underlying data */ void *v_data; /* private data for fs */ @@ -136,6 +137,7 @@ #define VXLOCK 0x0100 /* vnode is locked to change underlying type */ #define VXWANT 0x0200 /* process is waiting for vnode */ #define VALIASED 0x0800 /* vnode has an alias */ +#define VLAYER 0x2000 /* vnode is on a layer filesystem */ #define VLOCKSWORK 0x4000 /* FS supports locking discipline */ /* @@ -286,12 +288,20 @@ */ #define VDESC_MAX_VPS 16 /* Low order 16 flag bits are reserved for willrele flags for vp arguments. */ -#define VDESC_VP0_WILLRELE 0x0001 -#define VDESC_VP1_WILLRELE 0x0002 -#define VDESC_VP2_WILLRELE 0x0004 -#define VDESC_VP3_WILLRELE 0x0008 -#define VDESC_NOMAP_VPP 0x0100 -#define VDESC_VPP_WILLRELE 0x0200 +#define VDESC_VP0_WILLRELE 0x00000001 +#define VDESC_VP1_WILLRELE 0x00000002 +#define VDESC_VP2_WILLRELE 0x00000004 +#define VDESC_VP3_WILLRELE 0x00000008 +#define VDESC_VP0_WILLUNLOCK 0x00000100 +#define VDESC_VP1_WILLUNLOCK 0x00000200 +#define VDESC_VP2_WILLUNLOCK 0x00000400 +#define VDESC_VP3_WILLUNLOCK 0x00000800 +#define VDESC_VP0_WILLPUT 0x00000101 +#define VDESC_VP1_WILLPUT 0x00000202 +#define VDESC_VP2_WILLPUT 0x00000404 +#define VDESC_VP3_WILLPUT 0x00000808 +#define VDESC_NOMAP_VPP 0x00010000 +#define VDESC_VPP_WILLRELE 0x00020000 /* * VDESC_NO_OFFSET is used to identify the end of the offset list diff -ruN /backup/src.old/sys/sys/vnode_if.h sys/sys/vnode_if.h --- /backup/src.old/sys/sys/vnode_if.h Mon Dec 9 21:34:25 2002 +++ sys/sys/vnode_if.h Mon Dec 9 21:39:16 2002 @@ -5,7 +5,7 @@ * Created from the file: * OpenBSD: vnode_if.src,v 1.19 2002/02/22 20:37:45 drahn Exp * by the script: - * OpenBSD: vnode_if.sh,v 1.8 2001/02/26 17:34:18 art Exp + * OpenBSD: vnode_if.sh,v 1.10 2002/03/14 23:47:05 millert Exp */ /* @@ -121,8 +121,7 @@ struct proc *a_p; }; extern struct vnodeop_desc vop_getattr_desc; -int VOP_GETATTR(struct vnode *, struct vattr *, struct ucred *, - struct proc *); +int VOP_GETATTR(struct vnode *, struct vattr *, struct ucred *, struct proc *); struct vop_setattr_args { struct vnodeop_desc *a_desc; @@ -132,8 +131,7 @@ struct proc *a_p; }; extern struct vnodeop_desc vop_setattr_desc; -int VOP_SETATTR(struct vnode *, struct vattr *, struct ucred *, - struct proc *); +int VOP_SETATTR(struct vnode *, struct vattr *, struct ucred *, struct proc *); struct vop_read_args { struct vnodeop_desc *a_desc; @@ -275,8 +273,8 @@ char *a_target; }; extern struct vnodeop_desc vop_symlink_desc; -int VOP_SYMLINK(struct vnode *, struct vnode **, - struct componentname *, struct vattr *, char *); +int VOP_SYMLINK(struct vnode *, struct vnode **, struct componentname *, + struct vattr *, char *); struct vop_readdir_args { struct vnodeop_desc *a_desc; @@ -288,8 +286,8 @@ u_long **a_cookies; }; extern struct vnodeop_desc vop_readdir_desc; -int VOP_READDIR(struct vnode *, struct uio *, struct ucred *, int *, - int *, u_long **); +int VOP_READDIR(struct vnode *, struct uio *, struct ucred *, int *, int *, + u_long **); struct vop_readlink_args { struct vnodeop_desc *a_desc; diff -ruN /backup/src.old/sys/ufs/ext2fs/ext2fs_lookup.c sys/ufs/ext2fs/ext2fs_lookup.c --- /backup/src.old/sys/ufs/ext2fs/ext2fs_lookup.c Mon Dec 9 21:34:25 2002 +++ sys/ufs/ext2fs/ext2fs_lookup.c Mon Dec 9 21:39:16 2002 @@ -336,13 +336,19 @@ error = 0; } else if (flags & ISDOTDOT) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags &= ~PDIRUNLOCK; error = vget(vdp, LK_EXCLUSIVE, p); - if (!error && lockparent && (flags & ISLASTCN)) + if (!error && lockparent && (flags & ISLASTCN)) { error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p); + if (error == 0) + cnp->cn_flags &= ~PDIRUNLOCK; + } } else { error = vget(vdp, LK_EXCLUSIVE, p); - if (!lockparent || error || !(flags & ISLASTCN)) + if (!lockparent || error || !(flags & ISLASTCN)) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } } /* * Check that the capability number did not change @@ -352,11 +358,14 @@ if (vpid == vdp->v_id) return (0); vput(vdp); - if (lockparent && pdp != vdp && (flags & ISLASTCN)) + if (lockparent && pdp != vdp && (flags & ISLASTCN)) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } } if ((error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p)) != 0) return (error); + cnp->cn_flags &= ~PDIRUNLOCK; vdp = pdp; dp = VTOI(pdp); *vpp = NULL; @@ -570,8 +579,10 @@ * information cannot be used. */ cnp->cn_flags |= SAVENAME; - if (!lockparent) + if (!lockparent) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } return (EJUSTRETURN); } /* @@ -646,8 +657,10 @@ return (EPERM); } *vpp = tdp; - if (!lockparent) + if (!lockparent) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } return (0); } @@ -671,8 +684,10 @@ return (error); *vpp = tdp; cnp->cn_flags |= SAVENAME; - if (!lockparent) + if (!lockparent) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } return (0); } @@ -698,8 +713,10 @@ pdp = vdp; if (flags & ISDOTDOT) { VOP_UNLOCK(pdp, 0, p); /* race to get the inode */ + cnp->cn_flags |= PDIRUNLOCK; if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) { - vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p); + if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p) == 0) + cnp->cn_flags &= ~PDIRUNLOCK; return (error); } if (lockparent && (flags & ISLASTCN) && @@ -707,6 +724,7 @@ vput(tdp); return (error); } + cnp->cn_flags |= PDIRUNLOCK; *vpp = tdp; } else if (dp->i_number == dp->i_ino) { VREF(vdp); /* we want ourself, ie "." */ @@ -714,8 +732,10 @@ } else { if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) return (error); - if (!lockparent || !(flags & ISLASTCN)) + if (!lockparent || !(flags & ISLASTCN)) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } *vpp = tdp; } diff -ruN /backup/src.old/sys/ufs/ext2fs/ext2fs_vfsops.c sys/ufs/ext2fs/ext2fs_vfsops.c --- /backup/src.old/sys/ufs/ext2fs/ext2fs_vfsops.c Mon Dec 9 21:34:25 2002 +++ sys/ufs/ext2fs/ext2fs_vfsops.c Mon Dec 9 21:39:16 2002 @@ -599,7 +599,7 @@ brelse(bp); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); - VOP_UNLOCK(devvp, 0, p); + vput(devvp); if (ump) { free(ump->um_e2fs, M_UFSMNT); free(ump, M_UFSMNT); @@ -854,7 +854,6 @@ } MALLOC(ip, struct inode *, sizeof(struct inode), M_EXT2FSNODE, M_WAITOK); bzero((caddr_t)ip, sizeof(struct inode)); - lockinit(&ip->i_lock, PINOD, "inode", 0, 0); vp->v_data = ip; ip->i_vnode = vp; ip->i_e2fs = fs = ump->um_e2fs; diff -ruN /backup/src.old/sys/ufs/ext2fs/ext2fs_vnops.c sys/ufs/ext2fs/ext2fs_vnops.c --- /backup/src.old/sys/ufs/ext2fs/ext2fs_vnops.c Mon Dec 9 21:34:25 2002 +++ sys/ufs/ext2fs/ext2fs_vnops.c Mon Dec 9 21:39:17 2002 @@ -1271,6 +1271,7 @@ vp->v_op = spec_vnodeop_p; vrele(vp); vgone(vp); + lockmgr(&nvp->v_lock, LK_EXCLUSIVE, &nvp->v_interlock, p); /* * Reinitialize aliased inode. */ diff -ruN /backup/src.old/sys/ufs/ffs/ffs_vfsops.c sys/ufs/ffs/ffs_vfsops.c --- /backup/src.old/sys/ufs/ffs/ffs_vfsops.c Mon Dec 9 21:34:25 2002 +++ sys/ufs/ffs/ffs_vfsops.c Mon Dec 9 21:39:17 2002 @@ -1155,7 +1155,6 @@ /* XXX - we use the same pool for ffs and mfs */ ip = pool_get(&ffs_ino_pool, PR_WAITOK); bzero((caddr_t)ip, sizeof(struct inode)); - lockinit(&ip->i_lock, PINOD, "inode", 0, 0); vp->v_data = ip; ip->i_vnode = vp; ip->i_fs = fs = ump->um_fs; diff -ruN /backup/src.old/sys/ufs/ufs/inode.h sys/ufs/ufs/inode.h --- /backup/src.old/sys/ufs/ufs/inode.h Mon Dec 9 21:34:26 2002 +++ sys/ufs/ufs/inode.h Mon Dec 9 21:39:17 2002 @@ -87,7 +87,6 @@ struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ u_quad_t i_modrev; /* Revision level for NFS lease. */ struct lockf *i_lockf;/* Head of byte-level lock list. */ - struct lock i_lock; /* Inode lock */ /* * Side effects; used during directory lookup. diff -ruN /backup/src.old/sys/ufs/ufs/ufs_ihash.c sys/ufs/ufs/ufs_ihash.c --- /backup/src.old/sys/ufs/ufs/ufs_ihash.c Mon Dec 9 21:34:26 2002 +++ sys/ufs/ufs/ufs_ihash.c Mon Dec 9 21:39:17 2002 @@ -130,7 +130,7 @@ ino_t inum = ip->i_number; /* lock the inode, then put it on the appropriate hash list */ - lockmgr(&ip->i_lock, LK_EXCLUSIVE, (struct simplelock *)0, p); + lockmgr(&ip->i_vnode->v_lock, LK_EXCLUSIVE, (struct simplelock *)0, p); simple_lock(&ufs_ihash_slock); @@ -138,7 +138,8 @@ curip = curip->i_hash.le_next) { if (inum == curip->i_number && dev == curip->i_dev) { simple_unlock(&ufs_ihash_slock); - lockmgr(&ip->i_lock, LK_RELEASE, (struct simplelock *)0, p); + lockmgr(&ip->i_vnode->v_lock, LK_RELEASE, + (struct simplelock *)0, p); return (EEXIST); } } diff -ruN /backup/src.old/sys/ufs/ufs/ufs_lookup.c sys/ufs/ufs/ufs_lookup.c --- /backup/src.old/sys/ufs/ufs/ufs_lookup.c Mon Dec 9 21:34:26 2002 +++ sys/ufs/ufs/ufs_lookup.c Mon Dec 9 21:39:17 2002 @@ -134,10 +134,12 @@ struct vnode **vpp = ap->a_vpp; struct componentname *cnp = ap->a_cnp; struct ucred *cred = cnp->cn_cred; - int flags = cnp->cn_flags; + int flags; int nameiop = cnp->cn_nameiop; struct proc *p = cnp->cn_proc; + cnp->cn_flags &= ~PDIRUNLOCK; + flags = cnp->cn_flags; bp = NULL; slotoffset = -1; *vpp = NULL; @@ -185,12 +187,17 @@ } else if (flags & ISDOTDOT) { VOP_UNLOCK(pdp, 0, p); error = vget(vdp, LK_EXCLUSIVE, p); - if (!error && lockparent && (flags & ISLASTCN)) + if (!error && lockparent && (flags & ISLASTCN)) { error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p); + if (error == 0) + cnp->cn_flags &= ~PDIRUNLOCK; + } } else { error = vget(vdp, LK_EXCLUSIVE, p); - if (!lockparent || error || !(flags & ISLASTCN)) + if (!lockparent || error || !(flags & ISLASTCN)) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } } /* * Check that the capability number did not change @@ -200,13 +207,16 @@ if (vpid == vdp->v_id) return (0); vput(vdp); - if (lockparent && pdp != vdp && (flags & ISLASTCN)) + if (lockparent && pdp != vdp && (flags & ISLASTCN)) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } } *vpp = NULL; - if ((error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p)) != 0) + if ((error = vn_lock(pdp, LK_EXCLUSIVE, p)) != 0) return (error); + cnp->cn_flags &= ~PDIRUNLOCK; vdp = pdp; dp = VTOI(pdp); } @@ -455,8 +465,10 @@ * information cannot be used. */ cnp->cn_flags |= SAVENAME; - if (!lockparent) + if (!lockparent) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } return (EJUSTRETURN); } /* @@ -534,8 +546,10 @@ return (EPERM); } *vpp = tdp; - if (!lockparent) + if (!lockparent) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } return (0); } @@ -561,8 +575,10 @@ return (error); *vpp = tdp; cnp->cn_flags |= SAVENAME; - if (!lockparent) + if (!lockparent) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } return (0); } @@ -588,16 +604,21 @@ pdp = vdp; if (flags & ISDOTDOT) { VOP_UNLOCK(pdp, 0, p); /* race to get the inode */ + cnp->cn_flags |= PDIRUNLOCK; error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp); if (error) { - vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p); + if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p) == 0) { + cnp->cn_flags &= ~PDIRUNLOCK; + } return (error); } - if (lockparent && (flags & ISLASTCN) && - (error = vn_lock(pdp, LK_EXCLUSIVE, p))) { - vput(tdp); - return (error); + if (lockparent && (flags & ISLASTCN)) { + if ((error = vn_lock(pdp, LK_EXCLUSIVE, p))) { + vput(tdp); + return (error); + } } + cnp->cn_flags &= ~PDIRUNLOCK; *vpp = tdp; } else if (dp->i_number == dp->i_ino) { VREF(vdp); /* we want ourself, ie "." */ @@ -606,8 +627,10 @@ error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp); if (error) return (error); - if (!lockparent || !(flags & ISLASTCN)) + if (!lockparent || !(flags & ISLASTCN)) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } *vpp = tdp; } diff -ruN /backup/src.old/sys/ufs/ufs/ufs_quota.c sys/ufs/ufs/ufs_quota.c --- /backup/src.old/sys/ufs/ufs/ufs_quota.c Mon Dec 9 21:34:26 2002 +++ sys/ufs/ufs/ufs_quota.c Mon Dec 9 21:39:17 2002 @@ -231,7 +231,7 @@ #ifdef DIAGNOSTIC if (!VOP_ISLOCKED(ITOV(ip))) - panic ("ufs_quota_free_blocks2: vnode is not locked"); + panic ("ufs_quota_free_blocks2: vnode (%p) is not locked", ITOV(ip)); #endif if (change == 0) diff -ruN /backup/src.old/sys/ufs/ufs/ufs_vnops.c sys/ufs/ufs/ufs_vnops.c --- /backup/src.old/sys/ufs/ufs/ufs_vnops.c Mon Dec 9 21:34:26 2002 +++ sys/ufs/ufs/ufs_vnops.c Mon Dec 9 21:39:17 2002 @@ -1687,7 +1687,7 @@ } */ *ap = v; struct vnode *vp = ap->a_vp; - return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags, &vp->v_interlock, + return (lockmgr(vp->v_vnlock, ap->a_flags, &vp->v_interlock, ap->a_p)); } @@ -1705,7 +1705,7 @@ } */ *ap = v; struct vnode *vp = ap->a_vp; - return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags | LK_RELEASE, + return (lockmgr(vp->v_vnlock, ap->a_flags | LK_RELEASE, &vp->v_interlock, ap->a_p)); } @@ -1720,7 +1720,7 @@ struct vnode *a_vp; } */ *ap = v; - return (lockstatus(&VTOI(ap->a_vp)->i_lock)); + return (lockstatus(ap->a_vp->v_vnlock)); } /* @@ -1793,7 +1793,7 @@ if (vp->v_type == VFIFO) fifo_printinfo(vp); #endif /* FIFO */ - lockmgr_printinfo(&ip->i_lock); + lockmgr_printinfo(vp->v_vnlock); printf("\n"); return (0); } @@ -2008,6 +2008,7 @@ { struct inode *ip; struct vnode *vp, *nvp; + struct proc *p = curproc; vp = *vpp; ip = VTOI(vp); @@ -2018,17 +2019,17 @@ if ((nvp = checkalias(vp, ip->i_ffs_rdev, mntp)) != NULL) { /* * Discard unneeded vnode, but save its inode. - * Note that the lock is carried over in the inode - * to the replacement vnode. */ nvp->v_data = vp->v_data; vp->v_data = NULL; + VOP_UNLOCK(vp, 0, p); vp->v_op = spec_vnodeop_p; #ifdef DIAGNOSTIC vp->v_flag &= ~VLOCKSWORK; #endif vrele(vp); vgone(vp); + lockmgr(&nvp->v_lock, LK_EXCLUSIVE, &nvp->v_interlock, p); /* * Reinitialize aliased inode. */