diff options
48 files changed, 308 insertions, 191 deletions
diff --git a/sys/coda/coda_vnops.c b/sys/coda/coda_vnops.c index 646ee34..c47d309 100644 --- a/sys/coda/coda_vnops.c +++ b/sys/coda/coda_vnops.c @@ -1854,7 +1854,7 @@ coda_grab_vnode(dev_t dev, ino_t ino, struct vnode **vpp) } /* XXX - ensure that nonzero-return means failure */ - error = VFS_VGET(mp,ino,vpp); + error = VFS_VGET(mp,ino,LK_EXCLUSIVE,vpp); if (error) { myprintf(("coda_grab_vnode: iget/vget(%lx, %lu) returns %p, err %d\n", (u_long)dev2udev(dev), (u_long)ino, (void *)*vpp, error)); diff --git a/sys/fs/cd9660/cd9660_lookup.c b/sys/fs/cd9660/cd9660_lookup.c index 706a7ae..da927e1 100644 --- a/sys/fs/cd9660/cd9660_lookup.c +++ b/sys/fs/cd9660/cd9660_lookup.c @@ -352,7 +352,8 @@ found: */ if (flags & ISDOTDOT) { VOP_UNLOCK(pdp, 0, td); /* race to get the inode */ - error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, &tdp, + error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, + LK_EXCLUSIVE, &tdp, dp->i_ino != ino, ep); brelse(bp); if (error) { @@ -373,7 +374,8 @@ found: VREF(vdp); /* we want ourself, ie "." */ *vpp = vdp; } else { - error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, &tdp, + error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, + LK_EXCLUSIVE, &tdp, dp->i_ino != ino, ep); brelse(bp); if (error) diff --git a/sys/fs/cd9660/cd9660_node.c b/sys/fs/cd9660/cd9660_node.c index 53ffeca..0060364 100644 --- a/sys/fs/cd9660/cd9660_node.c +++ b/sys/fs/cd9660/cd9660_node.c @@ -92,15 +92,19 @@ cd9660_uninit(vfsp) * Use the device/inum pair to find the incore inode, and return a pointer * to it. If it is in core, but locked, wait for it. */ -struct vnode * -cd9660_ihashget(dev, inum) +int +cd9660_ihashget(dev, inum, flags, vpp) dev_t dev; ino_t inum; + int flags; + struct vnode **vpp; { struct thread *td = curthread; /* XXX */ struct iso_node *ip; struct vnode *vp; + int error; + *vpp = NULL; loop: mtx_lock(&cd9660_ihash_mtx); for (ip = isohashtbl[INOHASH(dev, inum)]; ip; ip = ip->i_next) { @@ -108,13 +112,17 @@ loop: vp = ITOV(ip); mtx_lock(&vp->v_interlock); mtx_unlock(&cd9660_ihash_mtx); - if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) + error = vget(vp, flags | LK_INTERLOCK, td); + if (error == ENOENT) goto loop; - return (vp); + if (error) + return (error); + *vpp = vp; + return (0); } } mtx_unlock(&cd9660_ihash_mtx); - return (NULL); + return (0); } /* diff --git a/sys/fs/cd9660/cd9660_node.h b/sys/fs/cd9660/cd9660_node.h index 100c08e..2a0d7ef 100644 --- a/sys/fs/cd9660/cd9660_node.h +++ b/sys/fs/cd9660/cd9660_node.h @@ -117,7 +117,7 @@ void cd9660_defattr __P((struct iso_directory_record *, struct iso_node *, struct buf *, enum ISO_FTYPE)); void cd9660_deftstamp __P((struct iso_directory_record *, struct iso_node *, struct buf *, enum ISO_FTYPE)); -struct vnode *cd9660_ihashget __P((dev_t, ino_t)); +int cd9660_ihashget __P((dev_t, ino_t, int, struct vnode **)); void cd9660_ihashins __P((struct iso_node *)); int cd9660_tstamp_conv7 __P((u_char *, struct timespec *, enum ISO_FTYPE)); int cd9660_tstamp_conv17 __P((u_char *, struct timespec *)); diff --git a/sys/fs/cd9660/cd9660_vfsops.c b/sys/fs/cd9660/cd9660_vfsops.c index 1e3719d..60a7b38 100644 --- a/sys/fs/cd9660/cd9660_vfsops.c +++ b/sys/fs/cd9660/cd9660_vfsops.c @@ -69,7 +69,7 @@ static int cd9660_mount __P((struct mount *, static int cd9660_unmount __P((struct mount *, int, struct thread *)); static int cd9660_root __P((struct mount *, struct vnode **)); static int cd9660_statfs __P((struct mount *, struct statfs *, struct thread *)); -static int cd9660_vget __P((struct mount *, ino_t, struct vnode **)); +static int cd9660_vget __P((struct mount *, ino_t, int, struct vnode **)); static int cd9660_fhtovp __P((struct mount *, struct fid *, struct vnode **)); static int cd9660_vptofh __P((struct vnode *, struct fid *)); @@ -578,7 +578,7 @@ cd9660_root(mp, vpp) * With RRIP we must use the `.' entry of the root directory. * Simply tell vget, that it's a relocated directory. */ - return (cd9660_vget_internal(mp, ino, vpp, + return (cd9660_vget_internal(mp, ino, LK_EXCLUSIVE, vpp, imp->iso_ftype == ISO_FTYPE_RRIP, dp)); } @@ -644,7 +644,7 @@ cd9660_fhtovp(mp, fhp, vpp) ifhp->ifid_ino, ifhp->ifid_start); #endif - if ((error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) != 0) { + if ((error = VFS_VGET(mp, ifhp->ifid_ino, LK_EXCLUSIVE, &nvp)) != 0) { *vpp = NULLVP; return (error); } @@ -659,9 +659,10 @@ cd9660_fhtovp(mp, fhp, vpp) } int -cd9660_vget(mp, ino, vpp) +cd9660_vget(mp, ino, flags, vpp) struct mount *mp; ino_t ino; + int flags; struct vnode **vpp; { @@ -671,7 +672,7 @@ cd9660_vget(mp, ino, vpp) * and force the extra read, but I don't want to think about fixing * that right now. */ - return (cd9660_vget_internal(mp, ino, vpp, + return (cd9660_vget_internal(mp, ino, flags, vpp, #if 0 VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP, #else @@ -681,9 +682,10 @@ cd9660_vget(mp, ino, vpp) } int -cd9660_vget_internal(mp, ino, vpp, relocated, isodir) +cd9660_vget_internal(mp, ino, flags, vpp, relocated, isodir) struct mount *mp; ino_t ino; + int flags; struct vnode **vpp; int relocated; struct iso_directory_record *isodir; @@ -697,7 +699,9 @@ cd9660_vget_internal(mp, ino, vpp, relocated, isodir) imp = VFSTOISOFS(mp); dev = imp->im_dev; - if ((*vpp = cd9660_ihashget(dev, ino)) != NULLVP) + if ((error = cd9660_ihashget(dev, ino, flags, vpp)) != 0) + return (error); + if (*vpp != NULL) return (0); /* Allocate a new vnode/iso_node. */ @@ -718,6 +722,18 @@ cd9660_vget_internal(mp, ino, vpp, relocated, isodir) ip->i_number = ino; /* + * Check to be sure that it did not show up. We have to put it + * on the hash chain as the cleanup from vput expects to find + * it there. + */ + if ((error = cd9660_ihashget(dev, ino, flags, vpp)) != 0 || + *vpp != NULL) { + cd9660_ihashins(ip); + vput(vp); + return (error); + } + + /* * Put it onto its hash chain and lock it so that other requests for * this inode will block if they arrive while we are sleeping waiting * for old data structures to be purged or for the contents of the diff --git a/sys/fs/cd9660/iso.h b/sys/fs/cd9660/iso.h index b62c723..453423a 100644 --- a/sys/fs/cd9660/iso.h +++ b/sys/fs/cd9660/iso.h @@ -254,7 +254,7 @@ struct iso_mnt { #define lblkno(imp, loc) ((loc) >> (imp)->im_bshift) #define blksize(imp, ip, lbn) ((imp)->logical_block_size) -int cd9660_vget_internal __P((struct mount *, ino_t, struct vnode **, int, +int cd9660_vget_internal __P((struct mount *, ino_t, int, struct vnode **, int, struct iso_directory_record *)); int cd9660_init __P((struct vfsconf *)); int cd9660_uninit __P((struct vfsconf *)); diff --git a/sys/fs/coda/coda_vnops.c b/sys/fs/coda/coda_vnops.c index 646ee34..c47d309 100644 --- a/sys/fs/coda/coda_vnops.c +++ b/sys/fs/coda/coda_vnops.c @@ -1854,7 +1854,7 @@ coda_grab_vnode(dev_t dev, ino_t ino, struct vnode **vpp) } /* XXX - ensure that nonzero-return means failure */ - error = VFS_VGET(mp,ino,vpp); + error = VFS_VGET(mp,ino,LK_EXCLUSIVE,vpp); if (error) { myprintf(("coda_grab_vnode: iget/vget(%lx, %lu) returns %p, err %d\n", (u_long)dev2udev(dev), (u_long)ino, (void *)*vpp, error)); diff --git a/sys/fs/hpfs/hpfs.h b/sys/fs/hpfs/hpfs.h index bd90ce4..ec2cfad 100644 --- a/sys/fs/hpfs/hpfs.h +++ b/sys/fs/hpfs/hpfs.h @@ -393,7 +393,7 @@ void hpfs_hphashinit __P((void)); void hpfs_hphashdestroy __P((void)); struct hpfsnode *hpfs_hphashlookup __P((dev_t, lsn_t)); struct hpfsnode *hpfs_hphashget __P((dev_t, lsn_t)); -struct vnode *hpfs_hphashvget __P((dev_t, lsn_t, struct thread *)); +int hpfs_hphashvget __P((dev_t, lsn_t, int, struct vnode **, struct thread *)); void hpfs_hphashins __P((register struct hpfsnode *)); void hpfs_hphashrem __P((register struct hpfsnode *)); extern struct lock hpfs_hphash_lock; diff --git a/sys/fs/hpfs/hpfs_hash.c b/sys/fs/hpfs/hpfs_hash.c index 1c6601a..0a04a9a 100644 --- a/sys/fs/hpfs/hpfs_hash.c +++ b/sys/fs/hpfs/hpfs_hash.c @@ -122,15 +122,19 @@ loop: } #endif -struct vnode * -hpfs_hphashvget(dev, ino, td) +int +hpfs_hphashvget(dev, ino, flags, vpp, td) dev_t dev; lsn_t ino; + int flags; + struct vnode **vpp; struct thread *td; { struct hpfsnode *hp; struct vnode *vp; + int error; + *vpp = NULLVP; loop: mtx_lock(&hpfs_hphash_mtx); LIST_FOREACH(hp, HPNOHASH(dev, ino), h_hash) { @@ -138,13 +142,17 @@ loop: vp = HPTOV(hp); mtx_lock(&vp->v_interlock); mtx_unlock(&hpfs_hphash_mtx); - if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) + error = vget(vp, flags | LK_INTERLOCK, td); + if (error == ENOENT) goto loop; - return (vp); + if (error) + return (error); + *vpp = vp; + return (0); } } mtx_unlock(&hpfs_hphash_mtx); - return (NULLVP); + return (0); } /* diff --git a/sys/fs/hpfs/hpfs_subr.c b/sys/fs/hpfs/hpfs_subr.c index 5fa32a5..b45ebbd 100644 --- a/sys/fs/hpfs/hpfs_subr.c +++ b/sys/fs/hpfs/hpfs_subr.c @@ -536,7 +536,8 @@ hpfs_validateparent ( if (hp->h_no == hp->h_fn.fn_parent) { dhp = hp; } else { - error = VFS_VGET(hpmp->hpm_mp, hp->h_fn.fn_parent, &dvp); + error = VFS_VGET(hpmp->hpm_mp, hp->h_fn.fn_parent, + LK_EXCLUSIVE, &dvp); if (error) return (error); dhp = VTOHP(dvp); @@ -689,7 +690,7 @@ hpfs_updateparent ( dhp = hp; } else { error = VFS_VGET(hp->h_hpmp->hpm_mp, hp->h_fn.fn_parent, - &dvp); + LK_EXCLUSIVE, &dvp); if (error) return (error); dhp = VTOHP(dvp); diff --git a/sys/fs/hpfs/hpfs_vfsops.c b/sys/fs/hpfs/hpfs_vfsops.c index dcb5995..cf3c114 100644 --- a/sys/fs/hpfs/hpfs_vfsops.c +++ b/sys/fs/hpfs/hpfs_vfsops.c @@ -59,7 +59,7 @@ static int hpfs_root __P((struct mount *, struct vnode **)); static int hpfs_statfs __P((struct mount *, struct statfs *, struct thread *)); static int hpfs_unmount __P((struct mount *, int, struct thread *)); -static int hpfs_vget __P((struct mount *mp, ino_t ino, +static int hpfs_vget __P((struct mount *mp, ino_t ino, int flags, struct vnode **vpp)); static int hpfs_mountfs __P((register struct vnode *, struct mount *, struct hpfs_args *, struct thread *)); @@ -380,7 +380,7 @@ hpfs_root( struct hpfsmount *hpmp = VFSTOHPFS(mp); dprintf(("hpfs_root():\n")); - error = VFS_VGET(mp, (ino_t)hpmp->hpm_su.su_rootfno, vpp); + error = VFS_VGET(mp, (ino_t)hpmp->hpm_su.su_rootfno, LK_EXCLUSIVE, vpp); if(error) { printf("hpfs_root: VFS_VGET failed: %d\n",error); return (error); @@ -429,7 +429,7 @@ hpfs_fhtovp( struct hpfid *hpfhp = (struct hpfid *)fhp; int error; - if ((error = VFS_VGET(mp, hpfhp->hpfid_ino, &nvp)) != 0) { + if ((error = VFS_VGET(mp, hpfhp->hpfid_ino, LK_EXCLUSIVE, &nvp)) != 0) { *vpp = NULLVP; return (error); } @@ -460,6 +460,7 @@ static int hpfs_vget( struct mount *mp, ino_t ino, + int flags, struct vnode **vpp) { struct hpfsmount *hpmp = VFSTOHPFS(mp); @@ -475,7 +476,9 @@ hpfs_vget( hp = NULL; vp = NULL; - if ((*vpp = hpfs_hphashvget(hpmp->hpm_dev, ino, td)) != NULL) { + if ((error = hpfs_hphashvget(hpmp->hpm_dev, ino, flags, vpp, td)) != 0) + return (error); + if (*vpp != NULL) { dprintf(("hashed\n")); return (0); } @@ -531,7 +534,12 @@ hpfs_vget( } do { - if ((*vpp = hpfs_hphashvget(hpmp->hpm_dev, ino, td)) != NULL) { + if ((error = + hpfs_hphashvget(hpmp->hpm_dev, ino, flags, vpp, td))) { + vput(vp); + return (error); + } + if (*vpp != NULL) { dprintf(("hashed2\n")); vput(vp); return (0); diff --git a/sys/fs/hpfs/hpfs_vnops.c b/sys/fs/hpfs/hpfs_vnops.c index e3ed555..7b4d731 100644 --- a/sys/fs/hpfs/hpfs_vnops.c +++ b/sys/fs/hpfs/hpfs_vnops.c @@ -1096,21 +1096,18 @@ hpfs_lookup(ap) dprintf(("hpfs_lookup(0x%x,...): .. faked (0x%x)\n", dhp->h_no, dhp->h_fn.fn_parent)); - VOP_UNLOCK(dvp,0,cnp->cn_thread); - - error = VFS_VGET(hpmp->hpm_mp, - dhp->h_fn.fn_parent, ap->a_vpp); - if(error) { + if (VFS_VGET(hpmp->hpm_mp, dhp->h_fn.fn_parent, + LK_NOWAIT | LK_EXCLUSIVE, ap->a_vpp)) { + VOP_UNLOCK(dvp,0,cnp->cn_thread); + error = VFS_VGET(hpmp->hpm_mp, + dhp->h_fn.fn_parent, LK_EXCLUSIVE, ap->a_vpp); VOP_LOCK(dvp, 0, cnp->cn_thread); - return(error); - } - - if( lockparent && (flags & ISLASTCN) && - (error = VOP_LOCK(dvp, 0, cnp->cn_thread)) ) { - vput( *(ap->a_vpp) ); - return (error); + if(error) + return(error); } - return (error); + if (!lockparent || !(flags & ISLASTCN)) + VOP_UNLOCK(dvp,0,cnp->cn_thread); + return (0); } else { struct buf *bp; struct hpfsdirent *dep; @@ -1148,7 +1145,8 @@ hpfs_lookup(ap) return (0); } - error = VFS_VGET(hpmp->hpm_mp, dep->de_fnode, ap->a_vpp); + error = VFS_VGET(hpmp->hpm_mp, dep->de_fnode, LK_EXCLUSIVE, + ap->a_vpp); if (error) { printf("hpfs_lookup: VFS_VGET FAILED %d\n", error); brelse(bp); diff --git a/sys/fs/ntfs/ntfs_subr.c b/sys/fs/ntfs/ntfs_subr.c index f14d741..de239f0 100644 --- a/sys/fs/ntfs/ntfs_subr.c +++ b/sys/fs/ntfs/ntfs_subr.c @@ -1946,7 +1946,7 @@ ntfs_toupper_use(mp, ntmp) MALLOC(ntfs_toupper_tab, wchar *, 65536 * sizeof(wchar), M_NTFSRDATA, M_WAITOK); - if ((error = VFS_VGET(mp, NTFS_UPCASEINO, &vp))) + if ((error = VFS_VGET(mp, NTFS_UPCASEINO, LK_EXCLUSIVE, &vp))) goto out; error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 0, 65536*sizeof(wchar), (char *) ntfs_toupper_tab, NULL); diff --git a/sys/fs/ntfs/ntfs_vfsops.c b/sys/fs/ntfs/ntfs_vfsops.c index 712d4d3..48bacbe 100644 --- a/sys/fs/ntfs/ntfs_vfsops.c +++ b/sys/fs/ntfs/ntfs_vfsops.c @@ -68,7 +68,7 @@ static int ntfs_root __P((struct mount *, struct vnode **)); static int ntfs_statfs __P((struct mount *, struct statfs *, struct thread *)); static int ntfs_unmount __P((struct mount *, int, struct thread *)); -static int ntfs_vget __P((struct mount *mp, ino_t ino, +static int ntfs_vget __P((struct mount *mp, ino_t ino, int lkflags, struct vnode **vpp)); static int ntfs_mountfs __P((register struct vnode *, struct mount *, struct ntfs_args *, struct thread *)); @@ -367,7 +367,8 @@ ntfs_mountfs(devvp, mp, argsp, td) { int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO }; for (i=0; i<3; i++) { - error = VFS_VGET(mp, pi[i], &(ntmp->ntm_sysvn[pi[i]])); + error = VFS_VGET(mp, pi[i], LK_EXCLUSIVE, + &(ntmp->ntm_sysvn[pi[i]])); if(error) goto out1; ntmp->ntm_sysvn[pi[i]]->v_flag |= VSYSTEM; @@ -397,7 +398,7 @@ ntfs_mountfs(devvp, mp, argsp, td) struct attrdef ad; /* Open $AttrDef */ - error = VFS_VGET(mp, NTFS_ATTRDEFINO, &vp ); + error = VFS_VGET(mp, NTFS_ATTRDEFINO, LK_EXCLUSIVE, &vp ); if(error) goto out1; @@ -537,7 +538,7 @@ ntfs_root( dprintf(("ntfs_root(): sysvn: %p\n", VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO])); - error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, &nvp); + error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, LK_EXCLUSIVE, &nvp); if(error) { printf("ntfs_root: VFS_VGET failed: %d\n",error); return (error); @@ -625,7 +626,7 @@ ntfs_fhtovp( ddprintf(("ntfs_fhtovp(): %d\n", ntfhp->ntfid_ino)); - if ((error = VFS_VGET(mp, ntfhp->ntfid_ino, &nvp)) != 0) { + if ((error = VFS_VGET(mp, ntfhp->ntfid_ino, LK_EXCLUSIVE, &nvp)) != 0) { *vpp = NULLVP; return (error); } @@ -768,10 +769,11 @@ static int ntfs_vget( struct mount *mp, ino_t ino, + int lkflags, struct vnode **vpp) { - return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL, - LK_EXCLUSIVE | LK_RETRY, 0, curthread, vpp); + return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL, lkflags, 0, + curthread, vpp); } static struct vfsops ntfs_vfsops = { diff --git a/sys/fs/ntfs/ntfs_vnops.c b/sys/fs/ntfs/ntfs_vnops.c index e07914b..31b910b 100644 --- a/sys/fs/ntfs/ntfs_vnops.c +++ b/sys/fs/ntfs/ntfs_vnops.c @@ -629,8 +629,8 @@ ntfs_lookup(ap) dprintf(("ntfs_lookup: parentdir: %d\n", vap->va_a_name->n_pnumber)); - error = VFS_VGET(ntmp->ntm_mountp, - vap->va_a_name->n_pnumber,ap->a_vpp); + error = VFS_VGET(ntmp->ntm_mountp, vap->va_a_name->n_pnumber, + LK_EXCLUSIVE, ap->a_vpp); ntfs_ntvattrrele(vap); if (error) { if (vn_lock(dvp,LK_EXCLUSIVE|LK_RETRY,cnp->cn_thread)==0) diff --git a/sys/fs/nullfs/null_vfsops.c b/sys/fs/nullfs/null_vfsops.c index 1ab0aaa..d0a1ed1 100644 --- a/sys/fs/nullfs/null_vfsops.c +++ b/sys/fs/nullfs/null_vfsops.c @@ -73,7 +73,8 @@ static int nullfs_statfs(struct mount *mp, struct statfs *sbp, static int nullfs_sync(struct mount *mp, int waitfor, struct ucred *cred, struct thread *td); static int nullfs_unmount(struct mount *mp, int mntflags, struct thread *td); -static int nullfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp); +static int nullfs_vget(struct mount *mp, ino_t ino, int flags, + struct vnode **vpp); static int nullfs_vptofh(struct vnode *vp, struct fid *fhp); static int nullfs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, @@ -344,13 +345,14 @@ nullfs_sync(mp, waitfor, cred, td) } static int -nullfs_vget(mp, ino, vpp) +nullfs_vget(mp, ino, flags, vpp) struct mount *mp; ino_t ino; + int flags; struct vnode **vpp; { int error; - error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp); + error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, flags, vpp); if (error) return (error); diff --git a/sys/fs/smbfs/smbfs_vfsops.c b/sys/fs/smbfs/smbfs_vfsops.c index b3b5cd3..575585c 100644 --- a/sys/fs/smbfs/smbfs_vfsops.c +++ b/sys/fs/smbfs/smbfs_vfsops.c @@ -90,7 +90,8 @@ static int smbfs_init(struct vfsconf *vfsp); static int smbfs_uninit(struct vfsconf *vfsp); #if __FreeBSD_version < 400009 -static int smbfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp); +static int smbfs_vget(struct mount *mp, ino_t ino, int flags, + struct vnode **vpp); static int smbfs_fhtovp(struct mount *, struct fid *, struct sockaddr *, struct vnode **, int *, struct ucred **); @@ -467,9 +468,10 @@ loop: * smbfs flat namespace lookup. Unsupported. */ /* ARGSUSED */ -static int smbfs_vget(mp, ino, vpp) +static int smbfs_vget(mp, ino, flags, vpp) struct mount *mp; ino_t ino; + int flags; struct vnode **vpp; { return (EOPNOTSUPP); diff --git a/sys/fs/umapfs/umap_vfsops.c b/sys/fs/umapfs/umap_vfsops.c index a22b8df..17bfdc1 100644 --- a/sys/fs/umapfs/umap_vfsops.c +++ b/sys/fs/umapfs/umap_vfsops.c @@ -73,7 +73,7 @@ static int umapfs_sync __P((struct mount *mp, int waitfor, struct ucred *cred, struct thread *td)); static int umapfs_unmount __P((struct mount *mp, int mntflags, struct thread *td)); -static int umapfs_vget __P((struct mount *mp, ino_t ino, +static int umapfs_vget __P((struct mount *mp, ino_t ino, int flags, struct vnode **vpp)); static int umapfs_vptofh __P((struct vnode *vp, struct fid *fhp)); static int umapfs_extattrctl __P((struct mount *mp, int cmd, @@ -387,13 +387,14 @@ umapfs_sync(mp, waitfor, cred, td) } static int -umapfs_vget(mp, ino, vpp) +umapfs_vget(mp, ino, flags, vpp) struct mount *mp; ino_t ino; + int flags; struct vnode **vpp; { - return (VFS_VGET(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, ino, vpp)); + return (VFS_VGET(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, ino, flags, vpp)); } static int diff --git a/sys/gnu/ext2fs/ext2_alloc.c b/sys/gnu/ext2fs/ext2_alloc.c index 5b04196..f078e04 100644 --- a/sys/gnu/ext2fs/ext2_alloc.c +++ b/sys/gnu/ext2fs/ext2_alloc.c @@ -399,7 +399,7 @@ ext2_valloc(pvp, mode, cred, vpp) if (ino == 0) goto noinodes; - error = VFS_VGET(pvp->v_mount, ino, vpp); + error = VFS_VGET(pvp->v_mount, ino, LK_EXCLUSIVE, vpp); if (error) { UFS_VFREE(pvp, ino, mode); return (error); diff --git a/sys/gnu/ext2fs/ext2_ihash.c b/sys/gnu/ext2fs/ext2_ihash.c index d1537af..d31add3 100644 --- a/sys/gnu/ext2fs/ext2_ihash.c +++ b/sys/gnu/ext2fs/ext2_ihash.c @@ -93,15 +93,19 @@ ufs_ihashlookup(dev, inum) * Use the device/inum pair to find the incore inode, and return a pointer * to it. If it is in core, but locked, wait for it. */ -struct vnode * -ufs_ihashget(dev, inum) +int +ufs_ihashget(dev, inum, flags, vpp) dev_t dev; ino_t inum; + int flags; + struct vnode **vpp; { struct thread *td = curthread; /* XXX */ struct inode *ip; struct vnode *vp; + int error; + *vpp = NULL; loop: mtx_lock(&ufs_ihash_mtx); LIST_FOREACH(ip, INOHASH(dev, inum), i_hash) { @@ -109,13 +113,17 @@ loop: vp = ITOV(ip); mtx_lock(&vp->v_interlock); mtx_unlock(&ufs_ihash_mtx); - if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) + error = vget(vp, flags | LK_INTERLOCK, td); + if (error == ENOENT) goto loop; - return (vp); + if (error) + return (error); + *vpp = vp; + return (0); } } mtx_unlock(&ufs_ihash_mtx); - return (NULL); + return (0); } /* diff --git a/sys/gnu/ext2fs/ext2_lookup.c b/sys/gnu/ext2fs/ext2_lookup.c index b2e1511..50479e0 100644 --- a/sys/gnu/ext2fs/ext2_lookup.c +++ b/sys/gnu/ext2fs/ext2_lookup.c @@ -601,7 +601,8 @@ found: *vpp = vdp; return (0); } - if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) + if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, LK_EXCLUSIVE, + &tdp)) != 0) return (error); /* * If directory is "sticky", then user must own @@ -638,7 +639,8 @@ found: */ if (dp->i_number == dp->i_ino) return (EISDIR); - if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) + if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, LK_EXCLUSIVE, + &tdp)) != 0) return (error); *vpp = tdp; cnp->cn_flags |= SAVENAME; @@ -669,7 +671,8 @@ found: pdp = vdp; if (flags & ISDOTDOT) { VOP_UNLOCK(pdp, 0, td); /* race to get the inode */ - if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) { + if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, LK_EXCLUSIVE, + &tdp)) != 0) { vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, td); return (error); } @@ -683,7 +686,8 @@ found: VREF(vdp); /* we want ourself, ie "." */ *vpp = vdp; } else { - if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) + if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, LK_EXCLUSIVE, + &tdp)) != 0) return (error); if (!lockparent || !(flags & ISLASTCN)) VOP_UNLOCK(pdp, 0, td); @@ -1064,7 +1068,8 @@ ext2_checkpath(source, target, cred) if (dirbuf.dotdot_ino == rootino) break; vput(vp); - if ((error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino, &vp)) != 0) { + if ((error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino, + LK_EXCLUSIVE, &vp)) != 0) { vp = NULL; break; } diff --git a/sys/gnu/ext2fs/ext2_vfsops.c b/sys/gnu/ext2fs/ext2_vfsops.c index 15a94d9..8a7cc07 100644 --- a/sys/gnu/ext2fs/ext2_vfsops.c +++ b/sys/gnu/ext2fs/ext2_vfsops.c @@ -80,7 +80,7 @@ static int ext2_sbupdate __P((struct ufsmount *, int)); static int ext2_statfs __P((struct mount *, struct statfs *, struct thread *)); static int ext2_sync __P((struct mount *, int, struct ucred *, struct thread *)); static int ext2_unmount __P((struct mount *, int, struct thread *)); -static int ext2_vget __P((struct mount *, ino_t, struct vnode **)); +static int ext2_vget __P((struct mount *, ino_t, int, struct vnode **)); static int ext2_vptofh __P((struct vnode *, struct fid *)); static MALLOC_DEFINE(M_EXT2NODE, "EXT2 node", "EXT2 vnode private part"); @@ -982,9 +982,10 @@ loop: * done by the calling routine. */ static int -ext2_vget(mp, ino, vpp) +ext2_vget(mp, ino, flags, vpp) struct mount *mp; ino_t ino; + int flags; struct vnode **vpp; { register struct ext2_sb_info *fs; @@ -999,7 +1000,9 @@ ext2_vget(mp, ino, vpp) ump = VFSTOUFS(mp); dev = ump->um_dev; restart: - if ((*vpp = ufs_ihashget(dev, ino)) != NULL) + if ((error = ufs_ihashget(dev, ino, flags, vpp)) != 0) + return (error); + if (*vpp != NULL) return (0); /* diff --git a/sys/gnu/ext2fs/ext2_vnops.c b/sys/gnu/ext2fs/ext2_vnops.c index ad60728..a90c20f 100644 --- a/sys/gnu/ext2fs/ext2_vnops.c +++ b/sys/gnu/ext2fs/ext2_vnops.c @@ -285,7 +285,7 @@ ext2_mknod(ap) (*vpp)->v_type = VNON; ino = ip->i_number; /* Save this before vgone() invalidates ip. */ vgone(*vpp); - error = VFS_VGET(ap->a_dvp->v_mount, ino, vpp); + error = VFS_VGET(ap->a_dvp->v_mount, ino, LK_EXCLUSIVE, vpp); if (error) { *vpp = NULL; return (error); diff --git a/sys/gnu/fs/ext2fs/ext2_alloc.c b/sys/gnu/fs/ext2fs/ext2_alloc.c index 5b04196..f078e04 100644 --- a/sys/gnu/fs/ext2fs/ext2_alloc.c +++ b/sys/gnu/fs/ext2fs/ext2_alloc.c @@ -399,7 +399,7 @@ ext2_valloc(pvp, mode, cred, vpp) if (ino == 0) goto noinodes; - error = VFS_VGET(pvp->v_mount, ino, vpp); + error = VFS_VGET(pvp->v_mount, ino, LK_EXCLUSIVE, vpp); if (error) { UFS_VFREE(pvp, ino, mode); return (error); diff --git a/sys/gnu/fs/ext2fs/ext2_lookup.c b/sys/gnu/fs/ext2fs/ext2_lookup.c index b2e1511..50479e0 100644 --- a/sys/gnu/fs/ext2fs/ext2_lookup.c +++ b/sys/gnu/fs/ext2fs/ext2_lookup.c @@ -601,7 +601,8 @@ found: *vpp = vdp; return (0); } - if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) + if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, LK_EXCLUSIVE, + &tdp)) != 0) return (error); /* * If directory is "sticky", then user must own @@ -638,7 +639,8 @@ found: */ if (dp->i_number == dp->i_ino) return (EISDIR); - if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) + if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, LK_EXCLUSIVE, + &tdp)) != 0) return (error); *vpp = tdp; cnp->cn_flags |= SAVENAME; @@ -669,7 +671,8 @@ found: pdp = vdp; if (flags & ISDOTDOT) { VOP_UNLOCK(pdp, 0, td); /* race to get the inode */ - if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) { + if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, LK_EXCLUSIVE, + &tdp)) != 0) { vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, td); return (error); } @@ -683,7 +686,8 @@ found: VREF(vdp); /* we want ourself, ie "." */ *vpp = vdp; } else { - if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) + if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, LK_EXCLUSIVE, + &tdp)) != 0) return (error); if (!lockparent || !(flags & ISLASTCN)) VOP_UNLOCK(pdp, 0, td); @@ -1064,7 +1068,8 @@ ext2_checkpath(source, target, cred) if (dirbuf.dotdot_ino == rootino) break; vput(vp); - if ((error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino, &vp)) != 0) { + if ((error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino, + LK_EXCLUSIVE, &vp)) != 0) { vp = NULL; break; } diff --git a/sys/gnu/fs/ext2fs/ext2_vfsops.c b/sys/gnu/fs/ext2fs/ext2_vfsops.c index 15a94d9..8a7cc07 100644 --- a/sys/gnu/fs/ext2fs/ext2_vfsops.c +++ b/sys/gnu/fs/ext2fs/ext2_vfsops.c @@ -80,7 +80,7 @@ static int ext2_sbupdate __P((struct ufsmount *, int)); static int ext2_statfs __P((struct mount *, struct statfs *, struct thread *)); static int ext2_sync __P((struct mount *, int, struct ucred *, struct thread *)); static int ext2_unmount __P((struct mount *, int, struct thread *)); -static int ext2_vget __P((struct mount *, ino_t, struct vnode **)); +static int ext2_vget __P((struct mount *, ino_t, int, struct vnode **)); static int ext2_vptofh __P((struct vnode *, struct fid *)); static MALLOC_DEFINE(M_EXT2NODE, "EXT2 node", "EXT2 vnode private part"); @@ -982,9 +982,10 @@ loop: * done by the calling routine. */ static int -ext2_vget(mp, ino, vpp) +ext2_vget(mp, ino, flags, vpp) struct mount *mp; ino_t ino; + int flags; struct vnode **vpp; { register struct ext2_sb_info *fs; @@ -999,7 +1000,9 @@ ext2_vget(mp, ino, vpp) ump = VFSTOUFS(mp); dev = ump->um_dev; restart: - if ((*vpp = ufs_ihashget(dev, ino)) != NULL) + if ((error = ufs_ihashget(dev, ino, flags, vpp)) != 0) + return (error); + if (*vpp != NULL) return (0); /* diff --git a/sys/gnu/fs/ext2fs/ext2_vnops.c b/sys/gnu/fs/ext2fs/ext2_vnops.c index ad60728..a90c20f 100644 --- a/sys/gnu/fs/ext2fs/ext2_vnops.c +++ b/sys/gnu/fs/ext2fs/ext2_vnops.c @@ -285,7 +285,7 @@ ext2_mknod(ap) (*vpp)->v_type = VNON; ino = ip->i_number; /* Save this before vgone() invalidates ip. */ vgone(*vpp); - error = VFS_VGET(ap->a_dvp->v_mount, ino, vpp); + error = VFS_VGET(ap->a_dvp->v_mount, ino, LK_EXCLUSIVE, vpp); if (error) { *vpp = NULL; return (error); diff --git a/sys/isofs/cd9660/cd9660_lookup.c b/sys/isofs/cd9660/cd9660_lookup.c index 706a7ae..da927e1 100644 --- a/sys/isofs/cd9660/cd9660_lookup.c +++ b/sys/isofs/cd9660/cd9660_lookup.c @@ -352,7 +352,8 @@ found: */ if (flags & ISDOTDOT) { VOP_UNLOCK(pdp, 0, td); /* race to get the inode */ - error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, &tdp, + error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, + LK_EXCLUSIVE, &tdp, dp->i_ino != ino, ep); brelse(bp); if (error) { @@ -373,7 +374,8 @@ found: VREF(vdp); /* we want ourself, ie "." */ *vpp = vdp; } else { - error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, &tdp, + error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, + LK_EXCLUSIVE, &tdp, dp->i_ino != ino, ep); brelse(bp); if (error) diff --git a/sys/isofs/cd9660/cd9660_node.c b/sys/isofs/cd9660/cd9660_node.c index 53ffeca..0060364 100644 --- a/sys/isofs/cd9660/cd9660_node.c +++ b/sys/isofs/cd9660/cd9660_node.c @@ -92,15 +92,19 @@ cd9660_uninit(vfsp) * Use the device/inum pair to find the incore inode, and return a pointer * to it. If it is in core, but locked, wait for it. */ -struct vnode * -cd9660_ihashget(dev, inum) +int +cd9660_ihashget(dev, inum, flags, vpp) dev_t dev; ino_t inum; + int flags; + struct vnode **vpp; { struct thread *td = curthread; /* XXX */ struct iso_node *ip; struct vnode *vp; + int error; + *vpp = NULL; loop: mtx_lock(&cd9660_ihash_mtx); for (ip = isohashtbl[INOHASH(dev, inum)]; ip; ip = ip->i_next) { @@ -108,13 +112,17 @@ loop: vp = ITOV(ip); mtx_lock(&vp->v_interlock); mtx_unlock(&cd9660_ihash_mtx); - if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) + error = vget(vp, flags | LK_INTERLOCK, td); + if (error == ENOENT) goto loop; - return (vp); + if (error) + return (error); + *vpp = vp; + return (0); } } mtx_unlock(&cd9660_ihash_mtx); - return (NULL); + return (0); } /* diff --git a/sys/isofs/cd9660/cd9660_node.h b/sys/isofs/cd9660/cd9660_node.h index 100c08e..2a0d7ef 100644 --- a/sys/isofs/cd9660/cd9660_node.h +++ b/sys/isofs/cd9660/cd9660_node.h @@ -117,7 +117,7 @@ void cd9660_defattr __P((struct iso_directory_record *, struct iso_node *, struct buf *, enum ISO_FTYPE)); void cd9660_deftstamp __P((struct iso_directory_record *, struct iso_node *, struct buf *, enum ISO_FTYPE)); -struct vnode *cd9660_ihashget __P((dev_t, ino_t)); +int cd9660_ihashget __P((dev_t, ino_t, int, struct vnode **)); void cd9660_ihashins __P((struct iso_node *)); int cd9660_tstamp_conv7 __P((u_char *, struct timespec *, enum ISO_FTYPE)); int cd9660_tstamp_conv17 __P((u_char *, struct timespec *)); diff --git a/sys/isofs/cd9660/cd9660_vfsops.c b/sys/isofs/cd9660/cd9660_vfsops.c index 1e3719d..60a7b38 100644 --- a/sys/isofs/cd9660/cd9660_vfsops.c +++ b/sys/isofs/cd9660/cd9660_vfsops.c @@ -69,7 +69,7 @@ static int cd9660_mount __P((struct mount *, static int cd9660_unmount __P((struct mount *, int, struct thread *)); static int cd9660_root __P((struct mount *, struct vnode **)); static int cd9660_statfs __P((struct mount *, struct statfs *, struct thread *)); -static int cd9660_vget __P((struct mount *, ino_t, struct vnode **)); +static int cd9660_vget __P((struct mount *, ino_t, int, struct vnode **)); static int cd9660_fhtovp __P((struct mount *, struct fid *, struct vnode **)); static int cd9660_vptofh __P((struct vnode *, struct fid *)); @@ -578,7 +578,7 @@ cd9660_root(mp, vpp) * With RRIP we must use the `.' entry of the root directory. * Simply tell vget, that it's a relocated directory. */ - return (cd9660_vget_internal(mp, ino, vpp, + return (cd9660_vget_internal(mp, ino, LK_EXCLUSIVE, vpp, imp->iso_ftype == ISO_FTYPE_RRIP, dp)); } @@ -644,7 +644,7 @@ cd9660_fhtovp(mp, fhp, vpp) ifhp->ifid_ino, ifhp->ifid_start); #endif - if ((error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) != 0) { + if ((error = VFS_VGET(mp, ifhp->ifid_ino, LK_EXCLUSIVE, &nvp)) != 0) { *vpp = NULLVP; return (error); } @@ -659,9 +659,10 @@ cd9660_fhtovp(mp, fhp, vpp) } int -cd9660_vget(mp, ino, vpp) +cd9660_vget(mp, ino, flags, vpp) struct mount *mp; ino_t ino; + int flags; struct vnode **vpp; { @@ -671,7 +672,7 @@ cd9660_vget(mp, ino, vpp) * and force the extra read, but I don't want to think about fixing * that right now. */ - return (cd9660_vget_internal(mp, ino, vpp, + return (cd9660_vget_internal(mp, ino, flags, vpp, #if 0 VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP, #else @@ -681,9 +682,10 @@ cd9660_vget(mp, ino, vpp) } int -cd9660_vget_internal(mp, ino, vpp, relocated, isodir) +cd9660_vget_internal(mp, ino, flags, vpp, relocated, isodir) struct mount *mp; ino_t ino; + int flags; struct vnode **vpp; int relocated; struct iso_directory_record *isodir; @@ -697,7 +699,9 @@ cd9660_vget_internal(mp, ino, vpp, relocated, isodir) imp = VFSTOISOFS(mp); dev = imp->im_dev; - if ((*vpp = cd9660_ihashget(dev, ino)) != NULLVP) + if ((error = cd9660_ihashget(dev, ino, flags, vpp)) != 0) + return (error); + if (*vpp != NULL) return (0); /* Allocate a new vnode/iso_node. */ @@ -718,6 +722,18 @@ cd9660_vget_internal(mp, ino, vpp, relocated, isodir) ip->i_number = ino; /* + * Check to be sure that it did not show up. We have to put it + * on the hash chain as the cleanup from vput expects to find + * it there. + */ + if ((error = cd9660_ihashget(dev, ino, flags, vpp)) != 0 || + *vpp != NULL) { + cd9660_ihashins(ip); + vput(vp); + return (error); + } + + /* * Put it onto its hash chain and lock it so that other requests for * this inode will block if they arrive while we are sleeping waiting * for old data structures to be purged or for the contents of the diff --git a/sys/isofs/cd9660/iso.h b/sys/isofs/cd9660/iso.h index b62c723..453423a 100644 --- a/sys/isofs/cd9660/iso.h +++ b/sys/isofs/cd9660/iso.h @@ -254,7 +254,7 @@ struct iso_mnt { #define lblkno(imp, loc) ((loc) >> (imp)->im_bshift) #define blksize(imp, ip, lbn) ((imp)->logical_block_size) -int cd9660_vget_internal __P((struct mount *, ino_t, struct vnode **, int, +int cd9660_vget_internal __P((struct mount *, ino_t, int, struct vnode **, int, struct iso_directory_record *)); int cd9660_init __P((struct vfsconf *)); int cd9660_uninit __P((struct vfsconf *)); diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c index dab13c2..9a3a3c1 100644 --- a/sys/kern/vfs_default.c +++ b/sys/kern/vfs_default.c @@ -802,9 +802,10 @@ vfs_stdsync (mp, waitfor, cred, td) } int -vfs_stdvget (mp, ino, vpp) +vfs_stdvget (mp, ino, flags, vpp) struct mount *mp; ino_t ino; + int flags; struct vnode **vpp; { return (EOPNOTSUPP); diff --git a/sys/nfsserver/nfs_serv.c b/sys/nfsserver/nfs_serv.c index 17aea87..2d79643 100644 --- a/sys/nfsserver/nfs_serv.c +++ b/sys/nfsserver/nfs_serv.c @@ -3428,7 +3428,8 @@ again: * Probe one of the directory entries to see if the filesystem * supports VGET. */ - if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp) == EOPNOTSUPP) { + if (VFS_VGET(vp->v_mount, dp->d_fileno, LK_EXCLUSIVE, &nvp) == + EOPNOTSUPP) { error = NFSERR_NOTSUPP; vrele(vp); vp = NULL; @@ -3462,7 +3463,8 @@ again: * For readdir_and_lookup get the vnode using * the file number. */ - if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) + if (VFS_VGET(vp->v_mount, dp->d_fileno, LK_EXCLUSIVE, + &nvp)) goto invalid; bzero((caddr_t)nfhp, NFSX_V3FH); nfhp->fh_fsid = diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 5cd748d..505e034 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -358,7 +358,7 @@ struct vfsops { struct thread *td)); int (*vfs_sync) __P((struct mount *mp, int waitfor, struct ucred *cred, struct thread *td)); - int (*vfs_vget) __P((struct mount *mp, ino_t ino, + int (*vfs_vget) __P((struct mount *mp, ino_t ino, int flags, struct vnode **vpp)); int (*vfs_fhtovp) __P((struct mount *mp, struct fid *fhp, struct vnode **vpp)); @@ -381,7 +381,8 @@ struct vfsops { #define VFS_QUOTACTL(MP,C,U,A,P) (*(MP)->mnt_op->vfs_quotactl)(MP, C, U, A, P) #define VFS_STATFS(MP, SBP, P) (*(MP)->mnt_op->vfs_statfs)(MP, SBP, P) #define VFS_SYNC(MP, WAIT, C, P) (*(MP)->mnt_op->vfs_sync)(MP, WAIT, C, P) -#define VFS_VGET(MP, INO, VPP) (*(MP)->mnt_op->vfs_vget)(MP, INO, VPP) +#define VFS_VGET(MP, INO, FLAGS, VPP) \ + (*(MP)->mnt_op->vfs_vget)(MP, INO, FLAGS, VPP) #define VFS_FHTOVP(MP, FIDP, VPP) \ (*(MP)->mnt_op->vfs_fhtovp)(MP, FIDP, VPP) #define VFS_VPTOFH(VP, FIDP) (*(VP)->v_mount->mnt_op->vfs_vptofh)(VP, FIDP) @@ -456,7 +457,7 @@ int vfs_stdquotactl __P((struct mount *mp, int cmds, uid_t uid, int vfs_stdstatfs __P((struct mount *mp, struct statfs *sbp, struct thread *td)); int vfs_stdsync __P((struct mount *mp, int waitfor, struct ucred *cred, struct thread *td)); -int vfs_stdvget __P((struct mount *mp, ino_t ino, struct vnode **vpp)); +int vfs_stdvget __P((struct mount *mp, ino_t ino, int, struct vnode **vpp)); int vfs_stdfhtovp __P((struct mount *mp, struct fid *fhp, struct vnode **vpp)); int vfs_stdcheckexp __P((struct mount *mp, struct sockaddr *nam, int *extflagsp, struct ucred **credanonp)); diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index 93e8c99..374c0b9 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -629,7 +629,7 @@ ffs_valloc(pvp, mode, cred, vpp) (allocfcn_t *)ffs_nodealloccg); if (ino == 0) goto noinodes; - error = VFS_VGET(pvp->v_mount, ino, vpp); + error = VFS_VGET(pvp->v_mount, ino, LK_EXCLUSIVE, vpp); if (error) { UFS_VFREE(pvp, ino, mode); return (error); @@ -1977,7 +1977,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) cmd.size); } #endif /* DEBUG */ - if ((error = VFS_VGET(mp, (ino_t)cmd.value, &vp)) != 0) + if ((error = VFS_VGET(mp, (ino_t)cmd.value, LK_EXCLUSIVE, &vp))) break; ip = VTOI(vp); ip->i_nlink += cmd.size; @@ -1996,7 +1996,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) cmd.size); } #endif /* DEBUG */ - if ((error = VFS_VGET(mp, (ino_t)cmd.value, &vp)) != 0) + if ((error = VFS_VGET(mp, (ino_t)cmd.value, LK_EXCLUSIVE, &vp))) break; ip = VTOI(vp); ip->i_blocks += cmd.size; diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index cfcdcbd..1da7153 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -93,7 +93,7 @@ int ffs_update __P((struct vnode *, int)); int ffs_valloc __P((struct vnode *, int, struct ucred *, struct vnode **)); int ffs_vfree __P((struct vnode *, ino_t, int)); -int ffs_vget __P((struct mount *, ino_t, struct vnode **)); +int ffs_vget __P((struct mount *, ino_t, int, struct vnode **)); int ffs_vptofh __P((struct vnode *, struct fid *)); extern vop_t **ffs_vnodeop_p; diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index faca50f..a14fbea 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -1177,7 +1177,8 @@ ffs_snapshot_mount(mp) for (snaploc = 0; snaploc < FSMAXSNAP; snaploc++) { if (fs->fs_snapinum[snaploc] == 0) return; - if ((error = VFS_VGET(mp, fs->fs_snapinum[snaploc], &vp)) != 0){ + if ((error = VFS_VGET(mp, fs->fs_snapinum[snaploc], + LK_EXCLUSIVE, &vp)) != 0){ printf("ffs_snapshot_mount: vget failed %d\n", error); continue; } diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 475ba17..5110b8c 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -165,7 +165,7 @@ static void initiate_write_filepage __P((struct pagedep *, struct buf *)); static void handle_written_mkdir __P((struct mkdir *, int)); static void initiate_write_inodeblock __P((struct inodedep *, struct buf *)); static void handle_workitem_freefile __P((struct freefile *)); -static void handle_workitem_remove __P((struct dirrem *)); +static void handle_workitem_remove __P((struct dirrem *, struct vnode *)); static struct dirrem *newdirrem __P((struct buf *, struct inode *, struct inode *, int, struct dirrem **)); static void free_diradd __P((struct diradd *)); @@ -580,7 +580,7 @@ softdep_process_worklist(matchmnt) struct mount *matchmnt; { struct thread *td = curthread; - int matchcnt, loopcount; + int cnt, matchcnt, loopcount; long starttime; /* @@ -618,7 +618,10 @@ softdep_process_worklist(matchmnt) loopcount = 1; starttime = time_second; while (num_on_worklist > 0) { - matchcnt += process_worklist_item(matchmnt, 0); + if ((cnt = process_worklist_item(matchmnt, 0)) == -1) + break; + else + matchcnt += cnt; /* * If a umount operation wants to run the worklist @@ -675,7 +678,6 @@ process_worklist_item(matchmnt, flags) int flags; { struct worklist *wk; - struct dirrem *dirrem; struct mount *mp; struct vnode *vp; int matchcnt = 0; @@ -687,13 +689,19 @@ process_worklist_item(matchmnt, flags) * inodes, we have to skip over any dirrem requests whose * vnodes are resident and locked. */ + vp = NULL; LIST_FOREACH(wk, &softdep_workitem_pending, wk_list) { + if (wk->wk_state & INPROGRESS) + continue; if ((flags & LK_NOWAIT) == 0 || wk->wk_type != D_DIRREM) break; - dirrem = WK_DIRREM(wk); - vp = ufs_ihashlookup(VFSTOUFS(dirrem->dm_mnt)->um_dev, - dirrem->dm_oldinum); - if (vp == NULL || !VOP_ISLOCKED(vp, curthread)) + wk->wk_state |= INPROGRESS; + FREE_LOCK(&lk); + VFS_VGET(WK_DIRREM(wk)->dm_mnt, WK_DIRREM(wk)->dm_oldinum, + LK_NOWAIT | LK_EXCLUSIVE, &vp); + ACQUIRE_LOCK(&lk); + wk->wk_state &= ~INPROGRESS; + if (vp != NULL) break; } if (wk == 0) { @@ -713,7 +721,7 @@ process_worklist_item(matchmnt, flags) "process_worklist_item"); if (mp == matchmnt) matchcnt += 1; - handle_workitem_remove(WK_DIRREM(wk)); + handle_workitem_remove(WK_DIRREM(wk), vp); break; case D_FREEBLKS: @@ -2280,8 +2288,9 @@ handle_workitem_freeblocks(freeblks, flags) * to see if the block count needs to be adjusted. */ if (freeblks->fb_chkcnt != blocksreleased && - (fs->fs_flags & FS_UNCLEAN) != 0 && (flags & LK_NOWAIT) == 0 && - VFS_VGET(freeblks->fb_mnt, freeblks->fb_previousinum, &vp) == 0) { + (fs->fs_flags & FS_UNCLEAN) != 0 && + VFS_VGET(freeblks->fb_mnt, freeblks->fb_previousinum, + (flags & LK_NOWAIT) | LK_EXCLUSIVE, &vp) == 0) { ip = VTOI(vp); ip->i_blocks += freeblks->fb_chkcnt - blocksreleased; ip->i_flag |= IN_CHANGE; @@ -2742,7 +2751,7 @@ softdep_setup_remove(bp, dp, ip, isrmdir) prevdirrem, dm_next); dirrem->dm_dirinum = dirrem->dm_pagedep->pd_ino; FREE_LOCK(&lk); - handle_workitem_remove(dirrem); + handle_workitem_remove(dirrem, NULL); } } @@ -3033,8 +3042,9 @@ softdep_releasefile(ip) * If the link count reaches zero, the file is removed. */ static void -handle_workitem_remove(dirrem) +handle_workitem_remove(dirrem, xp) struct dirrem *dirrem; + struct vnode *xp; { struct thread *td = curthread; struct inodedep *inodedep; @@ -3043,7 +3053,9 @@ handle_workitem_remove(dirrem) ino_t oldinum; int error; - if ((error = VFS_VGET(dirrem->dm_mnt, dirrem->dm_oldinum, &vp)) != 0) { + if ((vp = xp) == NULL && + (error = VFS_VGET(dirrem->dm_mnt, dirrem->dm_oldinum, LK_EXCLUSIVE, + &vp)) != 0) { softdep_error("handle_workitem_remove: vget", error); return; } @@ -3112,7 +3124,7 @@ handle_workitem_remove(dirrem) check_inode_unwritten(inodedep)) { FREE_LOCK(&lk); vput(vp); - handle_workitem_remove(dirrem); + handle_workitem_remove(dirrem, NULL); return; } WORKLIST_INSERT(&inodedep->id_inowait, &dirrem->dm_list); @@ -4228,16 +4240,19 @@ softdep_fsync(vp) /* * We prevent deadlock by always fetching inodes from the * root, moving down the directory tree. Thus, when fetching - * our parent directory, we must unlock ourselves before - * requesting the lock on our parent. See the comment in - * ufs_lookup for details on possible races. + * our parent directory, we first try to get the lock. If + * that fails, we must unlock ourselves before requesting + * the lock on our parent. See the comment in ufs_lookup + * for details on possible races. */ FREE_LOCK(&lk); - VOP_UNLOCK(vp, 0, td); - error = VFS_VGET(mnt, parentino, &pvp); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - if (error != 0) - return (error); + if (VFS_VGET(mnt, parentino, LK_NOWAIT | LK_EXCLUSIVE, &pvp)) { + VOP_UNLOCK(vp, 0, td); + error = VFS_VGET(mnt, parentino, LK_EXCLUSIVE, &pvp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); + if (error != 0) + return (error); + } /* * All MKDIR_PARENT dependencies and all the NEWBLOCK pagedeps * that are contained in direct blocks will be resolved by @@ -4735,7 +4750,7 @@ flush_pagedep_deps(pvp, mp, diraddhdp) inum = dap->da_newinum; if (dap->da_state & MKDIR_BODY) { FREE_LOCK(&lk); - if ((error = VFS_VGET(mp, inum, &vp)) != 0) + if ((error = VFS_VGET(mp, inum, LK_EXCLUSIVE, &vp))) break; if ((error=VOP_FSYNC(vp, td->td_ucred, MNT_NOWAIT, td)) || (error=VOP_FSYNC(vp, td->td_ucred, MNT_NOWAIT, td))) { @@ -4999,7 +5014,7 @@ clear_remove(td) FREE_LOCK(&lk); if (vn_start_write(NULL, &mp, V_NOWAIT) != 0) continue; - if ((error = VFS_VGET(mp, ino, &vp)) != 0) { + if ((error = VFS_VGET(mp, ino, LK_EXCLUSIVE, &vp))) { softdep_error("clear_remove: vget", error); vn_finished_write(mp); return; @@ -5072,7 +5087,7 @@ clear_inodedeps(td) FREE_LOCK(&lk); if (vn_start_write(NULL, &mp, V_NOWAIT) != 0) continue; - if ((error = VFS_VGET(mp, ino, &vp)) != 0) { + if ((error = VFS_VGET(mp, ino, LK_EXCLUSIVE, &vp)) != 0) { softdep_error("clear_inodedeps: vget", error); vn_finished_write(mp); return; diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index ce4198c..025d30a 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -158,7 +158,6 @@ ffs_mount(mp, path, data, ndp, td) if ((error = ffs_mountfs(rootvp, mp, td, M_FFSNODE)) != 0) return (error); - (void)VFS_STATFS(mp, &mp->mnt_stat, td); return (0); } @@ -1143,9 +1142,10 @@ static int ffs_inode_hash_lock; static struct mtx ffs_inode_hash_mtx; int -ffs_vget(mp, ino, vpp) +ffs_vget(mp, ino, flags, vpp) struct mount *mp; ino_t ino; + int flags; struct vnode **vpp; { struct fs *fs; @@ -1159,9 +1159,10 @@ ffs_vget(mp, ino, vpp) ump = VFSTOUFS(mp); dev = ump->um_dev; restart: - if ((*vpp = ufs_ihashget(dev, ino)) != NULL) { + if ((error = ufs_ihashget(dev, ino, flags, vpp)) != 0) + return (error); + if (*vpp != NULL) return (0); - } /* * Lock out the creation of new entries in the FFS hash table in diff --git a/sys/ufs/ffs/softdep.h b/sys/ufs/ffs/softdep.h index 5610bdc..cdb1f68 100644 --- a/sys/ufs/ffs/softdep.h +++ b/sys/ufs/ffs/softdep.h @@ -101,6 +101,7 @@ #define IOSTARTED 0x0200 /* inodedep & pagedep only */ #define SPACECOUNTED 0x0400 /* inodedep only */ #define NEWBLOCK 0x0800 /* pagedep only */ +#define INPROGRESS 0x1000 /* dirrem, freeblks, freefrag, freefile only */ #define ONWORKLIST 0x8000 #define ALLCOMPLETE (ATTACHED | COMPLETE | DEPCOMPLETE) diff --git a/sys/ufs/ifs/ifs_lookup.c b/sys/ufs/ifs/ifs_lookup.c index c6e5873..510b02b 100644 --- a/sys/ufs/ifs/ifs_lookup.c +++ b/sys/ufs/ifs/ifs_lookup.c @@ -242,7 +242,7 @@ ifs_lookup(ap) return ENOENT; } /* Now, we can get the vnode */ - error = VFS_VGET(vdp->v_mount, (long)inodenum, &tdp); + error = VFS_VGET(vdp->v_mount, (long)inodenum, LK_EXCLUSIVE, &tdp); if (error) return (error); if (!lockparent || !(flags & ISLASTCN)) diff --git a/sys/ufs/ifs/ifs_vfsops.c b/sys/ufs/ifs/ifs_vfsops.c index 7eade14..b86048f 100644 --- a/sys/ufs/ifs/ifs_vfsops.c +++ b/sys/ufs/ifs/ifs_vfsops.c @@ -71,7 +71,7 @@ static MALLOC_DEFINE(M_IFSNODE, "IFS node", "IFS vnode private part"); static int ifs_init (struct vfsconf *); static int ifs_mount (struct mount *, char *, caddr_t, struct nameidata *, struct thread *); -extern int ifs_vget (struct mount *, ino_t, struct vnode **); +extern int ifs_vget (struct mount *, ino_t, int, struct vnode **); @@ -151,9 +151,10 @@ ifs_init(vfsp) } int -ifs_vget(mp, ino, vpp) +ifs_vget(mp, ino, flags, vpp) struct mount *mp; ino_t ino; + int flags; struct vnode **vpp; { struct fs *fs; @@ -167,9 +168,10 @@ ifs_vget(mp, ino, vpp) ump = VFSTOUFS(mp); dev = ump->um_dev; restart: - if ((*vpp = ufs_ihashget(dev, ino)) != NULL) { + if ((error = ufs_ihashget(dev, ino, flags, vpp)) != 0) + return (error); + if (*vpp != NULL) return (0); - } /* * Lock out the creation of new entries in the FFS hash table in diff --git a/sys/ufs/ufs/ufs_extern.h b/sys/ufs/ufs/ufs_extern.h index c4e2795..dc59164 100644 --- a/sys/ufs/ufs/ufs_extern.h +++ b/sys/ufs/ufs/ufs_extern.h @@ -74,8 +74,7 @@ int ufs_direnter __P((struct vnode *, struct vnode *, struct direct *, int ufs_dirremove __P((struct vnode *, struct inode *, int, int)); int ufs_dirrewrite __P((struct inode *, struct inode *, ino_t, int, int)); int ufs_getlbns __P((struct vnode *, ufs_daddr_t, struct indir *, int *)); -struct vnode * - ufs_ihashget __P((dev_t, ino_t)); +int ufs_ihashget __P((dev_t, ino_t, int, struct vnode **)); void ufs_ihashinit __P((void)); void ufs_ihashins __P((struct inode *)); struct vnode * diff --git a/sys/ufs/ufs/ufs_ihash.c b/sys/ufs/ufs/ufs_ihash.c index d1537af..d31add3 100644 --- a/sys/ufs/ufs/ufs_ihash.c +++ b/sys/ufs/ufs/ufs_ihash.c @@ -93,15 +93,19 @@ ufs_ihashlookup(dev, inum) * Use the device/inum pair to find the incore inode, and return a pointer * to it. If it is in core, but locked, wait for it. */ -struct vnode * -ufs_ihashget(dev, inum) +int +ufs_ihashget(dev, inum, flags, vpp) dev_t dev; ino_t inum; + int flags; + struct vnode **vpp; { struct thread *td = curthread; /* XXX */ struct inode *ip; struct vnode *vp; + int error; + *vpp = NULL; loop: mtx_lock(&ufs_ihash_mtx); LIST_FOREACH(ip, INOHASH(dev, inum), i_hash) { @@ -109,13 +113,17 @@ loop: vp = ITOV(ip); mtx_lock(&vp->v_interlock); mtx_unlock(&ufs_ihash_mtx); - if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) + error = vget(vp, flags | LK_INTERLOCK, td); + if (error == ENOENT) goto loop; - return (vp); + if (error) + return (error); + *vpp = vp; + return (0); } } mtx_unlock(&ufs_ihash_mtx); - return (NULL); + return (0); } /* diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c index bbb07af..a668a18 100644 --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -508,14 +508,8 @@ found: *vpp = vdp; return (0); } - if (flags & ISDOTDOT) - VOP_UNLOCK(vdp, 0, td); /* race to get the inode */ - error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp); - if (flags & ISDOTDOT) { - if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, td) != 0) - cnp->cn_flags |= PDIRUNLOCK; - } - if (error) + if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, + LK_EXCLUSIVE, &tdp)) != 0) return (error); /* * If directory is "sticky", then user must own @@ -544,7 +538,7 @@ found: * regular file, or empty directory. */ if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) { - if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread)) != 0) + if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread))) return (error); /* * Careful about locking second inode. @@ -552,14 +546,8 @@ found: */ if (dp->i_number == dp->i_ino) return (EISDIR); - if (flags & ISDOTDOT) - VOP_UNLOCK(vdp, 0, td); /* race to get the inode */ - error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp); - if (flags & ISDOTDOT) { - if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, td) != 0) - cnp->cn_flags |= PDIRUNLOCK; - } - if (error) + if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, + LK_EXCLUSIVE, &tdp)) != 0) return (error); *vpp = tdp; cnp->cn_flags |= SAVENAME; @@ -591,26 +579,25 @@ found: */ pdp = vdp; if (flags & ISDOTDOT) { - VOP_UNLOCK(pdp, 0, td); /* race to get the inode */ - cnp->cn_flags |= PDIRUNLOCK; - if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) { - if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, td) == 0) - cnp->cn_flags &= ~PDIRUNLOCK; - return (error); - } - if (lockparent && (flags & ISLASTCN)) { - if ((error = vn_lock(pdp, LK_EXCLUSIVE, td)) != 0) { - vput(tdp); + if ((VFS_VGET(pdp->v_mount, dp->i_ino, LK_NOWAIT | LK_EXCLUSIVE, + &tdp)) != 0) { + VOP_UNLOCK(pdp, 0, td); /* race to get the inode */ + error = VFS_VGET(pdp->v_mount, dp->i_ino, + LK_EXCLUSIVE, &tdp); + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, td); + if (error) return (error); - } - cnp->cn_flags &= ~PDIRUNLOCK; + } + if (!lockparent || !(flags & ISLASTCN)) { + VOP_UNLOCK(pdp, 0, td); + cnp->cn_flags |= PDIRUNLOCK; } *vpp = tdp; } else if (dp->i_number == dp->i_ino) { VREF(vdp); /* we want ourself, ie "." */ *vpp = vdp; } else { - error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp); + error = VFS_VGET(pdp->v_mount, dp->i_ino, LK_EXCLUSIVE, &tdp); if (error) return (error); if (!lockparent || !(flags & ISLASTCN)) { @@ -1254,7 +1241,8 @@ ufs_checkpath(source, target, cred) if (dirbuf.dotdot_ino == rootino) break; vput(vp); - error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino, &vp); + error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino, + LK_EXCLUSIVE, &vp); if (error) { vp = NULL; break; diff --git a/sys/ufs/ufs/ufs_vfsops.c b/sys/ufs/ufs/ufs_vfsops.c index e6cbd6c..c9176d9 100644 --- a/sys/ufs/ufs/ufs_vfsops.c +++ b/sys/ufs/ufs/ufs_vfsops.c @@ -84,7 +84,7 @@ ufs_root(mp, vpp) struct vnode *nvp; int error; - error = VFS_VGET(mp, (ino_t)ROOTINO, &nvp); + error = VFS_VGET(mp, (ino_t)ROOTINO, LK_EXCLUSIVE, &nvp); if (error) return (error); *vpp = nvp; @@ -199,7 +199,7 @@ ufs_fhtovp(mp, ufhp, vpp) struct vnode *nvp; int error; - error = VFS_VGET(mp, ufhp->ufid_ino, &nvp); + error = VFS_VGET(mp, ufhp->ufid_ino, LK_EXCLUSIVE, &nvp); if (error) { *vpp = NULLVP; return (error); diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index bf05ff3..9dd3eab 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -244,7 +244,7 @@ ufs_mknod(ap) (*vpp)->v_type = VNON; ino = ip->i_number; /* Save this before vgone() invalidates ip. */ vgone(*vpp); - error = VFS_VGET(ap->a_dvp->v_mount, ino, vpp); + error = VFS_VGET(ap->a_dvp->v_mount, ino, LK_EXCLUSIVE, vpp); if (error) { *vpp = NULL; return (error); |