From afe7539a613df113c18cbcdc62d6c6677978ab0b Mon Sep 17 00:00:00 2001 From: Taylor R Campbell Date: Tue, 8 Apr 2014 05:24:50 +0000 Subject: [PATCH 02/14] Make VFS_ROOT, VFS_VGET, and VFS_FHTOVP return unlocked vnodes. - Change the signature of these so existing uses fail to compile. - Change each implementation to unlock the vnode on success. - Change each caller to lock the vnode on success. The signature change currently serves no functional purpose, but may become useful later to allow non-blocking or interruption. This is part of a larger scheme to disentangle referencing vnodes from preserving invariants during operations on vnodes with the vnode lock. This change adds code to unlock and relock the vnode in every case, rather than selectively removing unnecessary lock/unlocks, for three reasons: 1. It makes the patch easier to audit by eyeballing. 2. When, in the next step, we start making VFS_VGET *never* lock the vnode, it serves as an error check to make sure we don't accidentally leave the vnode locked on return from VFS_VGET. 3. It enhances the psychological effect of culling great swaths of code in subsequent steps. --- .../cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c | 23 ++++-- lib/libp2k/p2k.c | 5 +- share/man/man9/vfsops.9 | 8 +- sys/coda/coda_vfsops.c | 13 +++- sys/coda/coda_vfsops.h | 4 +- sys/coda/coda_vnops.c | 15 +++- sys/compat/common/vfs_syscalls_20.c | 6 +- sys/compat/common/vfs_syscalls_30.c | 6 +- sys/compat/netbsd32/netbsd32_compat_30.c | 6 +- sys/fs/adosfs/adlookup.c | 23 +++++- sys/fs/adosfs/advfsops.c | 33 +++++++-- sys/fs/adosfs/advnops.c | 8 +- sys/fs/cd9660/cd9660_lookup.c | 22 +++++- sys/fs/cd9660/cd9660_node.h | 2 +- sys/fs/cd9660/cd9660_vfsops.c | 33 ++++++--- sys/fs/efs/efs_vfsops.c | 28 +++++-- sys/fs/efs/efs_vnops.c | 17 ++++- sys/fs/filecorefs/filecore_lookup.c | 20 ++++- sys/fs/filecorefs/filecore_vfsops.c | 33 +++++++-- sys/fs/hfs/hfs.h | 2 +- sys/fs/hfs/hfs_vfsops.c | 17 +++-- sys/fs/hfs/hfs_vnops.c | 26 +++++-- sys/fs/msdosfs/denode.h | 2 +- sys/fs/msdosfs/msdosfs_denode.c | 7 +- sys/fs/msdosfs/msdosfs_lookup.c | 53 ++++++++++++-- sys/fs/msdosfs/msdosfs_vfsops.c | 19 +++-- sys/fs/nilfs/nilfs_subr.c | 15 +++- sys/fs/nilfs/nilfs_subr.h | 4 +- sys/fs/nilfs/nilfs_vfsops.c | 41 +++++++++-- sys/fs/nilfs/nilfs_vnops.c | 20 ++++- sys/fs/ntfs/ntfs_subr.c | 13 +++- sys/fs/ntfs/ntfs_subr.h | 2 +- sys/fs/ntfs/ntfs_vfsops.c | 37 ++++++++-- sys/fs/ntfs/ntfs_vnops.c | 30 ++++++-- sys/fs/ptyfs/ptyfs.h | 4 +- sys/fs/ptyfs/ptyfs_subr.c | 13 +++- sys/fs/ptyfs/ptyfs_vfsops.c | 14 ++-- sys/fs/ptyfs/ptyfs_vnops.c | 9 ++- sys/fs/puffs/puffs_vfsops.c | 16 ++-- sys/fs/smbfs/smbfs_node.c | 3 +- sys/fs/smbfs/smbfs_node.h | 2 +- sys/fs/smbfs/smbfs_vfsops.c | 14 +++- sys/fs/smbfs/smbfs_vnops.c | 58 +++++++++++++-- sys/fs/sysvbfs/sysvbfs_vfsops.c | 12 ++- sys/fs/sysvbfs/sysvbfs_vnops.c | 15 +++- sys/fs/tmpfs/tmpfs.h | 3 +- sys/fs/tmpfs/tmpfs_rename.c | 14 +++- sys/fs/tmpfs/tmpfs_subr.c | 14 +++- sys/fs/tmpfs/tmpfs_vfsops.c | 21 ++++-- sys/fs/tmpfs/tmpfs_vnops.c | 25 ++++++- sys/fs/udf/udf_rename.c | 15 +++- sys/fs/udf/udf_subr.c | 63 ++++++++++++++-- sys/fs/udf/udf_subr.h | 2 +- sys/fs/udf/udf_vfsops.c | 8 +- sys/fs/udf/udf_vnops.c | 19 ++++- sys/fs/union/union_vfsops.c | 5 +- sys/fs/union/union_vnops.c | 12 ++- sys/fs/unionfs/unionfs_subr.c | 3 +- sys/fs/unionfs/unionfs_vfsops.c | 17 ++++- sys/fs/unionfs/unionfs_vnops.c | 44 ++++++++++- sys/fs/v7fs/v7fs_vfsops.c | 11 ++- sys/fs/v7fs/v7fs_vnops.c | 48 ++++++++++-- sys/kern/tty_bsdpty.c | 9 ++- sys/kern/tty_ptm.c | 19 ++++- sys/kern/vfs_lookup.c | 13 +++- sys/kern/vfs_mount.c | 8 +- sys/kern/vfs_subr.c | 8 +- sys/kern/vfs_syscalls.c | 41 +++++++++-- sys/miscfs/fdesc/fdesc.h | 2 +- sys/miscfs/fdesc/fdesc_vfsops.c | 7 +- sys/miscfs/fdesc/fdesc_vnops.c | 14 +++- sys/miscfs/genfs/layer_extern.h | 6 +- sys/miscfs/genfs/layer_vfsops.c | 35 +++++++-- sys/miscfs/kernfs/kernfs.h | 4 +- sys/miscfs/kernfs/kernfs_subr.c | 12 ++- sys/miscfs/kernfs/kernfs_vfsops.c | 6 +- sys/miscfs/kernfs/kernfs_vnops.c | 16 +++- sys/miscfs/procfs/procfs.h | 2 +- sys/miscfs/procfs/procfs_vfsops.c | 6 +- sys/nfs/nfs_export.c | 6 +- sys/nfs/nfs_node.c | 6 +- sys/nfs/nfs_serv.c | 10 ++- sys/nfs/nfs_srvsubs.c | 8 +- sys/nfs/nfs_var.h | 6 +- sys/nfs/nfs_vfsops.c | 28 +++++-- sys/nfs/nfs_vnops.c | 51 +++++++++++-- sys/nfs/nfsm_subs.h | 8 +- sys/rump/librump/rumpvfs/rump_vfs.c | 17 ++--- sys/rump/librump/rumpvfs/rumpfs.c | 5 +- sys/rump/librump/rumpvfs/rumpvfs.ifspec | 5 +- sys/sys/mount.h | 20 ++--- sys/sys/pty.h | 4 +- sys/ufs/chfs/chfs_vfsops.c | 29 ++++++-- sys/ufs/chfs/chfs_vnode.c | 7 +- sys/ufs/chfs/chfs_vnops.c | 31 +++++++- sys/ufs/ext2fs/ext2fs_alloc.c | 10 ++- sys/ufs/ext2fs/ext2fs_lookup.c | 64 +++++++++++++--- sys/ufs/ext2fs/ext2fs_rename.c | 14 +++- sys/ufs/ext2fs/ext2fs_vfsops.c | 25 ++++++- sys/ufs/ext2fs/ext2fs_vnops.c | 9 ++- sys/ufs/ffs/ffs_alloc.c | 15 +++- sys/ufs/ffs/ffs_quota2.c | 22 +++++- sys/ufs/ffs/ffs_snapshot.c | 17 ++++- sys/ufs/ffs/ffs_vfsops.c | 11 ++- sys/ufs/ffs/ffs_wapbl.c | 28 ++++++- sys/ufs/lfs/lfs_extern.h | 4 +- sys/ufs/lfs/lfs_rename.c | 14 +++- sys/ufs/lfs/lfs_rfw.c | 9 ++- sys/ufs/lfs/lfs_syscalls.c | 12 ++- sys/ufs/lfs/lfs_vfsops.c | 19 +++-- sys/ufs/lfs/lfs_vnops.c | 10 ++- sys/ufs/lfs/ulfs_extattr.c | 9 ++- sys/ufs/lfs/ulfs_extern.h | 4 +- sys/ufs/lfs/ulfs_lookup.c | 82 ++++++++++++++++++--- sys/ufs/lfs/ulfs_quota2.c | 22 +++++- sys/ufs/lfs/ulfs_vfsops.c | 24 +++++- sys/ufs/ufs/ufs_extattr.c | 9 ++- sys/ufs/ufs/ufs_extern.h | 4 +- sys/ufs/ufs/ufs_lookup.c | 85 +++++++++++++++++++--- sys/ufs/ufs/ufs_rename.c | 14 +++- sys/ufs/ufs/ufs_vfsops.c | 22 +++++- sys/ufs/ufs/ufs_vnops.c | 11 ++- usr.sbin/makefs/msdos.c | 2 +- usr.sbin/makefs/msdos.h | 2 +- usr.sbin/makefs/msdos/msdosfs_denode.c | 2 +- usr.sbin/makefs/msdos/msdosfs_vfsops.c | 5 +- 126 files changed, 1690 insertions(+), 416 deletions(-) diff --git a/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c b/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c index 00ec0e5..58570a2 100644 --- a/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c +++ b/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c @@ -76,10 +76,10 @@ kmutex_t zfs_debug_mtx; /* XXX NetBSD static int zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr);*/ static int zfs_mount(vfs_t *vfsp, const char *path, void *data, size_t *data_len); static int zfs_umount(vfs_t *vfsp, int fflag); -static int zfs_root(vfs_t *vfsp, vnode_t **vpp); +static int zfs_root(vfs_t *vfsp, int, vnode_t **vpp); static int zfs_statvfs(vfs_t *vfsp, struct statvfs *statp); -static int zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, vnode_t **vpp); -static int zfs_vget(vfs_t *vfsp, ino_t ino, vnode_t **vpp); +static int zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, int, vnode_t **vpp); +static int zfs_vget(vfs_t *vfsp, ino_t ino, int, vnode_t **vpp); static int zfs_start(vfs_t *vfsp, int flags); static void zfs_freevfs(vfs_t *vfsp); @@ -1770,7 +1770,7 @@ zfs_statvfs(vfs_t *vfsp, struct statvfs *statp) } static int -zfs_root(vfs_t *vfsp, vnode_t **vpp) +zfs_root(vfs_t *vfsp, int flags, vnode_t **vpp) { zfsvfs_t *zfsvfs = vfsp->vfs_data; znode_t *rootzp; @@ -1787,6 +1787,8 @@ zfs_root(vfs_t *vfsp, vnode_t **vpp) vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); KASSERT((error != 0) || (*vpp != NULL)); KASSERT((error != 0) || (VOP_ISLOCKED(*vpp) == LK_EXCLUSIVE)); + if (error == 0) /* XXX ugh bletch error == 0 branch */ + VOP_UNLOCK(*vpp); return (error); } @@ -1999,7 +2001,7 @@ zfs_umount(vfs_t *vfsp, int fflag) } static int -zfs_vget(vfs_t *vfsp, ino_t ino, vnode_t **vpp) +zfs_vget(vfs_t *vfsp, ino_t ino, int flags, vnode_t **vpp) { zfsvfs_t *zfsvfs = vfsp->vfs_data; znode_t *zp; @@ -2022,11 +2024,14 @@ zfs_vget(vfs_t *vfsp, ino_t ino, vnode_t **vpp) vn_lock(*vpp, 0); } ZFS_EXIT(zfsvfs); - return (err); + if (err != 0) + return err; + VOP_UNLOCK(*vpp); + return (0); } static int -zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, vnode_t **vpp) +zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, int flags, vnode_t **vpp) { zfsvfs_t *zfsvfs = vfsp->vfs_data; znode_t *zp; @@ -2087,8 +2092,10 @@ zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, vnode_t **vpp) VN_HOLD(*vpp); } ZFS_EXIT(zfsvfs); + /* XXX Omit needless lock/unlock. */ /* XXX: LK_RETRY? */ vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); + VOP_UNLOCK(*vpp); return (0); } @@ -2110,9 +2117,11 @@ zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, vnode_t **vpp) } *vpp = ZTOV(zp); + /* XXX Omit needless lock/unlock. */ /* XXX: LK_RETRY? */ vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); ZFS_EXIT(zfsvfs); + VOP_UNLOCK(*vpp); return (0); } diff --git a/lib/libp2k/p2k.c b/lib/libp2k/p2k.c index 834a7b3..8cc0559 100644 --- a/lib/libp2k/p2k.c +++ b/lib/libp2k/p2k.c @@ -459,7 +459,7 @@ setupfs(struct p2k_mount *p2m, const char *vfsname, const char *devpath, p2m->p2m_ukfs = ukfs; p2m->p2m_mp = ukfs_getmp(ukfs); } - if ((rv = rump_pub_vfs_root(p2m->p2m_mp, &p2m->p2m_rvp, 0)) != 0) { + if ((rv = rump_pub_vfs_root(p2m->p2m_mp, 0, &p2m->p2m_rvp)) != 0) { errno = rv; rv = -1; goto out; @@ -656,9 +656,10 @@ p2k_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize, uint64_t rdev; /* XXX: allows running this on NetBSD 5.0 */ int rv; - rv = rump_pub_vfs_fhtovp(mp, fid, &vp); + rv = rump_pub_vfs_fhtovp(mp, fid, 0, &vp); if (rv) return rv; + RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); RUMP_VOP_UNLOCK(vp); p2n = getp2n(p2m, vp, false, NULL); diff --git a/share/man/man9/vfsops.9 b/share/man/man9/vfsops.9 index 02a3db6..f1e46ce 100644 --- a/share/man/man9/vfsops.9 +++ b/share/man/man9/vfsops.9 @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd February 13, 2012 +.Dd April 9, 2014 .Dt VFSOPS 9 .Os .Sh NAME @@ -272,7 +272,7 @@ that were allocated for the file system when it was mounted. Get the root vnode of the file system specified by the mount structure .Fa mp . -The vnode is returned in the address given by +The vnode is returned unlocked and referenced in the address given by .Fa vpp . This function is used by the pathname translation algorithms when a vnode that has been covered by a mounted file system is encountered. @@ -324,7 +324,7 @@ Get vnode for a file system type specific file id .Fa ino for the file system specified by the mount structure .Fa mp . -The vnode is returned in the address specified +The vnode is returned unlocked and referenced in the address specified .Fa vpp . The function is optional for file systems which have a unique id number for every file in the file system. @@ -337,7 +337,7 @@ Get the vnode for the file handle .Fa fhp in the file system specified by the mount structure .Fa mp . -The locked vnode is returned in +The vnode is returned unlocked and referenced in .Fa vpp . .Pp When exporting, the call to diff --git a/sys/coda/coda_vfsops.c b/sys/coda/coda_vfsops.c index 4d22e80..6485c90 100644 --- a/sys/coda/coda_vfsops.c +++ b/sys/coda/coda_vfsops.c @@ -353,7 +353,7 @@ coda_unmount(struct mount *vfsp, int mntflags) * find root of cfs */ int -coda_root(struct mount *vfsp, struct vnode **vpp) +coda_root(struct mount *vfsp, int flags, struct vnode **vpp) { struct coda_mntinfo *mi = vftomi(vfsp); int error; @@ -370,8 +370,10 @@ coda_root(struct mount *vfsp, struct vnode **vpp) *vpp = mi->mi_rootvp; /* On Mach, this is vref. On NetBSD, VOP_LOCK */ vref(*vpp); + /* XXX Omit needless lock/unlock. */ vn_lock(*vpp, LK_EXCLUSIVE); MARK_INT_SAT(CODA_ROOT_STATS); + VOP_UNLOCK(*vpp); return(0); } } @@ -389,6 +391,7 @@ coda_root(struct mount *vfsp, struct vnode **vpp) *vpp = mi->mi_rootvp; vref(*vpp); + /* XXX Omit needless lock/unlock. */ vn_lock(*vpp, LK_EXCLUSIVE); MARK_INT_SAT(CODA_ROOT_STATS); goto exit; @@ -404,6 +407,7 @@ coda_root(struct mount *vfsp, struct vnode **vpp) */ *vpp = mi->mi_rootvp; vref(*vpp); + /* XXX Omit needless lock/unlock. */ vn_lock(*vpp, LK_EXCLUSIVE); MARK_INT_FAIL(CODA_ROOT_STATS); error = 0; @@ -415,7 +419,10 @@ coda_root(struct mount *vfsp, struct vnode **vpp) goto exit; } exit: - return(error); + if (error) + return(error); + VOP_UNLOCK(*vpp); + return(0); } /* @@ -476,7 +483,7 @@ coda_sync(struct mount *vfsp, int waitfor, } int -coda_vget(struct mount *vfsp, ino_t ino, +coda_vget(struct mount *vfsp, ino_t ino, int flags, struct vnode **vpp) { ENTRY; diff --git a/sys/coda/coda_vfsops.h b/sys/coda/coda_vfsops.h index c7771e8..870591c 100644 --- a/sys/coda/coda_vfsops.h +++ b/sys/coda/coda_vfsops.h @@ -49,10 +49,10 @@ int coda_vfsopstats_init(void); int coda_mount(struct mount *, const char *, void *, size_t *); int coda_start(struct mount *, int); int coda_unmount(struct mount *, int); -int coda_root(struct mount *, struct vnode **); +int coda_root(struct mount *, int, struct vnode **); int coda_nb_statvfs(struct mount *, struct statvfs *); int coda_sync(struct mount *, int, kauth_cred_t); -int coda_vget(struct mount *, ino_t, struct vnode **); +int coda_vget(struct mount *, ino_t, int, struct vnode **); int coda_fhtovp(struct mount *, struct fid *, struct mbuf *, struct vnode **, int *, kauth_cred_t *); int coda_vptofh(struct vnode *, struct fid *); diff --git a/sys/coda/coda_vnops.c b/sys/coda/coda_vnops.c index 33a327d..fc441518 100644 --- a/sys/coda/coda_vnops.c +++ b/sys/coda/coda_vnops.c @@ -1728,6 +1728,8 @@ coda_islocked(void *v) /* * Given a device and inode, obtain a locked vnode. One reference is * obtained and passed back to the caller. + * + * XXX Should be made to return unlocked instead. */ int coda_grab_vnode(vnode_t *uvp, dev_t dev, ino_t ino, vnode_t **vpp) @@ -1745,13 +1747,24 @@ coda_grab_vnode(vnode_t *uvp, dev_t dev, ino_t ino, vnode_t **vpp) /* * Obtain vnode from mount point and inode. */ - error = VFS_VGET(mp, ino, vpp); + error = VFS_VGET(mp, ino, 0, vpp); if (error) { myprintf(("%s: iget/vget(0x%llx, %llu) returns %p, err %d\n", __func__, (unsigned long long)dev, (unsigned long long)ino, *vpp, error)); return(ENOENT); } + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + return(error); + } /* share the underlying vnode lock with the coda vnode */ + /* + * XXX This is completely bogus -- needs to be done in getnewvnode + * if it is to be done at all, but sharing all interlocks can't + * possibly be sensible. + */ mutex_obj_hold((*vpp)->v_interlock); uvm_obj_setlock(&uvp->v_uobj, (*vpp)->v_interlock); KASSERT(VOP_ISLOCKED(*vpp)); diff --git a/sys/compat/common/vfs_syscalls_20.c b/sys/compat/common/vfs_syscalls_20.c index 3b92a86..004c2ad 100644 --- a/sys/compat/common/vfs_syscalls_20.c +++ b/sys/compat/common/vfs_syscalls_20.c @@ -281,8 +281,12 @@ compat_20_sys_fhstatfs(struct lwp *l, const struct compat_20_sys_fhstatfs_args * if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) return (ESTALE); - if ((error = VFS_FHTOVP(mp, (struct fid*)&fh.fh_fid, &vp))) + if ((error = VFS_FHTOVP(mp, (struct fid*)&fh.fh_fid, 0, &vp))) return (error); + if ((error = vn_lock(vp, LK_EXCLUSIVE))) { + vrele(vp); + return (error); + } mp = vp->v_mount; VOP_UNLOCK(vp); sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK); diff --git a/sys/compat/common/vfs_syscalls_30.c b/sys/compat/common/vfs_syscalls_30.c index f9b2a29..e9c355a 100644 --- a/sys/compat/common/vfs_syscalls_30.c +++ b/sys/compat/common/vfs_syscalls_30.c @@ -158,8 +158,12 @@ compat_30_sys_fhstat(struct lwp *l, const struct compat_30_sys_fhstat_args *uap, return (ESTALE); if (mp->mnt_op->vfs_fhtovp == NULL) return EOPNOTSUPP; - if ((error = VFS_FHTOVP(mp, (struct fid*)&fh.fh_fid, &vp))) + if ((error = VFS_FHTOVP(mp, (struct fid*)&fh.fh_fid, 0, &vp))) return (error); + if ((error = vn_lock(vp, LK_EXCLUSIVE))) { + vrele(vp); + return (error); + } error = vn_stat(vp, &sb); vput(vp); if (error) diff --git a/sys/compat/netbsd32/netbsd32_compat_30.c b/sys/compat/netbsd32/netbsd32_compat_30.c index c5a6bb1..90f4010 100644 --- a/sys/compat/netbsd32/netbsd32_compat_30.c +++ b/sys/compat/netbsd32/netbsd32_compat_30.c @@ -181,8 +181,12 @@ compat_30_netbsd32_fhstat(struct lwp *l, const struct compat_30_netbsd32_fhstat_ return (ESTALE); if (mp->mnt_op->vfs_fhtovp == NULL) return EOPNOTSUPP; - if ((error = VFS_FHTOVP(mp, (struct fid*)&fh.fh_fid, &vp))) + if ((error = VFS_FHTOVP(mp, (struct fid*)&fh.fh_fid, 0, &vp))) return (error); + if ((error = vn_lock(vp, LK_EXCLUSIVE))) { + vrele(vp); + return (error); + } error = vn_stat(vp, &sb); vput(vp); if (error) diff --git a/sys/fs/adosfs/adlookup.c b/sys/fs/adosfs/adlookup.c index 0bbe384..ab90df7 100644 --- a/sys/fs/adosfs/adlookup.c +++ b/sys/fs/adosfs/adlookup.c @@ -145,12 +145,21 @@ adosfs_lookup(void *v) * */ VOP_UNLOCK(vdp); /* race */ - error = VFS_VGET(vdp->v_mount, (ino_t)adp->pblock, vpp); - vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + error = VFS_VGET(vdp->v_mount, (ino_t)adp->pblock, 0, vpp); + if (error) { + *vpp = NULL; + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + return (error); + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); if (error) { + vrele(*vpp); *vpp = NULL; + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); return (error); } + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); goto found_lockdone; } @@ -163,13 +172,19 @@ adosfs_lookup(void *v) bn = adp->tab[hval]; i = min(adp->tabi[hval], 0); while (bn != 0) { - if ((error = VFS_VGET(vdp->v_mount, (ino_t)bn, vpp - )) != 0) { + if ((error = VFS_VGET(vdp->v_mount, (ino_t)bn, 0, vpp)) != 0) { #ifdef ADOSFS_DIAGNOSTIC printf("[aget] %d)", error); #endif return(error); } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + return error; + } ap = VTOA(*vpp); if (i <= 0) { if (--i < adp->tabi[hval]) diff --git a/sys/fs/adosfs/advfsops.c b/sys/fs/adosfs/advfsops.c index 3fa8764..60f8f81 100644 --- a/sys/fs/adosfs/advfsops.c +++ b/sys/fs/adosfs/advfsops.c @@ -270,8 +270,14 @@ adosfs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l) /* * get the root anode, if not a valid fs this will fail. */ - if ((error = VFS_ROOT(mp, &rvp)) != 0) + if ((error = VFS_ROOT(mp, 0, &rvp)) != 0) goto fail; + error = vn_lock(rvp, LK_EXCLUSIVE); + if (error) { + vrele(rvp); + rvp = NULL; + goto fail; + } /* allocate and load bitmap, set free space */ bitmap_sz = ((amp->numblks + 31) / 32) * sizeof(*amp->bitmap); amp->bitmap = kmem_alloc(bitmap_sz, KM_SLEEP); @@ -335,12 +341,13 @@ adosfs_unmount(struct mount *mp, int mntflags) } int -adosfs_root(struct mount *mp, struct vnode **vpp) +adosfs_root(struct mount *mp, int flags, struct vnode **vpp) { struct vnode *nvp; int error; - if ((error = VFS_VGET(mp, (ino_t)VFSTOADOSFS(mp)->rootb, &nvp)) != 0) + if ((error = VFS_VGET(mp, (ino_t)VFSTOADOSFS(mp)->rootb, flags, &nvp)) + != 0) return (error); /* XXX verify it's a root block? */ *vpp = nvp; @@ -373,7 +380,7 @@ adosfs_statvfs(struct mount *mp, struct statvfs *sbp) * return locked and referenced al la vget(vp, 1); */ int -adosfs_vget(struct mount *mp, ino_t an, struct vnode **vpp) +adosfs_vget(struct mount *mp, ino_t an, int flags, struct vnode **vpp) { struct adosfsmount *amp; struct vnode *vp; @@ -389,8 +396,10 @@ adosfs_vget(struct mount *mp, ino_t an, struct vnode **vpp) /* * check hash table. we are done if found */ - if ((*vpp = adosfs_ahashget(mp, an)) != NULL) + if ((*vpp = adosfs_ahashget(mp, an)) != NULL) { + VOP_UNLOCK(*vpp); return (0); + } error = getnewvnode(VT_ADOSFS, mp, adosfs_vnodeop_p, NULL, 0, &vp); if (error) @@ -406,6 +415,7 @@ adosfs_vget(struct mount *mp, ino_t an, struct vnode **vpp) ap->block = an; ap->nwords = amp->nwords; genfs_node_init(vp, &adosfs_genfsops); + /* XXX Need to handle race and retry. */ adosfs_ainshash(amp, ap); if ((error = bread(amp->devvp, an * amp->bsize / DEV_BSIZE, @@ -592,6 +602,7 @@ adosfs_vget(struct mount *mp, ino_t an, struct vnode **vpp) brelse(bp, 0); uvm_vnp_setsize(vp, ap->fsize); vready(vp); + VOP_UNLOCK(vp); return (0); } @@ -692,7 +703,7 @@ struct ifid { }; int -adosfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) +adosfs_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) { struct ifid ifh; #if 0 @@ -710,17 +721,23 @@ adosfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) memcpy(&ifh, fhp, sizeof(ifh)); - if ((error = VFS_VGET(mp, ifh.ifid_ino, &nvp)) != 0) { + if ((error = VFS_VGET(mp, ifh.ifid_ino, flags, &nvp)) != 0) { + *vpp = NULLVP; + return (error); + } +#if 0 /* XXX Kill this isofs copypasta. */ + if ((error = vn_lock(nvp, LK_EXCLUSIVE)) != 0) { + vrele(nvp); *vpp = NULLVP; return (error); } -#if 0 ap = VTOA(nvp); if (ap->inode.iso_mode == 0) { vput(nvp); *vpp = NULLVP; return (ESTALE); } + VOP_UNLOCK(*vpp); #endif *vpp = nvp; return(0); diff --git a/sys/fs/adosfs/advnops.c b/sys/fs/adosfs/advnops.c index 608cdb5..b2ecd1d 100644 --- a/sys/fs/adosfs/advnops.c +++ b/sys/fs/adosfs/advnops.c @@ -656,9 +656,15 @@ adosfs_readdir(void *v) */ ap = NULL; do { - error = VFS_VGET(pap->amp->mp, (ino_t)nextbn, &vp); + error = VFS_VGET(pap->amp->mp, (ino_t)nextbn, 0, &vp); if (error) goto reterr; + error = vn_lock(vp, LK_EXCLUSIVE); + if (error) { + vrele(vp); + vp = NULL; + goto reterr; + } ap = VTOA(vp); scanned++; chainc++; diff --git a/sys/fs/cd9660/cd9660_lookup.c b/sys/fs/cd9660/cd9660_lookup.c index edd6a89..3628706 100644 --- a/sys/fs/cd9660/cd9660_lookup.c +++ b/sys/fs/cd9660/cd9660_lookup.c @@ -381,8 +381,19 @@ found: brelse(bp, 0); if (flags & ISDOTDOT) { VOP_UNLOCK(pdp); /* 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, 0, &tdp, dp->i_ino != ino, ep); + if (error) { + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); + return error; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); + return error; + } vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); if (error) return error; @@ -391,10 +402,17 @@ 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, 0, &tdp, dp->i_ino != ino, ep); if (error) return (error); + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + tdp = NULL; + return error; + } *vpp = tdp; } diff --git a/sys/fs/cd9660/cd9660_node.h b/sys/fs/cd9660/cd9660_node.h index 735f1b9..202bc80 100644 --- a/sys/fs/cd9660/cd9660_node.h +++ b/sys/fs/cd9660/cd9660_node.h @@ -133,7 +133,7 @@ void cd9660_ihashins(struct iso_node *); void cd9660_ihashrem(struct iso_node *); int cd9660_tstamp_conv7(const u_char *, struct timespec *); int cd9660_tstamp_conv17(const u_char *, struct timespec *); -int cd9660_vget_internal(struct mount *, ino_t, struct vnode **, int, +int cd9660_vget_internal(struct mount *, ino_t, int, struct vnode **, int, struct iso_directory_record *); extern kmutex_t cd9660_hashlock; diff --git a/sys/fs/cd9660/cd9660_vfsops.c b/sys/fs/cd9660/cd9660_vfsops.c index e8097ea..912e1c9 100644 --- a/sys/fs/cd9660/cd9660_vfsops.c +++ b/sys/fs/cd9660/cd9660_vfsops.c @@ -577,7 +577,7 @@ cd9660_unmount(struct mount *mp, int mntflags) * Return root of a filesystem */ int -cd9660_root(struct mount *mp, struct vnode **vpp) +cd9660_root(struct mount *mp, int flags, struct vnode **vpp) { struct iso_mnt *imp = VFSTOISOFS(mp); struct iso_directory_record *dp = @@ -588,7 +588,7 @@ cd9660_root(struct mount *mp, struct vnode **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, flags, vpp, imp->iso_ftype == ISO_FTYPE_RRIP, dp)); } @@ -645,7 +645,7 @@ struct ifid { /* ARGSUSED */ int -cd9660_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) +cd9660_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) { struct ifid ifh; struct iso_node *ip; @@ -661,22 +661,34 @@ cd9660_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) ifh.ifid_ino, ifh.ifid_start); #endif - if ((error = VFS_VGET(mp, ifh.ifid_ino, &nvp)) != 0) { + if ((error = VFS_VGET(mp, ifh.ifid_ino, flags, &nvp)) != 0) { *vpp = NULLVP; return (error); } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(nvp, LK_EXCLUSIVE); + if (error) { + vrele(nvp); + *vpp = NULLVP; + return error; + } + /* + * XXX This test shouldn't be necessary: VFS_VGET should return + * only valid vnodes. + */ ip = VTOI(nvp); if (ip->inode.iso_mode == 0) { vput(nvp); *vpp = NULLVP; return (ESTALE); } + VOP_UNLOCK(nvp); *vpp = nvp; return (0); } int -cd9660_vget(struct mount *mp, ino_t ino, struct vnode **vpp) +cd9660_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { /* @@ -685,7 +697,7 @@ cd9660_vget(struct mount *mp, ino_t ino, struct vnode **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 @@ -695,8 +707,8 @@ cd9660_vget(struct mount *mp, ino_t ino, struct vnode **vpp) } int -cd9660_vget_internal(struct mount *mp, ino_t ino, struct vnode **vpp, - int relocated, struct iso_directory_record *isodir) +cd9660_vget_internal(struct mount *mp, ino_t ino, int flags, + struct vnode **vpp, int relocated, struct iso_directory_record *isodir) { struct iso_mnt *imp; struct iso_node *ip; @@ -709,8 +721,10 @@ cd9660_vget_internal(struct mount *mp, ino_t ino, struct vnode **vpp, dev = imp->im_dev; retry: - if ((*vpp = cd9660_ihashget(dev, ino, LK_EXCLUSIVE)) != NULLVP) + if ((*vpp = cd9660_ihashget(dev, ino, LK_EXCLUSIVE)) != NULLVP) { + VOP_UNLOCK(*vpp); return (0); + } /* Allocate a new vnode/iso_node. */ error = getnewvnode(VT_ISOFS, mp, cd9660_vnodeop_p, NULL, 0, &vp); @@ -897,6 +911,7 @@ cd9660_vget_internal(struct mount *mp, ino_t ino, struct vnode **vpp, */ vready(vp); + VOP_UNLOCK(vp); *vpp = vp; return (0); } diff --git a/sys/fs/efs/efs_vfsops.c b/sys/fs/efs/efs_vfsops.c index 339ee12..1130b3e 100644 --- a/sys/fs/efs/efs_vfsops.c +++ b/sys/fs/efs/efs_vfsops.c @@ -294,12 +294,12 @@ efs_unmount(struct mount *mp, int mntflags) * Returns 0 on success. */ static int -efs_root(struct mount *mp, struct vnode **vpp) +efs_root(struct mount *mp, int flags, struct vnode **vpp) { int err; struct vnode *vp; - if ((err = VFS_VGET(mp, EFS_ROOTINO, &vp))) + if ((err = VFS_VGET(mp, EFS_ROOTINO, flags, &vp))) return (err); *vpp = vp; @@ -346,7 +346,7 @@ efs_statvfs(struct mount *mp, struct statvfs *sbp) * Returns 0 on success. */ static int -efs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) +efs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { int err; struct vnode *vp; @@ -357,8 +357,10 @@ efs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) while (true) { *vpp = efs_ihashget(emp->em_dev, ino, LK_EXCLUSIVE); - if (*vpp != NULL) + if (*vpp != NULL) { + VOP_UNLOCK(*vpp); return (0); + } err = getnewvnode(VT_EFS, mp, efs_vnodeop_p, NULL, 0, &vp); if (err) @@ -464,6 +466,7 @@ efs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) *vpp = vp; KASSERT(VOP_ISLOCKED(vp)); + VOP_UNLOCK(vp); return (0); } @@ -474,7 +477,7 @@ efs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) * Returns 0 on success. */ static int -efs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) +efs_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) { int err; struct vnode *vp; @@ -486,11 +489,23 @@ efs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) efp = (struct efs_fid *)fhp; - if ((err = VFS_VGET(mp, efp->ef_ino, &vp))) { + if ((err = VFS_VGET(mp, efp->ef_ino, flags, &vp))) { *vpp = NULL; return (err); } + /* XXX Omit needless lock/unlock. */ + err = vn_lock(vp, LK_EXCLUSIVE); + if (err) { + vrele(vp); + *vpp = NULL; + return err; + } + + /* + * XXX This should not be necessary -- vget should not return + * invalid vnodes. + */ eip = EFS_VTOI(vp); if (eip->ei_mode == 0 || eip->ei_gen != efp->ef_gen) { vput(vp); @@ -498,6 +513,7 @@ efs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) return (ESTALE); } + VOP_UNLOCK(vp); *vpp = vp; return (0); } diff --git a/sys/fs/efs/efs_vnops.c b/sys/fs/efs/efs_vnops.c index d9e26f7..527eed1 100644 --- a/sys/fs/efs/efs_vnops.c +++ b/sys/fs/efs/efs_vnops.c @@ -92,11 +92,18 @@ efs_lookup(void *v) VOP_UNLOCK(ap->a_dvp); /* preserve lock order */ - err = VFS_VGET(ap->a_dvp->v_mount, ino, &vp); + err = VFS_VGET(ap->a_dvp->v_mount, ino, 0, &vp); if (err) { vn_lock(ap->a_dvp, LK_EXCLUSIVE | LK_RETRY); return (err); } + /* XXX Omit needless lock/unlock. */ + err = vn_lock(vp, LK_EXCLUSIVE); + if (err) { + vrele(vp); + vn_lock(ap->a_dvp, LK_EXCLUSIVE | LK_RETRY); + return err; + } vn_lock(ap->a_dvp, LK_EXCLUSIVE | LK_RETRY); *ap->a_vpp = vp; } else { @@ -116,9 +123,15 @@ efs_lookup(void *v) } return (err); } - err = VFS_VGET(ap->a_dvp->v_mount, ino, &vp); + err = VFS_VGET(ap->a_dvp->v_mount, ino, 0, &vp); if (err) return (err); + /* XXX Omit needless lock/unlock. */ + err = vn_lock(vp, LK_EXCLUSIVE); + if (err) { + vrele(vp); + return err; + } *ap->a_vpp = vp; } diff --git a/sys/fs/filecorefs/filecore_lookup.c b/sys/fs/filecorefs/filecore_lookup.c index 880f996..59afcb7 100644 --- a/sys/fs/filecorefs/filecore_lookup.c +++ b/sys/fs/filecorefs/filecore_lookup.c @@ -290,11 +290,19 @@ found: ino_t pin = filecore_getparent(dp); VOP_UNLOCK(pdp); /* race to get the inode */ - error = VFS_VGET(vdp->v_mount, pin, &tdp); - vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); + error = VFS_VGET(vdp->v_mount, pin, 0, &tdp); + if (error) { + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); + return error; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); if (error) { + vrele(tdp); + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); return error; } + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); *vpp = tdp; } else if (name[0] == '.' && namelen == 1) { vref(vdp); /* we want ourself, ie "." */ @@ -305,9 +313,15 @@ found: #endif brelse(bp, 0); error = VFS_VGET(vdp->v_mount, dp->i_dirent.addr | - (i << FILECORE_INO_INDEX), &tdp); + (i << FILECORE_INO_INDEX), 0, &tdp); if (error) return (error); + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + return (error); + } *vpp = tdp; } diff --git a/sys/fs/filecorefs/filecore_vfsops.c b/sys/fs/filecorefs/filecore_vfsops.c index e057ba4..c170361 100644 --- a/sys/fs/filecorefs/filecore_vfsops.c +++ b/sys/fs/filecorefs/filecore_vfsops.c @@ -461,12 +461,12 @@ filecore_unmount(struct mount *mp, int mntflags) * Return root of a filesystem */ int -filecore_root(struct mount *mp, struct vnode **vpp) +filecore_root(struct mount *mp, int flags, struct vnode **vpp) { struct vnode *nvp; int error; - if ((error = VFS_VGET(mp, FILECORE_ROOTINO, &nvp)) != 0) + if ((error = VFS_VGET(mp, FILECORE_ROOTINO, flags, &nvp)) != 0) return (error); *vpp = nvp; return (0); @@ -520,7 +520,8 @@ struct ifid { /* ARGSUSED */ int -filecore_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) +filecore_fhtovp(struct mount *mp, struct fid *fhp, int flags, + struct vnode **vpp) { struct ifid ifh; struct vnode *nvp; @@ -531,16 +532,31 @@ filecore_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) return EINVAL; memcpy(&ifh, fhp, sizeof(ifh)); - if ((error = VFS_VGET(mp, ifh.ifid_ino, &nvp)) != 0) { + if ((error = VFS_VGET(mp, ifh.ifid_ino, flags, &nvp)) != 0) { *vpp = NULLVP; return (error); } + + /* XXX Omit needless lock/unlock. */ + error = vn_lock(nvp, LK_EXCLUSIVE); + if (error) { + vrele(nvp); + *vpp = NULLVP; + return (error); + } + + /* + * XXX This check shouldn't be necessary -- vget should refuse + * to return invalid vnodes. + */ ip = VTOI(nvp); if (filecore_staleinode(ip)) { vput(nvp); *vpp = NULLVP; return (ESTALE); } + + VOP_UNLOCK(nvp); *vpp = nvp; return (0); } @@ -554,7 +570,7 @@ filecore_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) */ int -filecore_vget(struct mount *mp, ino_t ino, struct vnode **vpp) +filecore_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { struct filecore_mnt *fcmp; struct filecore_node *ip; @@ -565,8 +581,10 @@ filecore_vget(struct mount *mp, ino_t ino, struct vnode **vpp) fcmp = VFSTOFILECORE(mp); dev = fcmp->fc_dev; - if ((*vpp = filecore_ihashget(dev, ino)) != NULLVP) + if ((*vpp = filecore_ihashget(dev, ino)) != NULLVP) { + VOP_UNLOCK(*vpp); return (0); + } /* Allocate a new vnode/filecore_node. */ error = getnewvnode(VT_FILECORE, mp, filecore_vnodeop_p, NULL, 0, &vp); @@ -589,6 +607,8 @@ filecore_vget(struct mount *mp, ino_t ino, struct vnode **vpp) * 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 * disk portion of this inode to be read. + * + * XXX Wrong -- need to deal with race and retry. */ filecore_ihashins(ip); @@ -663,6 +683,7 @@ filecore_vget(struct mount *mp, ino_t ino, struct vnode **vpp) uvm_vnp_setsize(vp, ip->i_size); vready(vp); + VOP_UNLOCK(vp); *vpp = vp; return (0); } diff --git a/sys/fs/hfs/hfs.h b/sys/fs/hfs/hfs.h index 0a25cf2..3d9f057 100644 --- a/sys/fs/hfs/hfs.h +++ b/sys/fs/hfs/hfs.h @@ -190,7 +190,7 @@ uint64_t be64tohp(void**); VFS_PROTOS(hfs); int hfs_mountfs (struct vnode *, struct mount *, struct lwp *, const char *); -int hfs_vget_internal(struct mount *, ino_t, uint8_t, struct vnode **); +int hfs_vget_internal(struct mount *, ino_t, uint8_t, int, struct vnode **); /* hfs_vnops.c */ extern int (**hfs_vnodeop_p) (void *); diff --git a/sys/fs/hfs/hfs_vfsops.c b/sys/fs/hfs/hfs_vfsops.c index 814bf4b..71fbf81 100644 --- a/sys/fs/hfs/hfs_vfsops.c +++ b/sys/fs/hfs/hfs_vfsops.c @@ -446,7 +446,7 @@ hfs_unmount(struct mount *mp, int mntflags) } int -hfs_root(struct mount *mp, struct vnode **vpp) +hfs_root(struct mount *mp, int flags, struct vnode **vpp) { struct vnode *nvp; int error; @@ -455,7 +455,7 @@ hfs_root(struct mount *mp, struct vnode **vpp) printf("vfsop = hfs_root()\n"); #endif /* HFS_DEBUG */ - if ((error = VFS_VGET(mp, HFS_CNID_ROOT_FOLDER, &nvp)) != 0) + if ((error = VFS_VGET(mp, HFS_CNID_ROOT_FOLDER, flags, &nvp)) != 0) return error; *vpp = nvp; @@ -503,16 +503,16 @@ hfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) * since both are conveniently 32-bit numbers */ int -hfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) +hfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { - return hfs_vget_internal(mp, ino, HFS_DATAFORK, vpp); + return hfs_vget_internal(mp, ino, HFS_DATAFORK, flags, vpp); } /* * internal version with extra arguments to allow accessing resource fork */ int -hfs_vget_internal(struct mount *mp, ino_t ino, uint8_t fork, +hfs_vget_internal(struct mount *mp, ino_t ino, uint8_t fork, int flags, struct vnode **vpp) { struct hfsmount *hmp; @@ -540,8 +540,10 @@ hfs_vget_internal(struct mount *mp, ino_t ino, uint8_t fork, retry: /* Check if this vnode has already been allocated. If so, just return it. */ - if ((*vpp = hfs_nhashget(dev, cnid, fork, LK_EXCLUSIVE)) != NULL) + if ((*vpp = hfs_nhashget(dev, cnid, fork, LK_EXCLUSIVE)) != NULL) { + VOP_UNLOCK(*vpp); return 0; + } /* Allocate a new vnode/inode. */ error = getnewvnode(VT_HFS, mp, hfs_vnodeop_p, NULL, 0, &vp); @@ -634,6 +636,7 @@ hfs_vget_internal(struct mount *mp, ino_t ino, uint8_t fork, uvm_vnp_setsize(vp, 0); /* no directly reading directories */ vready(vp); + VOP_UNLOCK(vp); *vpp = vp; return 0; @@ -644,7 +647,7 @@ error: } int -hfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) +hfs_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) { #ifdef HFS_DEBUG diff --git a/sys/fs/hfs/hfs_vnops.c b/sys/fs/hfs/hfs_vnops.c index d1ee5e3..7a2cd8f 100644 --- a/sys/fs/hfs/hfs_vnops.c +++ b/sys/fs/hfs/hfs_vnops.c @@ -392,10 +392,19 @@ hfs_vop_lookup(void *v) if (flags & ISDOTDOT) { DPRINTF(("DOTDOT ")); VOP_UNLOCK(pdp); /* race to get the inode */ - error = VFS_VGET(vdp->v_mount, dp->h_parent, &tdp); + error = VFS_VGET(vdp->v_mount, dp->h_parent, 0, &tdp); + if (error) { + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); + return error; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); + return error; + } vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); - if (error != 0) - goto error; *vpp = tdp; #if 0 } else if (dp->h_rec.u.cnid == rec.file.u.cnid) { @@ -458,12 +467,19 @@ hfs_vop_lookup(void *v) cnp->cn_consume = 5; cnp->cn_flags &= ~REQUIREDIR; /* XXX: needed? */ error = hfs_vget_internal(vdp->v_mount, rec.file.cnid, - HFS_RSRCFORK, &tdp); + HFS_RSRCFORK, 0, &tdp); } else - error = VFS_VGET(vdp->v_mount, rec.file.cnid, &tdp); + error = VFS_VGET(vdp->v_mount, rec.file.cnid, 0, &tdp); if (error != 0) goto error; + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error != 0) { + vrele(tdp); + tdp = NULL; + goto error; + } *vpp = tdp; } DPRINTF(("\n")); diff --git a/sys/fs/msdosfs/denode.h b/sys/fs/msdosfs/denode.h index 7453d5f..f1c0581 100644 --- a/sys/fs/msdosfs/denode.h +++ b/sys/fs/msdosfs/denode.h @@ -303,7 +303,7 @@ int msdosfs_update(struct vnode *, const struct timespec *, int createde(struct denode *, struct denode *, struct denode **, struct componentname *); int deextend(struct denode *, u_long, struct kauth_cred *); -int deget(struct msdosfsmount *, u_long, u_long, struct denode **); +int deget(struct msdosfsmount *, u_long, u_long, int, struct denode **); int detrunc(struct denode *, u_long, int, struct kauth_cred *); int deupdat(struct denode *, int); int doscheckpath(struct denode *, struct denode *); diff --git a/sys/fs/msdosfs/msdosfs_denode.c b/sys/fs/msdosfs/msdosfs_denode.c index 756411a..5f39de3 100644 --- a/sys/fs/msdosfs/msdosfs_denode.c +++ b/sys/fs/msdosfs/msdosfs_denode.c @@ -260,7 +260,7 @@ msdosfs_hashrem(struct denode *dep) } /* - * If deget() succeeds it returns with the gotten denode locked(). + * If deget() succeeds it returns with the gotten denode referenced. * * pmp - address of msdosfsmount structure of the filesystem containing * the denode of interest. The pm_dev field and the address of @@ -272,7 +272,8 @@ msdosfs_hashrem(struct denode *dep) * depp - returns the address of the gotten denode. */ int -deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, struct denode **depp) +deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, + int flags, struct denode **depp) /* pmp: so we know the maj/min number */ /* dirclust: cluster this dir entry came from */ /* diroffset: index of entry within the cluster */ @@ -312,6 +313,7 @@ deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, struct denode retry: ldep = msdosfs_hashget(pmp->pm_dev, dirclust, diroffset, LK_EXCLUSIVE); if (ldep) { + VOP_UNLOCK(DETOV(ldep)); *depp = ldep; return (0); } @@ -440,6 +442,7 @@ deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, struct denode vref(ldep->de_devvp); *depp = ldep; uvm_vnp_setsize(nvp, ldep->de_FileSize); + VOP_UNLOCK(nvp); vready(nvp); return (0); } diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c index 65cd50b..01e8dd0 100644 --- a/sys/fs/msdosfs/msdosfs_lookup.c +++ b/sys/fs/msdosfs/msdosfs_lookup.c @@ -491,8 +491,13 @@ foundroot: *vpp = vdp; return (0); } - if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) + if ((error = deget(pmp, cluster, blkoff, 0, &tdp)) != 0) return (error); + /* XXX Omit needless lock/unlock. */ + if ((error = vn_lock(DETOV(tdp), LK_EXCLUSIVE)) != 0) { + vrele(DETOV(tdp)); + return (error); + } *vpp = DETOV(tdp); VOP_UNLOCK(*vpp); return (0); @@ -523,8 +528,13 @@ foundroot: if (dp->de_StartCluster == scn && isadir) return (EISDIR); - if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) + if ((error = deget(pmp, cluster, blkoff, 0, &tdp)) != 0) + return (error); + /* XXX Omit needless lock/unlock. */ + if ((error = vn_lock(DETOV(tdp), LK_EXCLUSIVE)) != 0) { + vrele(DETOV(tdp)); return (error); + } *vpp = DETOV(tdp); VOP_UNLOCK(*vpp); return (0); @@ -552,18 +562,31 @@ foundroot: pdp = vdp; if (flags & ISDOTDOT) { VOP_UNLOCK(pdp); /* race to get the inode */ - error = deget(pmp, cluster, blkoff, &tdp); - vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); + error = deget(pmp, cluster, blkoff, 0, &tdp); if (error) { + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); return error; } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(DETOV(tdp), LK_EXCLUSIVE); + if (error) { + vrele(DETOV(tdp)); + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); + return error; + } + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); *vpp = DETOV(tdp); } else if (dp->de_StartCluster == scn && isadir) { vref(vdp); /* we want ourself, ie "." */ *vpp = vdp; } else { - if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) + if ((error = deget(pmp, cluster, blkoff, 0, &tdp)) != 0) + return (error); + /* XXX Omit needless lock/unlock. */ + if ((error = vn_lock(DETOV(tdp), LK_EXCLUSIVE)) != 0) { + vrele(DETOV(tdp)); return (error); + } *vpp = DETOV(tdp); } @@ -716,8 +739,17 @@ createde(struct denode *dep, struct denode *ddep, struct denode **depp, struct c else diroffset = 0; } - error = deget(pmp, dirclust, diroffset, depp); + error = deget(pmp, dirclust, diroffset, 0, depp); #ifndef MAKEFS + if (error) + return error; + /* XXX Omit needless lock/unlock. */ + error = vn_lock(DETOV(*depp), LK_EXCLUSIVE); + if (error) { + vrele(DETOV(*depp)); + *depp = NULL; + return error; + } if (error == 0) VOP_UNLOCK(DETOV(*depp)); #endif @@ -936,8 +968,15 @@ doscheckpath(struct denode *source, struct denode *target) brelse(bp, 0); bp = NULL; /* NOTE: deget() clears dep on error */ - if ((error = deget(pmp, scn, 0, &dep)) != 0) + if ((error = deget(pmp, scn, 0, 0, &dep)) != 0) + break; +#ifndef MAKEFS + if ((error = vn_lock(DETOV(dep), LK_EXCLUSIVE)) != 0) { + vrele(DETOV(dep)); + dep = NULL; break; + } +#endif } out: if (bp) diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c index fda1d5d..fe89a37 100644 --- a/sys/fs/msdosfs/msdosfs_vfsops.c +++ b/sys/fs/msdosfs/msdosfs_vfsops.c @@ -211,8 +211,12 @@ update_mp(struct mount *mp, struct msdosfs_args *argp) if (FAT32(pmp)) pmp->pm_flags |= MSDOSFSMNT_LONGNAME; else { - if ((error = msdosfs_root(mp, &rtvp)) != 0) + if ((error = msdosfs_root(mp, 0, &rtvp)) != 0) return error; + if ((error = vn_lock(rtvp, LK_EXCLUSIVE)) != 0) { + vrele(rtvp); + return error; + } pmp->pm_flags |= findwin95(VTODE(rtvp)) ? MSDOSFSMNT_LONGNAME : MSDOSFSMNT_SHORTNAME; @@ -905,7 +909,7 @@ msdosfs_unmount(struct mount *mp, int mntflags) } int -msdosfs_root(struct mount *mp, struct vnode **vpp) +msdosfs_root(struct mount *mp, int flags, struct vnode **vpp) { struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); struct denode *ndep; @@ -914,7 +918,8 @@ msdosfs_root(struct mount *mp, struct vnode **vpp) #ifdef MSDOSFS_DEBUG printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); #endif - if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep)) != 0) + if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, flags, &ndep)) + != 0) return (error); *vpp = DETOV(ndep); return (0); @@ -999,7 +1004,8 @@ msdosfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) } int -msdosfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) +msdosfs_fhtovp(struct mount *mp, struct fid *fhp, int flags, + struct vnode **vpp) { struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); struct defid defh; @@ -1021,7 +1027,8 @@ msdosfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) *vpp = NULLVP; return error; } - error = deget(pmp, defh.defid_dirclust, defh.defid_dirofs, &dep); + error = deget(pmp, defh.defid_dirclust, defh.defid_dirofs, flags, + &dep); if (error) { DPRINTF(("deget %d\n", error)); *vpp = NULLVP; @@ -1057,7 +1064,7 @@ msdosfs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size) } int -msdosfs_vget(struct mount *mp, ino_t ino, +msdosfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { diff --git a/sys/fs/nilfs/nilfs_subr.c b/sys/fs/nilfs/nilfs_subr.c index 190228a..b97fd67 100644 --- a/sys/fs/nilfs/nilfs_subr.c +++ b/sys/fs/nilfs/nilfs_subr.c @@ -796,7 +796,8 @@ extern int (**nilfs_vnodeop_p)(void *); int nilfs_get_node_raw(struct nilfs_device *nilfsdev, struct nilfs_mount *ump, - uint64_t ino, struct nilfs_inode *inode, struct nilfs_node **nodep) + uint64_t ino, struct nilfs_inode *inode, int flags, + struct nilfs_node **nodep) { struct nilfs_node *node; struct vnode *nvp; @@ -875,13 +876,15 @@ nilfs_get_node_raw(struct nilfs_device *nilfsdev, struct nilfs_mount *ump, /* return node */ vready(nvp); + VOP_UNLOCK(nvp); *nodep = node; return 0; } int -nilfs_get_node(struct nilfs_mount *ump, uint64_t ino, struct nilfs_node **nodep) +nilfs_get_node(struct nilfs_mount *ump, uint64_t ino, int flags, + struct nilfs_node **nodep) { struct nilfs_device *nilfsdev; struct nilfs_inode inode, *entry; @@ -892,8 +895,10 @@ nilfs_get_node(struct nilfs_mount *ump, uint64_t ino, struct nilfs_node **nodep) /* lookup node in hash table */ *nodep = nilfs_hash_lookup(ump, ino); - if (*nodep) + if (*nodep) { + VOP_UNLOCK((*nodep)->vnode); return 0; + } /* lock to disallow simultanious creation of same udf_node */ mutex_enter(&ump->get_node_lock); @@ -902,6 +907,7 @@ nilfs_get_node(struct nilfs_mount *ump, uint64_t ino, struct nilfs_node **nodep) *nodep = nilfs_hash_lookup(ump, ino); if (*nodep) { mutex_exit(&ump->get_node_lock); + VOP_UNLOCK((*nodep)->vnode); return 0; } @@ -932,7 +938,8 @@ nilfs_get_node(struct nilfs_mount *ump, uint64_t ino, struct nilfs_node **nodep) brelse(bp, BC_AGE); /* get node */ - error = nilfs_get_node_raw(ump->nilfsdev, ump, ino, &inode, nodep); + error = nilfs_get_node_raw(ump->nilfsdev, ump, ino, &inode, flags, + nodep); mutex_exit(&ump->get_node_lock); return error; diff --git a/sys/fs/nilfs/nilfs_subr.h b/sys/fs/nilfs/nilfs_subr.h index 2ebb6ef..44eda0c 100644 --- a/sys/fs/nilfs/nilfs_subr.h +++ b/sys/fs/nilfs/nilfs_subr.h @@ -56,8 +56,8 @@ int nilfs_btree_nlookup(struct nilfs_node *node, uint64_t from, uint64_t blks, u int nilfs_nvtop(struct nilfs_node *node, uint64_t blks, uint64_t *l2vmap, uint64_t *v2pmap); /* node action implementators */ -int nilfs_get_node(struct nilfs_mount *ump, uint64_t ino, struct nilfs_node **nodep); -int nilfs_get_node_raw(struct nilfs_device *nilfsdev, struct nilfs_mount *ump, uint64_t ino, struct nilfs_inode *inode, struct nilfs_node **nodep); +int nilfs_get_node(struct nilfs_mount *ump, uint64_t ino, int flags, struct nilfs_node **nodep); +int nilfs_get_node_raw(struct nilfs_device *nilfsdev, struct nilfs_mount *ump, uint64_t ino, struct nilfs_inode *inode, int flags, struct nilfs_node **nodep); void nilfs_dispose_node(struct nilfs_node **node); int nilfs_grow_node(struct nilfs_node *node, uint64_t new_size); diff --git a/sys/fs/nilfs/nilfs_vfsops.c b/sys/fs/nilfs/nilfs_vfsops.c index 268fe96..2ac81a1 100644 --- a/sys/fs/nilfs/nilfs_vfsops.c +++ b/sys/fs/nilfs/nilfs_vfsops.c @@ -243,19 +243,37 @@ nilfs_create_system_nodes(struct nilfs_device *nilfsdev) int error; error = nilfs_get_node_raw(nilfsdev, NULL, NILFS_DAT_INO, - &nilfsdev->super_root.sr_dat, &nilfsdev->dat_node); + &nilfsdev->super_root.sr_dat, 0, &nilfsdev->dat_node); if (error) goto errorout; + error = vn_lock(nilfsdev->dat_node->vnode, LK_EXCLUSIVE); + if (error) { + vrele(nilfsdev->dat_node->vnode); + nilfsdev->dat_node = NULL; + goto errorout; + } error = nilfs_get_node_raw(nilfsdev, NULL, NILFS_CPFILE_INO, - &nilfsdev->super_root.sr_cpfile, &nilfsdev->cp_node); + &nilfsdev->super_root.sr_cpfile, 0, &nilfsdev->cp_node); if (error) goto errorout; + error = vn_lock(nilfsdev->cp_node->vnode, LK_EXCLUSIVE); + if (error) { + vrele(nilfsdev->cp_node->vnode); + nilfsdev->cp_node = NULL; + goto errorout; + } error = nilfs_get_node_raw(nilfsdev, NULL, NILFS_SUFILE_INO, - &nilfsdev->super_root.sr_sufile, &nilfsdev->su_node); + &nilfsdev->super_root.sr_sufile, 0, &nilfsdev->su_node); if (error) goto errorout; + error = vn_lock(nilfsdev->su_node->vnode, LK_EXCLUSIVE); + if (error) { + vrele(nilfsdev->su_node->vnode); + nilfsdev->su_node = NULL; + goto errorout; + } NILFS_SET_SYSTEMFILE(nilfsdev->dat_node->vnode); NILFS_SET_SYSTEMFILE(nilfsdev->cp_node->vnode); @@ -740,11 +758,18 @@ nilfs_mount_checkpoint(struct nilfs_mount *ump) /* get ifile inode */ error = nilfs_get_node_raw(ump->nilfsdev, NULL, NILFS_IFILE_INO, - &ifile_inode, &ump->ifile_node); + &ifile_inode, 0, &ump->ifile_node); if (error) { printf("mount_nilfs: can't read ifile node\n"); return EINVAL; } + error = vn_lock(ump->ifile_node->vnode, LK_EXCLUSIVE); + if (error) { + vrele(ump->ifile_node->vnode); + ump->ifile_node = NULL; + printf("mount_nilfs: can't lock ifile onde\n"); + return EINVAL; /* XXX Not error? */ + } NILFS_SET_SYSTEMFILE(ump->ifile_node->vnode); /* get root node? */ @@ -994,7 +1019,7 @@ nilfs_start(struct mount *mp, int flags) /* --------------------------------------------------------------------- */ int -nilfs_root(struct mount *mp, struct vnode **vpp) +nilfs_root(struct mount *mp, int flags, struct vnode **vpp) { struct nilfs_mount *ump = VFSTONILFS(mp); struct nilfs_node *node; @@ -1002,7 +1027,7 @@ nilfs_root(struct mount *mp, struct vnode **vpp) DPRINTF(NODE, ("nilfs_root called\n")); - error = nilfs_get_node(ump, NILFS_ROOT_INO, &node); + error = nilfs_get_node(ump, NILFS_ROOT_INO, flags, &node); if (node) { *vpp = node->vnode; KASSERT(node->vnode->v_vflag & VV_ROOT); @@ -1057,7 +1082,7 @@ nilfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) * (optional) TODO lookup why some sources state NFSv3 */ int -nilfs_vget(struct mount *mp, ino_t ino, +nilfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { DPRINTF(NOTIMPL, ("nilfs_vget called\n")); @@ -1070,7 +1095,7 @@ nilfs_vget(struct mount *mp, ino_t ino, * Lookup vnode for file handle specified */ int -nilfs_fhtovp(struct mount *mp, struct fid *fhp, +nilfs_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) { DPRINTF(NOTIMPL, ("nilfs_fhtovp called\n")); diff --git a/sys/fs/nilfs/nilfs_vnops.c b/sys/fs/nilfs/nilfs_vnops.c index a48ff8e..af4c11f 100644 --- a/sys/fs/nilfs/nilfs_vnops.c +++ b/sys/fs/nilfs/nilfs_vnops.c @@ -697,7 +697,15 @@ nilfs_lookup(void *v) if (error == 0) { DPRINTF(LOOKUP, ("\tfound '..'\n")); /* try to create/reuse the node */ - error = nilfs_get_node(ump, ino, &res_node); + error = nilfs_get_node(ump, ino, 0, &res_node); + if (!error) { /* XXX ugh bletch !error branch */ + /* XXX Omit needless lock/unlock. */ + error = vn_lock(res_node->vnode, LK_EXCLUSIVE); + if (error) { + vrele(res_node->vnode); + res_node = NULL; + } + } if (!error) { DPRINTF(LOOKUP, @@ -738,7 +746,15 @@ nilfs_lookup(void *v) /* done */ } else { /* try to create/reuse the node */ - error = nilfs_get_node(ump, ino, &res_node); + error = nilfs_get_node(ump, ino, 0, &res_node); + if (!error) { /* XXX ugh bletch !error branch */ + /* XXX Omit needless lock/unlock. */ + error = vn_lock(res_node->vnode, LK_EXCLUSIVE); + if (error) { + vrele(res_node->vnode); + res_node = NULL; + } + } if (!error) { /* * If we are not at the last path component diff --git a/sys/fs/ntfs/ntfs_subr.c b/sys/fs/ntfs/ntfs_subr.c index b58f517..ef08766 100644 --- a/sys/fs/ntfs/ntfs_subr.c +++ b/sys/fs/ntfs/ntfs_subr.c @@ -861,6 +861,7 @@ ntfs_ntlookupfile( struct ntfsmount * ntmp, struct vnode * vp, struct componentname * cnp, + int flags, struct vnode ** vpp) { struct fnode *fp = VTOF(vp); @@ -1117,7 +1118,10 @@ fail: ntfs_ntvattrrele(vap); ntfs_ntput(ip); free(rdbuf, M_TEMP); - return (error); + if (error) + return (error); + VOP_UNLOCK(*vpp); + return (0); } /* @@ -2034,8 +2038,13 @@ ntfs_toupper_use(struct mount *mp, struct ntfsmount *ntmp) ntfs_toupper_tab = malloc(256 * 256 * sizeof(*ntfs_toupper_tab), M_NTFSRDATA, M_WAITOK); - if ((error = VFS_VGET(mp, NTFS_UPCASEINO, &vp))) + if ((error = VFS_VGET(mp, NTFS_UPCASEINO, 0, &vp))) + goto out; + if ((error = vn_lock(vp, LK_EXCLUSIVE))) { + vrele(vp); + vp = NULL; goto out; + } error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 0, 256 * 256 * sizeof(*ntfs_toupper_tab), (char *)ntfs_toupper_tab, NULL); diff --git a/sys/fs/ntfs/ntfs_subr.h b/sys/fs/ntfs/ntfs_subr.h index da94401..bcccebb 100644 --- a/sys/fs/ntfs/ntfs_subr.h +++ b/sys/fs/ntfs/ntfs_subr.h @@ -96,7 +96,7 @@ int ntfs_loadntvattrs(struct ntfsmount *, struct vnode *, void *, struct ntvattr * ntfs_findntvattr(struct ntfsmount *, struct ntnode *, u_int32_t, cn_t); int ntfs_ntlookupfile(struct ntfsmount *, struct vnode *, - struct componentname *, struct vnode **); + struct componentname *, int, struct vnode **); int ntfs_isnamepermitted(struct ntfsmount *, struct attr_indexentry *); int ntfs_ntvattrrele(struct ntvattr *); int ntfs_ntvattrget(struct ntfsmount *, struct ntnode *, u_int32_t, diff --git a/sys/fs/ntfs/ntfs_vfsops.c b/sys/fs/ntfs/ntfs_vfsops.c index 56efd03..bb5b484 100644 --- a/sys/fs/ntfs/ntfs_vfsops.c +++ b/sys/fs/ntfs/ntfs_vfsops.c @@ -67,12 +67,12 @@ MALLOC_JUSTDEFINE(M_NTFSFNODE,"NTFS fnode", "NTFS fnode information"); MALLOC_JUSTDEFINE(M_NTFSDIR,"NTFS dir", "NTFS dir buffer"); static int ntfs_mount(struct mount *, const char *, void *, size_t *); -static int ntfs_root(struct mount *, struct vnode **); +static int ntfs_root(struct mount *, int, struct vnode **); static int ntfs_start(struct mount *, int); static int ntfs_statvfs(struct mount *, struct statvfs *); static int ntfs_sync(struct mount *, int, kauth_cred_t); static int ntfs_unmount(struct mount *, int); -static int ntfs_vget(struct mount *mp, ino_t ino, +static int ntfs_vget(struct mount *mp, ino_t ino, int, struct vnode **vpp); static int ntfs_mountfs(struct vnode *, struct mount *, struct ntfs_args *, struct lwp *); @@ -81,7 +81,7 @@ static int ntfs_vptofh(struct vnode *, struct fid *, size_t *); static void ntfs_init(void); static void ntfs_reinit(void); static void ntfs_done(void); -static int ntfs_fhtovp(struct mount *, struct fid *, +static int ntfs_fhtovp(struct mount *, struct fid *, int, struct vnode **); static int ntfs_mountroot(void); @@ -374,9 +374,16 @@ ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp, str { 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], 0, + &ntmp->ntm_sysvn[pi[i]]); if(error) goto out1; + error = vn_lock(ntmp->ntm_sysvn[pi[i]], LK_EXCLUSIVE); + if(error) { + vrele(ntmp->ntm_sysvn[pi[i]]); + ntmp->ntm_sysvn[pi[i]] = NULL; + goto out1; + } ntmp->ntm_sysvn[pi[i]]->v_vflag |= VV_SYSTEM; vref(ntmp->ntm_sysvn[pi[i]]); vput(ntmp->ntm_sysvn[pi[i]]); @@ -404,9 +411,15 @@ ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp, str struct attrdef ad; /* Open $AttrDef */ - error = VFS_VGET(mp, NTFS_ATTRDEFINO, &vp ); + error = VFS_VGET(mp, NTFS_ATTRDEFINO, 0, &vp); if(error) goto out1; + error = vn_lock(vp, LK_EXCLUSIVE); + if(error) { + vrele(vp); + vp = NULL; + goto out1; + } /* Count valid entries */ for(num=0;;num++) { @@ -556,6 +569,7 @@ ntfs_unmount( static int ntfs_root( struct mount *mp, + int flags, struct vnode **vpp) { struct vnode *nvp; @@ -563,7 +577,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, flags, &nvp); if(error) { printf("ntfs_root: VFS_VGET failed: %d\n",error); return (error); @@ -646,6 +660,7 @@ static int ntfs_fhtovp( struct mount *mp, struct fid *fhp, + int flags, struct vnode **vpp) { struct ntfid ntfh; @@ -663,6 +678,7 @@ ntfs_fhtovp( *vpp = NULLVP; return (error); } + VOP_UNLOCK(*vpp); /* XXX as unlink/rmdir/mkdir/creat are not currently possible * with NTFS, we don't need to check anything else for now */ @@ -848,9 +864,16 @@ static int ntfs_vget( struct mount *mp, ino_t ino, + int flags, struct vnode **vpp) { - return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL, LK_EXCLUSIVE, 0, vpp); + int error; + + error = ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL, LK_EXCLUSIVE, 0, vpp); + if (error) + return error; + VOP_UNLOCK(*vpp); + return 0; } extern const struct vnodeopv_desc ntfs_vnodeop_opv_desc; diff --git a/sys/fs/ntfs/ntfs_vnops.c b/sys/fs/ntfs/ntfs_vnops.c index 2afa861..c16a75f 100644 --- a/sys/fs/ntfs/ntfs_vnops.c +++ b/sys/fs/ntfs/ntfs_vnops.c @@ -709,19 +709,39 @@ ntfs_lookup(void *v) 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); - ntfs_ntvattrrele(vap); - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + error = VFS_VGET(ntmp->ntm_mountp, vap->va_a_name->n_pnumber, + 0, ap->a_vpp); + if (error) { + ntfs_ntvattrrele(vap); + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + return (error); + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE); if (error) { + vrele(*ap->a_vpp); + *ap->a_vpp = NULL; + ntfs_ntvattrrele(vap); + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); return (error); } + ntfs_ntvattrrele(vap); + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); } else { - error = ntfs_ntlookupfile(ntmp, dvp, cnp, ap->a_vpp); + error = ntfs_ntlookupfile(ntmp, dvp, cnp, 0, ap->a_vpp); if (error) { dprintf(("ntfs_ntlookupfile: returned %d\n", error)); return (error); } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE); + if (error) { + vrele(*ap->a_vpp); + *ap->a_vpp = NULL; + dprintf(("ntfs_ntlookupfile: lock returned %d\n", + error)); + return (error); + } dprintf(("ntfs_lookup: found ino: %llu\n", (unsigned long long)VTONT(*ap->a_vpp)->i_number)); diff --git a/sys/fs/ptyfs/ptyfs.h b/sys/fs/ptyfs/ptyfs.h index 71a7395..a5ab8eb 100644 --- a/sys/fs/ptyfs/ptyfs.h +++ b/sys/fs/ptyfs/ptyfs.h @@ -151,7 +151,7 @@ struct ptyfs_args { int ptyfs_freevp(struct vnode *); struct vnode *ptyfs_used_get(ptyfstype, int, struct mount *, int); -int ptyfs_allocvp(struct mount *, struct vnode **, ptyfstype, int, +int ptyfs_allocvp(struct mount *, int, struct vnode **, ptyfstype, int, struct lwp *); void ptyfs_hashinit(void); void ptyfs_hashreinit(void); @@ -162,7 +162,7 @@ void ptyfs_itimes(struct ptyfsnode *, const struct timespec *, extern int (**ptyfs_vnodeop_p)(void *); extern struct vfsops ptyfs_vfsops; -int ptyfs_root(struct mount *, struct vnode **); +int ptyfs_root(struct mount *, int, struct vnode **); #endif /* _KERNEL */ #endif /* _FS_PTYFS_PTYFS_H_ */ diff --git a/sys/fs/ptyfs/ptyfs_subr.c b/sys/fs/ptyfs/ptyfs_subr.c index 83dfbea..46a6214 100644 --- a/sys/fs/ptyfs/ptyfs_subr.c +++ b/sys/fs/ptyfs/ptyfs_subr.c @@ -208,16 +208,18 @@ out: * the vnode free list. */ int -ptyfs_allocvp(struct mount *mp, struct vnode **vpp, ptyfstype type, int pty, - struct lwp *l) +ptyfs_allocvp(struct mount *mp, int flags, struct vnode **vpp, ptyfstype type, + int pty, struct lwp *l) { struct ptyfsnode *ptyfs; struct vnode *vp; int error; retry: - if ((*vpp = ptyfs_used_get(type, pty, mp, LK_EXCLUSIVE)) != NULL) + if ((*vpp = ptyfs_used_get(type, pty, mp, LK_EXCLUSIVE)) != NULL) { + VOP_UNLOCK(*vpp); return 0; + } error = getnewvnode(VT_PTYFS, mp, ptyfs_vnodeop_p, NULL, 0, &vp); if (error) { @@ -232,6 +234,10 @@ ptyfs_allocvp(struct mount *mp, struct vnode **vpp, ptyfstype type, int pty, goto retry; } + /* + * XXX Can't call ptyfs_free_get under ptyfs_hashlock because + * it mallocs. + */ vp->v_data = ptyfs = ptyfs_free_get(type, pty, l); ptyfs->ptyfs_vnode = vp; @@ -255,6 +261,7 @@ ptyfs_allocvp(struct mount *mp, struct vnode **vpp, ptyfstype type, int pty, mutex_exit(&ptyfs_hashlock); vready(vp); + VOP_UNLOCK(vp); *vpp = vp; return 0; } diff --git a/sys/fs/ptyfs/ptyfs_vfsops.c b/sys/fs/ptyfs/ptyfs_vfsops.c index be65200..69a7a91 100644 --- a/sys/fs/ptyfs/ptyfs_vfsops.c +++ b/sys/fs/ptyfs/ptyfs_vfsops.c @@ -72,8 +72,8 @@ VFS_PROTOS(ptyfs); static struct sysctllog *ptyfs_sysctl_log; -static int ptyfs__allocvp(struct mount *, struct lwp *, struct vnode **, - dev_t, char); +static int ptyfs__allocvp(struct mount *, struct lwp *, int flags, + struct vnode **, dev_t, char); static int ptyfs__makename(struct mount *, struct lwp *, char *, size_t, dev_t, char); static void ptyfs__getvattr(struct mount *, struct lwp *, struct vattr *); @@ -190,7 +190,7 @@ ptyfs__makename(struct mount *mp, struct lwp *l, char *tbuf, size_t bufsiz, static int /*ARGSUSED*/ -ptyfs__allocvp(struct mount *mp, struct lwp *l, struct vnode **vpp, +ptyfs__allocvp(struct mount *mp, struct lwp *l, int flags, struct vnode **vpp, dev_t dev, char ms) { ptyfstype type; @@ -206,7 +206,7 @@ ptyfs__allocvp(struct mount *mp, struct lwp *l, struct vnode **vpp, return EINVAL; } - return ptyfs_allocvp(mp, vpp, type, minor(dev), l); + return ptyfs_allocvp(mp, flags, vpp, type, minor(dev), l); } @@ -365,10 +365,10 @@ ptyfs_unmount(struct mount *mp, int mntflags) } int -ptyfs_root(struct mount *mp, struct vnode **vpp) +ptyfs_root(struct mount *mp, int flags, struct vnode **vpp) { /* setup "." */ - return ptyfs_allocvp(mp, vpp, PTYFSroot, 0, NULL); + return ptyfs_allocvp(mp, flags, vpp, PTYFSroot, 0, NULL); } /*ARGSUSED*/ @@ -385,7 +385,7 @@ ptyfs_sync(struct mount *mp, int waitfor, */ /*ARGSUSED*/ int -ptyfs_vget(struct mount *mp, ino_t ino, +ptyfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { return EOPNOTSUPP; diff --git a/sys/fs/ptyfs/ptyfs_vnops.c b/sys/fs/ptyfs/ptyfs_vnops.c index ecfb1e9..7592c1a 100644 --- a/sys/fs/ptyfs/ptyfs_vnops.c +++ b/sys/fs/ptyfs/ptyfs_vnops.c @@ -643,10 +643,17 @@ ptyfs_lookup(void *v) ptyfs_used_get(PTYFSptc, pty, dvp->v_mount, 0) == NULL) break; - error = ptyfs_allocvp(dvp->v_mount, vpp, PTYFSpts, pty, + error = ptyfs_allocvp(dvp->v_mount, 0, vpp, PTYFSpts, pty, curlwp); if (error) return error; + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + return error; + } VOP_UNLOCK(*vpp); return 0; diff --git a/sys/fs/puffs/puffs_vfsops.c b/sys/fs/puffs/puffs_vfsops.c index 859071c..122a942 100644 --- a/sys/fs/puffs/puffs_vfsops.c +++ b/sys/fs/puffs/puffs_vfsops.c @@ -461,14 +461,17 @@ puffs_vfsop_unmount(struct mount *mp, int mntflags) * This doesn't need to travel to userspace */ int -puffs_vfsop_root(struct mount *mp, struct vnode **vpp) +puffs_vfsop_root(struct mount *mp, int flags, struct vnode **vpp) { struct puffs_mount *pmp = MPTOPUFFSMP(mp); int rv; - rv = puffs_cookie2vnode(pmp, pmp->pmp_root_cookie, 1, 1, vpp); - KASSERT(rv != PUFFS_NOSUCHCOOKIE); - return rv; + if ((rv = puffs_cookie2vnode(pmp, pmp->pmp_root_cookie, 1, 1, vpp))) { + KASSERT(rv != PUFFS_NOSUCHCOOKIE); + return rv; + } + VOP_UNLOCK(*vpp); + return 0; } int @@ -605,7 +608,8 @@ puffs_vfsop_sync(struct mount *mp, int waitfor, struct kauth_cred *cred) } int -puffs_vfsop_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) +puffs_vfsop_fhtovp(struct mount *mp, struct fid *fhp, int flags, + struct vnode **vpp) { PUFFS_MSG_VARS(vfs, fhtonode); struct puffs_mount *pmp = MPTOPUFFSMP(mp); @@ -644,6 +648,7 @@ puffs_vfsop_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) if (error) goto out; + /* XXX Omit needless lock/unlock. */ error = puffs_cookie2vnode(pmp, fhtonode_msg->pvfsr_fhcookie, 1,1,&vp); DPRINTF(("puffs_fhtovp: got cookie %p, existing vnode %p\n", fhtonode_msg->pvfsr_fhcookie, vp)); @@ -658,6 +663,7 @@ puffs_vfsop_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) goto out; } + VOP_UNLOCK(vp); *vpp = vp; out: puffs_msgmem_release(park_fhtonode); diff --git a/sys/fs/smbfs/smbfs_node.c b/sys/fs/smbfs/smbfs_node.c index c2c46e1..c2c6a73 100644 --- a/sys/fs/smbfs/smbfs_node.c +++ b/sys/fs/smbfs/smbfs_node.c @@ -230,7 +230,7 @@ allocnew: int smbfs_nget(struct mount *mp, struct vnode *dvp, const char *name, int nmlen, - struct smbfattr *fap, struct vnode **vpp) + struct smbfattr *fap, int flags, struct vnode **vpp) { struct vnode *vp = NULL; /* XXX gcc 4.8: maybe-uninitialized */ int error; @@ -240,6 +240,7 @@ smbfs_nget(struct mount *mp, struct vnode *dvp, const char *name, int nmlen, return error; if (fap) smbfs_attr_cacheenter(vp, fap); + VOP_UNLOCK(vp); *vpp = vp; return 0; } diff --git a/sys/fs/smbfs/smbfs_node.h b/sys/fs/smbfs/smbfs_node.h index 3ffad42..8a8eded0 100644 --- a/sys/fs/smbfs/smbfs_node.h +++ b/sys/fs/smbfs/smbfs_node.h @@ -86,7 +86,7 @@ struct smbfattr; int smbfs_inactive(void *); int smbfs_reclaim(void *); int smbfs_nget(struct mount *, struct vnode *, const char *, int, - struct smbfattr *, struct vnode **); + struct smbfattr *, int, struct vnode **); #define smbfs_hash(x, y) hash32_strn((x), (y), HASH32_STR_INIT) int smbfs_readvnode(struct vnode *, struct uio *, kauth_cred_t); diff --git a/sys/fs/smbfs/smbfs_vfsops.c b/sys/fs/smbfs/smbfs_vfsops.c index 8be80ae..c72c8b3 100644 --- a/sys/fs/smbfs/smbfs_vfsops.c +++ b/sys/fs/smbfs/smbfs_vfsops.c @@ -285,9 +285,14 @@ smbfs_setroot(struct mount *mp) error = smbfs_smb_lookup(NULL, NULL, 0, &fattr, &scred); if (error) return error; - error = smbfs_nget(mp, NULL, "TheRooT", 7, &fattr, &vp); + error = smbfs_nget(mp, NULL, "TheRooT", 7, &fattr, 0, &vp); if (error) return error; + error = vn_lock(vp, LK_EXCLUSIVE); + if (error) { + vrele(vp); + return error; + } /* * Someone might have already set sm_root while we slept @@ -310,7 +315,7 @@ smbfs_setroot(struct mount *mp) * Return locked root vnode of a filesystem. */ int -smbfs_root(struct mount *mp, struct vnode **vpp) +smbfs_root(struct mount *mp, int flags, struct vnode **vpp) { struct smbmount *smp = VFSTOSMBFS(mp); int error; @@ -325,9 +330,11 @@ smbfs_root(struct mount *mp, struct vnode **vpp) KASSERT(smp->sm_root != NULL && SMBTOV(smp->sm_root) != NULL); *vpp = SMBTOV(smp->sm_root); vref(*vpp); + /* XXX Omit needless lock/unlock. */ error = vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); if (error) vrele(*vpp); + VOP_UNLOCK(*vpp); return error; } @@ -437,12 +444,13 @@ smbfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) return (allerror); } +/* XXX This conditional is a little misleading! */ #if __FreeBSD_version < 400009 /* * smbfs flat namespace lookup. Unsupported. */ /* ARGSUSED */ -int smbfs_vget(struct mount *mp, ino_t ino, +int smbfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { return (EOPNOTSUPP); diff --git a/sys/fs/smbfs/smbfs_vnops.c b/sys/fs/smbfs/smbfs_vnops.c index c6915e9..e577ed0 100644 --- a/sys/fs/smbfs/smbfs_vnops.c +++ b/sys/fs/smbfs/smbfs_vnops.c @@ -601,9 +601,17 @@ smbfs_create(void *v) error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, &scred); if (error) goto out; - error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, ap->a_vpp); + error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, 0, + ap->a_vpp); if (error) goto out; + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE); + if (error) { + vrele(*ap->a_vpp); + *ap->a_vpp = NULL; + goto out; + } VOP_UNLOCK(*ap->a_vpp); cache_enter(dvp, *ap->a_vpp, cnp->cn_nameptr, cnp->cn_namelen, @@ -804,9 +812,16 @@ smbfs_mkdir(void *v) error = smbfs_smb_lookup(dnp, name, len, &fattr, &scred); if (error) goto out; - error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp); + error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, 0, &vp); if (error) goto out; + /* XXX Omit needless lock/unlock. */ + error = vn_lock(vp, LK_EXCLUSIVE); + if (error) { + vrele(vp); + vp = NULL; + goto out; + } VOP_UNLOCK(vp); *ap->a_vpp = vp; @@ -1345,11 +1360,22 @@ smbfs_lookup(void *v) return (EISDIR); if (flags & ISDOTDOT) VOP_UNLOCK(dvp); - error = smbfs_nget(mp, dvp, name, nmlen, &fattr, vpp); + error = smbfs_nget(mp, dvp, name, nmlen, &fattr, 0, vpp); + if (error) { + if (flags & ISDOTDOT) + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + return (error); + } + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + if (flags & ISDOTDOT) + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + return (error); + } if (flags & ISDOTDOT) vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); - if (error) - return (error); if (*vpp != dvp) VOP_UNLOCK(*vpp); return (0); @@ -1368,18 +1394,34 @@ smbfs_lookup(void *v) * ".." lookup */ VOP_UNLOCK(dvp); - error = smbfs_nget(mp, dvp, name, nmlen, NULL, vpp); - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + error = smbfs_nget(mp, dvp, name, nmlen, NULL, 0, vpp); + if (error) { + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + return error; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); if (error) { + vrele(*vpp); + *vpp = NULL; + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); return error; } + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); } else { /* * Other lookups. */ - error = smbfs_nget(mp, dvp, name, nmlen, &fattr, vpp); + error = smbfs_nget(mp, dvp, name, nmlen, &fattr, 0, vpp); if (error) return error; + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + return error; + } } KASSERT(error == 0); diff --git a/sys/fs/sysvbfs/sysvbfs_vfsops.c b/sys/fs/sysvbfs/sysvbfs_vfsops.c index 4f4f76b..51c2ce4 100644 --- a/sys/fs/sysvbfs/sysvbfs_vfsops.c +++ b/sys/fs/sysvbfs/sysvbfs_vfsops.c @@ -241,13 +241,13 @@ sysvbfs_unmount(struct mount *mp, int mntflags) } int -sysvbfs_root(struct mount *mp, struct vnode **vpp) +sysvbfs_root(struct mount *mp, int flags, struct vnode **vpp) { struct vnode *vp; int error; DPRINTF("%s:\n", __func__); - if ((error = VFS_VGET(mp, BFS_ROOT_INODE, &vp)) != 0) + if ((error = VFS_VGET(mp, BFS_ROOT_INODE, flags, &vp)) != 0) return error; *vpp = vp; @@ -297,6 +297,7 @@ sysvbfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) DPRINTF("%s:\n", __func__); error = 0; + /* XXX Should use vnode_iterator(9) here. */ mutex_enter(&mntvnode_lock); for (bnode = LIST_FIRST(&bmp->bnode_head); bnode != NULL; bnode = LIST_NEXT(bnode, link)) { @@ -318,7 +319,7 @@ sysvbfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) } int -sysvbfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) +sysvbfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { struct sysvbfs_mount *bmp = mp->mnt_data; struct bfs *bfs = bmp->bfs; @@ -343,6 +344,7 @@ sysvbfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) mutex_enter(vp->v_interlock); mutex_exit(&mntvnode_lock); if (vget(vp, LK_EXCLUSIVE) == 0) { + VOP_UNLOCK(vp); *vpp = vp; return 0; } else { @@ -384,13 +386,15 @@ sysvbfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) genfs_node_init(vp, &sysvbfs_genfsops); uvm_vnp_setsize(vp, bfs_file_size(inode)); vready(vp); + VOP_UNLOCK(vp); *vpp = vp; return 0; } int -sysvbfs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp) +sysvbfs_fhtovp(struct mount *mp, struct fid *fid, int flags, + struct vnode **vpp) { DPRINTF("%s:\n", __func__); diff --git a/sys/fs/sysvbfs/sysvbfs_vnops.c b/sys/fs/sysvbfs/sysvbfs_vnops.c index 88502f3..a12d6123 100644 --- a/sys/fs/sysvbfs/sysvbfs_vnops.c +++ b/sys/fs/sysvbfs/sysvbfs_vnops.c @@ -114,10 +114,16 @@ sysvbfs_lookup(void *arg) } /* Allocate v-node */ - if ((error = sysvbfs_vget(v->v_mount, dirent->inode, &vpp)) != 0) { + if ((error = sysvbfs_vget(v->v_mount, dirent->inode, 0, &vpp)) + != 0) { DPRINTF("%s: can't get vnode.\n", __func__); return error; } + /* XXX Omit needless lock/unlock. */ + if ((error = vn_lock(vpp, LK_EXCLUSIVE)) != 0) { + vrele(vpp); + return error; + } VOP_UNLOCK(vpp); *a->a_vpp = vpp; } @@ -159,10 +165,15 @@ sysvbfs_create(void *arg) if (!bfs_dirent_lookup_by_name(bfs, a->a_cnp->cn_nameptr, &dirent)) panic("no dirent for created file."); - if ((err = sysvbfs_vget(mp, dirent->inode, a->a_vpp)) != 0) { + if ((err = sysvbfs_vget(mp, dirent->inode, 0, a->a_vpp)) != 0) { DPRINTF("%s: sysvbfs_vget failed.\n", __func__); return err; } + if ((err = vn_lock(*a->a_vpp, LK_EXCLUSIVE)) != 0) { + vrele(*a->a_vpp); + *a->a_vpp = NULL; + return err; + } bnode = (*a->a_vpp)->v_data; bnode->update_ctime = true; bnode->update_mtime = true; diff --git a/sys/fs/tmpfs/tmpfs.h b/sys/fs/tmpfs/tmpfs.h index 4bff3f5..b94a671 100644 --- a/sys/fs/tmpfs/tmpfs.h +++ b/sys/fs/tmpfs/tmpfs.h @@ -247,7 +247,8 @@ void tmpfs_free_node(tmpfs_mount_t *, tmpfs_node_t *); int tmpfs_construct_node(vnode_t *, vnode_t **, struct vattr *, struct componentname *, char *); -int tmpfs_vnode_get(struct mount *, tmpfs_node_t *, vnode_t **); +int tmpfs_vnode_get(struct mount *, tmpfs_node_t *, int, + vnode_t **); int tmpfs_alloc_dirent(tmpfs_mount_t *, const char *, uint16_t, tmpfs_dirent_t **); diff --git a/sys/fs/tmpfs/tmpfs_rename.c b/sys/fs/tmpfs/tmpfs_rename.c index 7bb7649..9ca9e95 100644 --- a/sys/fs/tmpfs/tmpfs_rename.c +++ b/sys/fs/tmpfs/tmpfs_rename.c @@ -440,10 +440,15 @@ tmpfs_gro_lookup(struct mount *mp, struct vnode *dvp, return ENOENT; mutex_enter(&dirent->td_node->tn_vlock); - error = tmpfs_vnode_get(mp, dirent->td_node, &vp); + error = tmpfs_vnode_get(mp, dirent->td_node, 0, &vp); /* Note: tmpfs_vnode_get always releases dirent->td_node->tn_vlock. */ if (error) return error; + error = vn_lock(vp, LK_EXCLUSIVE); + if (error) { + vrele(vp); + return error; + } KASSERT(vp != NULL); KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); @@ -552,9 +557,14 @@ tmpfs_gro_genealogy(struct mount *mp, kauth_cred_t cred, mutex_enter(&dnode->tn_vlock); vput(vp); vp = NULL; /* Just in case, for the kassert above... */ - error = tmpfs_vnode_get(mp, dnode, &vp); + error = tmpfs_vnode_get(mp, dnode, 0, &vp); if (error) return error; + error = vn_lock(vp, LK_EXCLUSIVE); + if (error) { + vrele(vp); + return error; + } /* * tmpfs_vnode_get only guarantees that dnode will not diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c index 2dbecce..dfcc762 100644 --- a/sys/fs/tmpfs/tmpfs_subr.c +++ b/sys/fs/tmpfs/tmpfs_subr.c @@ -272,7 +272,7 @@ tmpfs_free_node(tmpfs_mount_t *tmp, tmpfs_node_t *node) * => Returns vnode (*vpp) locked. */ int -tmpfs_vnode_get(struct mount *mp, tmpfs_node_t *node, vnode_t **vpp) +tmpfs_vnode_get(struct mount *mp, tmpfs_node_t *node, int flags, vnode_t **vpp) { vnode_t *vp; kmutex_t *slock; @@ -289,6 +289,7 @@ again: goto again; } atomic_and_32(&node->tn_gen, ~TMPFS_RECLAIMING_BIT); + VOP_UNLOCK(vp); *vpp = vp; return error; } @@ -344,6 +345,7 @@ again: KASSERT(VOP_ISLOCKED(vp)); vready(vp); + VOP_UNLOCK(vp); *vpp = vp; return 0; } @@ -400,12 +402,20 @@ tmpfs_construct_node(vnode_t *dvp, vnode_t **vpp, struct vattr *vap, /* Get a vnode for the new file. */ mutex_enter(&node->tn_vlock); - error = tmpfs_vnode_get(dvp->v_mount, node, vpp); + error = tmpfs_vnode_get(dvp->v_mount, node, 0, vpp); if (error) { tmpfs_free_dirent(tmp, de); tmpfs_free_node(tmp, node); goto out; } + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + tmpfs_free_dirent(tmp, de); + tmpfs_free_node(tmp, node); + goto out; + } /* Remove whiteout before adding the new entry. */ if (cnp->cn_flags & ISWHITEOUT) { diff --git a/sys/fs/tmpfs/tmpfs_vfsops.c b/sys/fs/tmpfs/tmpfs_vfsops.c index e6e7c37..d9fa75d 100644 --- a/sys/fs/tmpfs/tmpfs_vfsops.c +++ b/sys/fs/tmpfs/tmpfs_vfsops.c @@ -65,9 +65,9 @@ struct pool tmpfs_node_pool; static int tmpfs_mount(struct mount *, const char *, void *, size_t *); static int tmpfs_start(struct mount *, int); static int tmpfs_unmount(struct mount *, int); -static int tmpfs_root(struct mount *, vnode_t **); -static int tmpfs_vget(struct mount *, ino_t, vnode_t **); -static int tmpfs_fhtovp(struct mount *, struct fid *, vnode_t **); +static int tmpfs_root(struct mount *, int, vnode_t **); +static int tmpfs_vget(struct mount *, ino_t, int, vnode_t **); +static int tmpfs_fhtovp(struct mount *, struct fid *, int, vnode_t **); static int tmpfs_vptofh(struct vnode *, struct fid *, size_t *); static int tmpfs_statvfs(struct mount *, struct statvfs *); static int tmpfs_sync(struct mount *, int, kauth_cred_t); @@ -260,23 +260,23 @@ tmpfs_unmount(struct mount *mp, int mntflags) } static int -tmpfs_root(struct mount *mp, vnode_t **vpp) +tmpfs_root(struct mount *mp, int flags, vnode_t **vpp) { tmpfs_node_t *node = VFS_TO_TMPFS(mp)->tm_root; mutex_enter(&node->tn_vlock); - return tmpfs_vnode_get(mp, node, vpp); + return tmpfs_vnode_get(mp, node, flags, vpp); } static int -tmpfs_vget(struct mount *mp, ino_t ino, vnode_t **vpp) +tmpfs_vget(struct mount *mp, ino_t ino, int flags, vnode_t **vpp) { return EOPNOTSUPP; } static int -tmpfs_fhtovp(struct mount *mp, struct fid *fhp, vnode_t **vpp) +tmpfs_fhtovp(struct mount *mp, struct fid *fhp, int flags, vnode_t **vpp) { tmpfs_mount_t *tmp = VFS_TO_TMPFS(mp); tmpfs_node_t *node; @@ -300,13 +300,18 @@ tmpfs_fhtovp(struct mount *mp, struct fid *fhp, vnode_t **vpp) if (node == NULL) return ESTALE; /* Will release the tn_vlock. */ - if ((error = tmpfs_vnode_get(mp, node, vpp)) != 0) + if ((error = tmpfs_vnode_get(mp, node, flags, vpp)) != 0) return error; + if ((error = vn_lock(*vpp, LK_EXCLUSIVE)) != 0) { + vrele(*vpp); + return error; + } if (TMPFS_NODE_GEN(node) != tfh.tf_gen) { vput(*vpp); *vpp = NULL; return ESTALE; } + VOP_UNLOCK(*vpp); return 0; } diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c index 524b3f2..2cc504a 100644 --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -214,7 +214,19 @@ tmpfs_lookup(void *v) * Get a vnode of the '..' entry and re-acquire the lock. * Release the tn_vlock. */ - error = tmpfs_vnode_get(dvp->v_mount, pnode, vpp); + error = tmpfs_vnode_get(dvp->v_mount, pnode, 0, vpp); + if (error) { + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + goto out; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + goto out; + } vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); goto out; @@ -291,7 +303,16 @@ tmpfs_lookup(void *v) /* Get a vnode for the matching entry. */ mutex_enter(&tnode->tn_vlock); - error = tmpfs_vnode_get(dvp->v_mount, tnode, vpp); + error = tmpfs_vnode_get(dvp->v_mount, tnode, 0, vpp); + if (error) + goto done; + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + goto done; + } done: /* * Cache the result, unless request was for creation (as it does diff --git a/sys/fs/udf/udf_rename.c b/sys/fs/udf/udf_rename.c index 1aa6bb2..0101f67 100644 --- a/sys/fs/udf/udf_rename.c +++ b/sys/fs/udf/udf_rename.c @@ -465,9 +465,15 @@ udf_gro_lookup(struct mount *mp, struct vnode *dvp, return ENOENT; DPRINTF(LOOKUP, ("udf_gro_lookup found '%s'\n", name)); - error = udf_get_node(dir_node->ump, &icb_loc, &res_node); + error = udf_get_node(dir_node->ump, &icb_loc, 0, &res_node); if (error) return error; + /* XXX Omit needless lock/unlock. */ + error = vn_lock(res_node->vnode, LK_EXCLUSIVE); + if (error) { + vrele(res_node->vnode); + return error; + } *vp_ret = res_node->vnode; VOP_UNLOCK(res_node->vnode); @@ -598,10 +604,15 @@ udf_gro_genealogy(struct mount *mp, kauth_cred_t cred, */ DPRINTF(NODE, ("\tgetting the parent node\n")); VOP_UNLOCK(vp); - error = udf_get_node(ump, &parent_loc, &parent_node); + error = udf_get_node(ump, &parent_loc, 0, &parent_node); vrele(vp); if (error) return error; + error = vn_lock(parent_node->vnode, LK_EXCLUSIVE); + if (error) { + vrele(parent_node->vnode); + return error; + } dvp = parent_node->vnode; diff --git a/sys/fs/udf/udf_subr.c b/sys/fs/udf/udf_subr.c index cbeb885..412111f 100644 --- a/sys/fs/udf/udf_subr.c +++ b/sys/fs/udf/udf_subr.c @@ -3041,7 +3041,14 @@ udf_search_vat(struct udf_mount *ump, union udf_pmap *mapping) icb_loc.loc.part_num = udf_rw16(UDF_VTOP_RAWPART); icb_loc.loc.lb_num = udf_rw32(vat_loc); - error = udf_get_node(ump, &icb_loc, &vat_node); + error = udf_get_node(ump, &icb_loc, 0, &vat_node); + if (!error) { /* XXX ugh bletch !error branch */ + error = vn_lock(vat_node->vnode, LK_EXCLUSIVE); + if (error) { + vrele(vat_node->vnode); + vat_node = NULL; + } + } if (!error) { error = udf_check_for_vat(vat_node); DPRINTFIF(VOLUMES, !error, @@ -3141,7 +3148,17 @@ udf_read_metadata_nodes(struct udf_mount *ump, union udf_pmap *mapping) DPRINTF(VOLUMES, ("Metadata file\n")); icb_loc.loc.lb_num = pmm->meta_file_lbn; - error = udf_get_node(ump, &icb_loc, &ump->metadata_node); + error = udf_get_node(ump, &icb_loc, 0, &ump->metadata_node); + /* + * XXX This error branch concept looks extremely sketchy -- + * please fix it. + */ + if (ump->metadata_node) { + if (vn_lock(ump->metadata_node->vnode, LK_EXCLUSIVE)) { + vrele(ump->metadata_node->vnode); + ump->metadata_node = NULL; + } + } if (ump->metadata_node) { vp = ump->metadata_node->vnode; UDF_SET_SYSTEMFILE(vp); @@ -3150,7 +3167,16 @@ udf_read_metadata_nodes(struct udf_mount *ump, union udf_pmap *mapping) icb_loc.loc.lb_num = pmm->meta_mirror_file_lbn; if (icb_loc.loc.lb_num != -1) { DPRINTF(VOLUMES, ("Metadata copy file\n")); - error = udf_get_node(ump, &icb_loc, &ump->metadatamirror_node); + error = udf_get_node(ump, &icb_loc, 0, + &ump->metadatamirror_node); + /* XXX Sketchy error branch concept. */ + if (ump->metadatamirror_node) { + if (vn_lock(ump->metadatamirror_node->vnode, + LK_EXCLUSIVE)) { + vrele(ump->metadatamirror_node->vnode); + ump->metadatamirror_node = NULL; + } + } if (ump->metadatamirror_node) { vp = ump->metadatamirror_node->vnode; UDF_SET_SYSTEMFILE(vp); @@ -3160,7 +3186,16 @@ udf_read_metadata_nodes(struct udf_mount *ump, union udf_pmap *mapping) icb_loc.loc.lb_num = pmm->meta_bitmap_file_lbn; if (icb_loc.loc.lb_num != -1) { DPRINTF(VOLUMES, ("Metadata bitmap file\n")); - error = udf_get_node(ump, &icb_loc, &ump->metadatabitmap_node); + error = udf_get_node(ump, &icb_loc, 0, + &ump->metadatabitmap_node); + /* XXX Sketchy error branch concept. */ + if (ump->metadatabitmap_node) { + if (vn_lock(ump->metadatabitmap_node->vnode, + LK_EXCLUSIVE)) { + vrele(ump->metadatabitmap_node->vnode); + ump->metadatabitmap_node = NULL; + } + } if (ump->metadatabitmap_node) { vp = ump->metadatabitmap_node->vnode; UDF_SET_SYSTEMFILE(vp); @@ -3341,9 +3376,14 @@ udf_read_rootdirs(struct udf_mount *ump) /* try to read in the rootdir */ dir_loc = &ump->fileset_desc->rootdir_icb; - error = udf_get_node(ump, dir_loc, &rootdir_node); + error = udf_get_node(ump, dir_loc, 0, &rootdir_node); if (error) return ENOENT; + error = vn_lock(rootdir_node->vnode, LK_EXCLUSIVE); + if (error) { + vrele(rootdir_node->vnode); + return ENOENT; /* XXX error? */ + } /* aparently it read in fine */ @@ -3354,7 +3394,14 @@ udf_read_rootdirs(struct udf_mount *ump) dir_loc = &ump->fileset_desc->streamdir_icb; if (udf_rw32(dir_loc->len)) { printf("udf_read_rootdirs: streamdir defined "); - error = udf_get_node(ump, dir_loc, &streamdir_node); + error = udf_get_node(ump, dir_loc, 0, &streamdir_node); + if (!error) { /* XXX ugh bletch !error branch */ + error = vn_lock(streamdir_node->vnode, LK_EXCLUSIVE); + if (error) { + vrele(streamdir_node->vnode); + streamdir_node = NULL; + } + } if (error) { printf("but error in streamdir reading\n"); } else { @@ -5279,7 +5326,7 @@ error_out: */ int -udf_get_node(struct udf_mount *ump, struct long_ad *node_icb_loc, +udf_get_node(struct udf_mount *ump, struct long_ad *node_icb_loc, int flags, struct udf_node **udf_noderes) { union dscrptr *dscr; @@ -5305,6 +5352,7 @@ udf_get_node(struct udf_mount *ump, struct long_ad *node_icb_loc, if (udf_node) { DPRINTF(NODE, ("\tgot it from the hash!\n")); /* vnode is returned locked */ + VOP_UNLOCK(udf_node->vnode); *udf_noderes = udf_node; mutex_exit(&ump->get_node_lock); return 0; @@ -5620,6 +5668,7 @@ udf_get_node(struct udf_mount *ump, struct long_ad *node_icb_loc, /* TODO ext attr and streamdir udf_nodes */ vready(nvp); + VOP_UNLOCK(nvp); *udf_noderes = udf_node; return 0; diff --git a/sys/fs/udf/udf_subr.h b/sys/fs/udf/udf_subr.h index 7146c13..9e7db58 100644 --- a/sys/fs/udf/udf_subr.h +++ b/sys/fs/udf/udf_subr.h @@ -131,7 +131,7 @@ uint64_t udf_advance_uniqueid(struct udf_mount *ump); void udf_lock_node(struct udf_node *udf_node, int flag, char const *fname, const int lineno); void udf_unlock_node(struct udf_node *udf_node, int flag); -int udf_get_node(struct udf_mount *ump, struct long_ad *icbloc, struct udf_node **noderes); +int udf_get_node(struct udf_mount *ump, struct long_ad *icbloc, int flags, struct udf_node **noderes); int udf_writeout_node(struct udf_node *udf_node, int waitfor); int udf_dispose_node(struct udf_node *node); diff --git a/sys/fs/udf/udf_vfsops.c b/sys/fs/udf/udf_vfsops.c index dbd49a2..0973d26 100644 --- a/sys/fs/udf/udf_vfsops.c +++ b/sys/fs/udf/udf_vfsops.c @@ -738,7 +738,7 @@ udf_start(struct mount *mp, int flags) /* --------------------------------------------------------------------- */ int -udf_root(struct mount *mp, struct vnode **vpp) +udf_root(struct mount *mp, int flags, struct vnode **vpp) { struct vnode *vp; struct long_ad *dir_loc; @@ -749,7 +749,7 @@ udf_root(struct mount *mp, struct vnode **vpp) DPRINTF(CALL, ("udf_root called\n")); dir_loc = &ump->fileset_desc->rootdir_icb; - error = udf_get_node(ump, dir_loc, &root_dir); + error = udf_get_node(ump, dir_loc, flags, &root_dir); if (!root_dir) error = ENOENT; @@ -888,7 +888,7 @@ udf_sync(struct mount *mp, int waitfor, kauth_cred_t cred) * (optional) TODO lookup why some sources state NFSv3 */ int -udf_vget(struct mount *mp, ino_t ino, +udf_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { DPRINTF(NOTIMPL, ("udf_vget called\n")); @@ -901,7 +901,7 @@ udf_vget(struct mount *mp, ino_t ino, * Lookup vnode for file handle specified */ int -udf_fhtovp(struct mount *mp, struct fid *fhp, +udf_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) { DPRINTF(NOTIMPL, ("udf_fhtovp called\n")); diff --git a/sys/fs/udf/udf_vnops.c b/sys/fs/udf/udf_vnops.c index 81a1cf3..560d83e 100644 --- a/sys/fs/udf/udf_vnops.c +++ b/sys/fs/udf/udf_vnops.c @@ -737,7 +737,15 @@ udf_lookup(void *v) if (error == 0) { DPRINTF(LOOKUP, ("\tfound '..'\n")); /* try to create/reuse the node */ - error = udf_get_node(ump, &icb_loc, &res_node); + error = udf_get_node(ump, &icb_loc, 0, &res_node); + if (!error) { /* XXX ugh bletch !error branch */ + /* XXX Omit needless lock/unlock. */ + error = vn_lock(res_node->vnode, LK_EXCLUSIVE); + if (error) { + vrele(res_node->vnode); + res_node = NULL; + } + } if (!error) { DPRINTF(LOOKUP, @@ -789,9 +797,16 @@ udf_lookup(void *v) */ /* try to create/reuse the node */ - error = udf_get_node(ump, &icb_loc, &res_node); + error = udf_get_node(ump, &icb_loc, 0, &res_node); if (error) goto out; + /* XXX Omit needless lock/unlock. */ + error = vn_lock(res_node->vnode, LK_EXCLUSIVE); + if (error) { + vrele(res_node->vnode); + res_node = NULL; + goto out; + } /* check permissions */ if (islastcn && (cnp->cn_nameiop == DELETE || diff --git a/sys/fs/union/union_vfsops.c b/sys/fs/union/union_vfsops.c index 63a9c59..4ac5579 100644 --- a/sys/fs/union/union_vfsops.c +++ b/sys/fs/union/union_vfsops.c @@ -377,7 +377,7 @@ union_unmount(struct mount *mp, int mntflags) } int -union_root(struct mount *mp, struct vnode **vpp) +union_root(struct mount *mp, int flags, struct vnode **vpp) { struct union_mount *um = MOUNTTOUNIONMOUNT(mp); int error; @@ -399,6 +399,7 @@ union_root(struct mount *mp, struct vnode **vpp) } vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); + VOP_UNLOCK(*vpp); return 0; } @@ -474,7 +475,7 @@ union_sync(struct mount *mp, int waitfor, /*ARGSUSED*/ int -union_vget(struct mount *mp, ino_t ino, +union_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { diff --git a/sys/fs/union/union_vnops.c b/sys/fs/union/union_vnops.c index b1205da..039d422 100644 --- a/sys/fs/union/union_vnops.c +++ b/sys/fs/union/union_vnops.c @@ -251,11 +251,19 @@ union_lookup1(struct vnode *udvp, struct vnode **dvpp, struct vnode **vpp, if (vfs_busy(mp, NULL)) continue; vput(dvp); - error = VFS_ROOT(mp, &tdvp); - vfs_unbusy(mp, false, NULL); + error = VFS_ROOT(mp, 0, &tdvp); if (error) { + vfs_unbusy(mp, false, NULL); return (error); } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdvp, LK_EXCLUSIVE); + if (error) { + vrele(tdvp); + vfs_unbusy(mp, false, NULL); + return (error); + } + vfs_unbusy(mp, false, NULL); dvp = tdvp; } diff --git a/sys/fs/unionfs/unionfs_subr.c b/sys/fs/unionfs/unionfs_subr.c index 0b077d1..386bbf8 100644 --- a/sys/fs/unionfs/unionfs_subr.c +++ b/sys/fs/unionfs/unionfs_subr.c @@ -67,7 +67,7 @@ MALLOC_DEFINE(M_UNIONFSPATH, "UNIONFS path", "UNIONFS path private part"); int unionfs_nodeget(struct mount *mp, struct vnode *uppervp, struct vnode *lowervp, struct vnode *dvp, - struct vnode **vpp, struct componentname *cnp) + int flags, struct vnode **vpp, struct componentname *cnp) { struct unionfs_mount *ump; struct unionfs_node *unp; @@ -129,6 +129,7 @@ unionfs_nodeget(struct mount *mp, struct vnode *uppervp, vp->v_vflag |= VV_ROOT; vready(vp); + VOP_UNLOCK(vp); *vpp = vp; return (0); diff --git a/sys/fs/unionfs/unionfs_vfsops.c b/sys/fs/unionfs/unionfs_vfsops.c index 91d6a74..36cafc5 100644 --- a/sys/fs/unionfs/unionfs_vfsops.c +++ b/sys/fs/unionfs/unionfs_vfsops.c @@ -251,13 +251,23 @@ unionfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) * Get the unionfs root vnode. */ error = unionfs_nodeget(mp, ump->um_uppervp, ump->um_lowervp, - NULLVP, &(ump->um_rootvp), NULL); - vrele(upperrootvp); + NULLVP, 0, &(ump->um_rootvp), NULL); if (error) { + vrele(upperrootvp); free(ump, M_UNIONFSMNT); mp->mnt_data = NULL; return (error); } + error = vn_lock(ump->um_rootvp, LK_EXCLUSIVE); + if (error) { + vrele(ump->um_rootvp); + ump->um_rootvp = NULL; + vrele(upperrootvp); + free(ump, M_UNIONFSMNT); + mp->mnt_data = NULL; + return (error); + } + vrele(upperrootvp); /* * Check mnt_flag @@ -351,7 +361,7 @@ unionfs_unmount(struct mount *mp, int mntflags) } int -unionfs_root(struct mount *mp, struct vnode **vpp) +unionfs_root(struct mount *mp, int flags, struct vnode **vpp) { struct unionfs_mount *ump; struct vnode *vp; @@ -364,6 +374,7 @@ unionfs_root(struct mount *mp, struct vnode **vpp) vref(vp); vn_lock(vp, LK_EXCLUSIVE); + VOP_UNLOCK(vp); *vpp = vp; diff --git a/sys/fs/unionfs/unionfs_vnops.c b/sys/fs/unionfs/unionfs_vnops.c index 332017b..adce6bd 100644 --- a/sys/fs/unionfs/unionfs_vnops.c +++ b/sys/fs/unionfs/unionfs_vnops.c @@ -242,6 +242,12 @@ unionfs_lookup(void *v) cnp); if (error != 0) goto unionfs_lookup_out; + error = vn_lock(vp, LK_EXCLUSIVE); + if (error != 0) { + vrele(vp); + vp = NULL; + goto unionfs_lookup_out; + } error = unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp->v_mount), udvp, VTOUNIONFS(vp), cnp); if (error != 0) { @@ -260,11 +266,19 @@ unionfs_lookup(void *v) error = lerror; if (error != 0) goto unionfs_lookup_out; - error = unionfs_nodeget(dvp->v_mount, uvp, lvp, dvp, &vp, cnp); + error = unionfs_nodeget(dvp->v_mount, uvp, lvp, dvp, 0, &vp, + cnp); if (error != 0) { UNIONFSDEBUG("unionfs_lookup: Unable to create unionfs vnode."); goto unionfs_lookup_out; } + error = vn_lock(vp, LK_EXCLUSIVE); + if (error != 0) { + vrele(vp); + vp = NULL; + UNIONFSDEBUG("unionfs_lookup: Unable to lock unionfs vnode."); + goto unionfs_lookup_out; + } } *(ap->a_vpp) = vp; @@ -309,6 +323,13 @@ unionfs_create(void *v) if ((error = VOP_CREATE(udvp, &vp, cnp, ap->a_vap)) == 0) { error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP, ap->a_dvp, ap->a_vpp, cnp); + if (!error) { /* XXX ugh bletch !error branch */ + error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE); + if (error) { + vrele(*ap->a_vpp); + *ap->a_vpp = NULL; + } + } if (error) { vput(vp); } else { @@ -377,6 +398,13 @@ unionfs_mknod(void *v) if ((error = VOP_MKNOD(udvp, &vp, cnp, ap->a_vap)) == 0) { error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP, ap->a_dvp, ap->a_vpp, cnp); + if (!error) { /* XXX ugh bletch !error branch */ + error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE); + if (error) { + vrele(*ap->a_vpp); + *ap->a_vpp = NULL; + } + } if (error) { vput(vp); } else { @@ -1190,6 +1218,13 @@ unionfs_mkdir(void *v) if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) { error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, ap->a_dvp, ap->a_vpp, cnp); + if (!error) { /* XXX ugh bletch !error branch */ + error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE); + if (error) { + vrele(*ap->a_vpp); + *ap->a_vpp = NULL; + } + } if (error) { vput(uvp); } else { @@ -1278,6 +1313,13 @@ unionfs_symlink(void *v) if (error == 0) { error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, ap->a_dvp, ap->a_vpp, cnp); + if (!error) { /* XXX ugh bletch !error branch */ + error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE); + if (error) { + vrele(*ap->a_vpp); + *ap->a_vpp = NULL; + } + } if (error) { vput(uvp); } else { diff --git a/sys/fs/v7fs/v7fs_vfsops.c b/sys/fs/v7fs/v7fs_vfsops.c index 227ec1c..1bc82a9 100644 --- a/sys/fs/v7fs/v7fs_vfsops.c +++ b/sys/fs/v7fs/v7fs_vfsops.c @@ -325,13 +325,13 @@ v7fs_unmount(struct mount *mp, int mntflags) } int -v7fs_root(struct mount *mp, struct vnode **vpp) +v7fs_root(struct mount *mp, int flags, struct vnode **vpp) { struct vnode *vp; int error; DPRINTF("\n"); - if ((error = VFS_VGET(mp, V7FS_ROOT_INODE, &vp)) != 0) { + if ((error = VFS_VGET(mp, V7FS_ROOT_INODE, flags, &vp)) != 0) { DPRINTF("error=%d\n", error); return error; } @@ -384,6 +384,7 @@ v7fs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) for (retry_cnt = 0; retry_cnt < 2; retry_cnt++) { error = 0; + /* XXX Should use vnode_iterator(9) here. */ mutex_enter(&mntvnode_lock); for (v7fs_node = LIST_FIRST(&v7fsmount->v7fs_node_head); v7fs_node != NULL; v7fs_node = LIST_NEXT(v7fs_node, link)) { @@ -424,7 +425,7 @@ v7fs_mode_to_vtype (v7fs_mode_t mode) } int -v7fs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) +v7fs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { struct v7fs_mount *v7fsmount = mp->mnt_data; struct v7fs_self *fs = v7fsmount->core; @@ -448,6 +449,7 @@ retry: mutex_enter(vp->v_interlock); mutex_exit(&mntvnode_lock); if (vget(vp, LK_EXCLUSIVE) == 0) { + VOP_UNLOCK(vp); *vpp = vp; return 0; } else { @@ -498,6 +500,7 @@ retry: } vready(vp); + VOP_UNLOCK(vp); *vpp = vp; return 0; @@ -505,7 +508,7 @@ retry: int -v7fs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp) +v7fs_fhtovp(struct mount *mp, struct fid *fid, int flags, struct vnode **vpp) { DPRINTF("\n"); diff --git a/sys/fs/v7fs/v7fs_vnops.c b/sys/fs/v7fs/v7fs_vnops.c index caef709..6809eb2 100644 --- a/sys/fs/v7fs/v7fs_vnops.c +++ b/sys/fs/v7fs/v7fs_vnops.c @@ -172,8 +172,20 @@ v7fs_lookup(void *v) VOP_UNLOCK(dvp); /* preserve reference count. (not vput) */ } DPRINTF("enter vget\n"); - if ((error = v7fs_vget(dvp->v_mount, ino, &vpp))) { + if ((error = v7fs_vget(dvp->v_mount, ino, 0, &vpp))) { DPRINTF("***can't get vnode.\n"); + if (isdotdot) { + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + } + return error; + } + /* XXX Omit needless lock/unlock. */ + if ((error = vn_lock(vpp, LK_EXCLUSIVE))) { + DPRINTF("***can't lock vnode.\n"); + vrele(vpp); + if (isdotdot) { + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + } return error; } DPRINTF("exit vget\n"); @@ -228,10 +240,16 @@ v7fs_create(void *v) /* Get myself vnode. */ *a->a_vpp = 0; - if ((error = v7fs_vget(mp, ino, a->a_vpp))) { + if ((error = v7fs_vget(mp, ino, 0, a->a_vpp))) { DPRINTF("v7fs_vget failed.\n"); return error; } + if ((error = vn_lock(*a->a_vpp, LK_EXCLUSIVE))) { + vrele(*a->a_vpp); + *a->a_vpp = NULL; + DPRINTF("vn_lock failed.\n"); + return error; + } /* Scheduling update time. real update by v7fs_update */ struct v7fs_node *newnode = (*a->a_vpp)->v_data; @@ -282,10 +300,16 @@ v7fs_mknod(void *v) /* Sync dirent size change. */ uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); - if ((error = v7fs_vget(mp, ino, a->a_vpp))) { + if ((error = v7fs_vget(mp, ino, 0, a->a_vpp))) { DPRINTF("can't get vnode.\n"); return error; } + if ((error = vn_lock(*a->a_vpp, LK_EXCLUSIVE))) { + vrele(*a->a_vpp); + *a->a_vpp = NULL; + DPRINTF("can't lock vnode.\n"); + return error; + } struct v7fs_node *newnode = (*a->a_vpp)->v_data; newnode->update_ctime = true; newnode->update_mtime = true; @@ -841,8 +865,15 @@ v7fs_mkdir(void *v) /* Sync dirent size change. */ uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); - if ((error = v7fs_vget(mp, ino, a->a_vpp))) { + if ((error = v7fs_vget(mp, ino, 0, a->a_vpp))) { DPRINTF("can't get vnode.\n"); + return error; + } + if ((error = vn_lock(*a->a_vpp, LK_EXCLUSIVE))) { + vrele(*a->a_vpp); + *a->a_vpp = NULL; + DPRINTF("can't get vnode.\n"); + return error; } struct v7fs_node *newnode = (*a->a_vpp)->v_data; newnode->update_ctime = true; @@ -1274,8 +1305,15 @@ v7fs_symlink(void *v) uvm_vnp_setsize(a->a_dvp, v7fs_inode_filesize(&parent_node->inode)); /* Get myself vnode. */ - if ((error = v7fs_vget(v7fsmount->mountp, ino, a->a_vpp))) { + if ((error = v7fs_vget(v7fsmount->mountp, ino, 0, a->a_vpp))) { DPRINTF("can't get vnode.\n"); + return error; + } + if ((error = vn_lock(*a->a_vpp, LK_EXCLUSIVE))) { + vrele(*a->a_vpp); + *a->a_vpp = NULL; + DPRINTF("can't lock vnode.\n"); + return error; } struct v7fs_node *newnode = (*a->a_vpp)->v_data; diff --git a/sys/kern/tty_bsdpty.c b/sys/kern/tty_bsdpty.c index d8aab62..ad60371 100644 --- a/sys/kern/tty_bsdpty.c +++ b/sys/kern/tty_bsdpty.c @@ -71,8 +71,8 @@ __KERNEL_RCSID(0, "$NetBSD: tty_bsdpty.c,v 1.20 2014/04/04 18:11:58 christos Exp static int pty_makename(struct mount *, struct lwp *, char *, size_t, dev_t, char); -static int pty_allocvp(struct mount *, struct lwp *, struct vnode **, - dev_t, char); +static int pty_allocvp(struct mount *, struct lwp *, int flags, + struct vnode **, dev_t, char); static void pty_getvattr(struct mount *, struct lwp *, struct vattr *); static int pty__getmp(struct lwp *, struct mount **); @@ -115,8 +115,8 @@ pty_makename(struct mount *mp, struct lwp *l, char *bf, static int /*ARGSUSED*/ -pty_allocvp(struct mount *mp, struct lwp *l, struct vnode **vp, dev_t dev, - char ms) +pty_allocvp(struct mount *mp, struct lwp *l, int flags, struct vnode **vp, + dev_t dev, char ms) { int error; struct pathbuf *pb; @@ -137,6 +137,7 @@ pty_allocvp(struct mount *mp, struct lwp *l, struct vnode **vp, dev_t dev, pathbuf_destroy(pb); return error; } + VOP_UNLOCK(nd.ni_vp); *vp = nd.ni_vp; pathbuf_destroy(pb); return 0; diff --git a/sys/kern/tty_ptm.c b/sys/kern/tty_ptm.c index cc3279d..5684eaf 100644 --- a/sys/kern/tty_ptm.c +++ b/sys/kern/tty_ptm.c @@ -189,10 +189,15 @@ retry: * You can test this by changing a_recycle from true to false * in ptyfs_inactive. */ - if ((error = (*ptm->allocvp)(mp, l, &vp, *dev, 'p')) != 0) { + if ((error = (*ptm->allocvp)(mp, l, 0, &vp, *dev, 'p')) != 0) { DPRINTF(("pty_allocvp %d\n", error)); goto bad; } + if ((error = vn_lock(vp, LK_EXCLUSIVE)) != 0) { + vrele(vp); + DPRINTF(("pty_allocvp lock %d\n", error)); + goto bad; + } if ((error = pty_vn_open(vp, l)) != 0) { DPRINTF(("pty_vn_open %d\n", error)); @@ -238,8 +243,12 @@ pty_grant_slave(struct lwp *l, dev_t dev, struct mount *mp) */ if (ptm == NULL) return EOPNOTSUPP; - if ((error = (*ptm->allocvp)(mp, l, &vp, dev, 't')) != 0) + if ((error = (*ptm->allocvp)(mp, l, 0, &vp, dev, 't')) != 0) + return error; + if ((error = vn_lock(vp, LK_EXCLUSIVE)) != 0) { + vrele(vp); return error; + } if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { struct vattr vattr; @@ -281,8 +290,12 @@ pty_alloc_slave(struct lwp *l, int *fd, dev_t dev, struct mount *mp) goto bad; } - if ((error = (*ptm->allocvp)(mp, l, &vp, dev, 't')) != 0) + if ((error = (*ptm->allocvp)(mp, l, 0, &vp, dev, 't')) != 0) + goto bad; + if ((error = vn_lock(vp, LK_EXCLUSIVE)) != 0) { + vrele(vp); goto bad; + } if ((error = pty_vn_open(vp, l)) != 0) goto bad; diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 0958900..e886dc1 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -1089,12 +1089,21 @@ unionlookup: VOP_UNLOCK(searchdir); } vput(foundobj); - error = VFS_ROOT(mp, &foundobj); - vfs_unbusy(mp, false, NULL); + error = VFS_ROOT(mp, 0, &foundobj); if (error) { + vfs_unbusy(mp, false, NULL); vn_lock(searchdir, LK_EXCLUSIVE | LK_RETRY); goto done; } + error = vn_lock(foundobj, LK_EXCLUSIVE); + if (error) { + vrele(foundobj); + foundobj = NULL; + vfs_unbusy(mp, false, NULL); + vn_lock(searchdir, LK_EXCLUSIVE | LK_RETRY); + goto done; + } + vfs_unbusy(mp, false, NULL); /* * avoid locking vnodes from two filesystems because it's * prune to deadlock. eg. when using puffs. diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 0b285bb..8abaa0b 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -563,7 +563,8 @@ mount_checkdirs(vnode_t *olddp) if (olddp->v_usecount == 1) { return; } - if (VFS_ROOT(olddp->v_mountedhere, &newdp)) + if (VFS_ROOT(olddp->v_mountedhere, 0, &newdp) || + vn_lock(newdp, LK_EXCLUSIVE)) panic("mount: lost mount"); do { @@ -1150,9 +1151,12 @@ done: * Get the vnode for '/'. Set cwdi0.cwdi_cdir to * reference it. */ - error = VFS_ROOT(mp, &rootvnode); + error = VFS_ROOT(mp, 0, &rootvnode); if (error) panic("cannot find root vnode, error=%d", error); + error = vn_lock(rootvnode, LK_EXCLUSIVE); + if (error) + panic("cannot lock root vnode, error=%d", error); cwdi0.cwdi_cdir = rootvnode; vref(cwdi0.cwdi_cdir); VOP_UNLOCK(rootvnode); diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 04a88bc..ff9a916 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -947,14 +947,14 @@ VFS_UNMOUNT(struct mount *mp, int a) } int -VFS_ROOT(struct mount *mp, struct vnode **a) +VFS_ROOT(struct mount *mp, int flags, struct vnode **a) { int error; if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { KERNEL_LOCK(1, NULL); } - error = (*(mp->mnt_op->vfs_root))(mp, a); + error = (*(mp->mnt_op->vfs_root))(mp, flags, a); if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { KERNEL_UNLOCK_ONE(NULL); } @@ -1011,14 +1011,14 @@ VFS_SYNC(struct mount *mp, int a, struct kauth_cred *b) } int -VFS_FHTOVP(struct mount *mp, struct fid *a, struct vnode **b) +VFS_FHTOVP(struct mount *mp, struct fid *a, int flags, struct vnode **b) { int error; if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { KERNEL_LOCK(1, NULL); } - error = (*(mp->mnt_op->vfs_fhtovp))(mp, a, b); + error = (*(mp->mnt_op->vfs_fhtovp))(mp, a, flags, b); if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { KERNEL_UNLOCK_ONE(NULL); } diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 1dd02c0..0efc37c 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1335,10 +1335,19 @@ sys_fchdir(struct lwp *l, const struct sys_fchdir_args *uap, register_t *retval) vput(vp); if (error != 0) goto out; - error = VFS_ROOT(mp, &tdp); - vfs_unbusy(mp, false, NULL); - if (error) + error = VFS_ROOT(mp, 0, &tdp); + if (error) { + vfs_unbusy(mp, false, NULL); + goto out; + } + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + tdp = NULL; + vfs_unbusy(mp, false, NULL); goto out; + } + vfs_unbusy(mp, false, NULL); vp = tdp; } VOP_UNLOCK(vp); @@ -1789,7 +1798,7 @@ vfs_composefh_free(fhandle_t *fhp) */ int -vfs_fhtovp(fhandle_t *fhp, struct vnode **vpp) +vfs_fhtovp(fhandle_t *fhp, int flags, struct vnode **vpp) { struct mount *mp; int error; @@ -1804,7 +1813,7 @@ vfs_fhtovp(fhandle_t *fhp, struct vnode **vpp) error = EOPNOTSUPP; goto out; } - error = VFS_FHTOVP(mp, FHANDLE_FILEID(fhp), vpp); + error = VFS_FHTOVP(mp, FHANDLE_FILEID(fhp), flags, vpp); out: return error; } @@ -1976,10 +1985,16 @@ dofhopen(struct lwp *l, const void *ufhp, size_t fhsize, int oflags, if (error != 0) { goto bad; } - error = vfs_fhtovp(fh, &vp); + error = vfs_fhtovp(fh, 0, &vp); if (error != 0) { goto bad; } + error = vn_lock(vp, LK_EXCLUSIVE); + if (error != 0) { + vrele(vp); + vp = NULL; + goto bad; + } /* Now do an effective vn_open */ @@ -2056,10 +2071,15 @@ do_fhstat(struct lwp *l, const void *ufhp, size_t fhsize, struct stat *sb) if (error != 0) return error; - error = vfs_fhtovp(fh, &vp); + error = vfs_fhtovp(fh, 0, &vp); vfs_copyinfh_free(fh); if (error != 0) return error; + error = vn_lock(vp, LK_EXCLUSIVE); + if (error != 0) { + vrele(vp); + return error; + } error = vn_stat(vp, sb); vput(vp); @@ -2105,10 +2125,15 @@ do_fhstatvfs(struct lwp *l, const void *ufhp, size_t fhsize, struct statvfs *sb, if (error != 0) return error; - error = vfs_fhtovp(fh, &vp); + error = vfs_fhtovp(fh, 0, &vp); vfs_copyinfh_free(fh); if (error != 0) return error; + error = vn_lock(vp, LK_EXCLUSIVE); + if (error != 0) { + vrele(vp); + return error; + } mp = vp->v_mount; error = dostatvfs(mp, sb, l, flags, 1); diff --git a/sys/miscfs/fdesc/fdesc.h b/sys/miscfs/fdesc/fdesc.h index 37793d9..c492a6e 100644 --- a/sys/miscfs/fdesc/fdesc.h +++ b/sys/miscfs/fdesc/fdesc.h @@ -71,7 +71,7 @@ struct fdescnode { extern dev_t devctty; extern void fdesc_init(void); extern void fdesc_done(void); -extern int fdesc_root(struct mount *, struct vnode **); +extern int fdesc_root(struct mount *, int, struct vnode **); extern int fdesc_allocvp(fdntype, int, struct mount *, struct vnode **); extern int (**fdesc_vnodeop_p)(void *); extern struct vfsops fdesc_vfsops; diff --git a/sys/miscfs/fdesc/fdesc_vfsops.c b/sys/miscfs/fdesc/fdesc_vfsops.c index 9145644..8c1432e 100644 --- a/sys/miscfs/fdesc/fdesc_vfsops.c +++ b/sys/miscfs/fdesc/fdesc_vfsops.c @@ -139,16 +139,17 @@ fdesc_unmount(struct mount *mp, int mntflags) } int -fdesc_root(struct mount *mp, struct vnode **vpp) +fdesc_root(struct mount *mp, int flags, struct vnode **vpp) { struct vnode *vp; /* - * Return locked reference to root. + * Return reference to root. */ vp = mp->mnt_data; vref(vp); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + VOP_UNLOCK(vp); *vpp = vp; return (0); } @@ -167,7 +168,7 @@ fdesc_sync(struct mount *mp, int waitfor, * Currently unsupported. */ int -fdesc_vget(struct mount *mp, ino_t ino, +fdesc_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { diff --git a/sys/miscfs/fdesc/fdesc_vnops.c b/sys/miscfs/fdesc/fdesc_vnops.c index dbccde0..6f46322 100644 --- a/sys/miscfs/fdesc/fdesc_vnops.c +++ b/sys/miscfs/fdesc/fdesc_vnops.c @@ -361,7 +361,19 @@ fdesc_lookup(void *v) case Fdevfd: if (cnp->cn_namelen == 2 && memcmp(pname, "..", 2) == 0) { VOP_UNLOCK(dvp); - error = fdesc_root(dvp->v_mount, vpp); + error = fdesc_root(dvp->v_mount, 0, vpp); + if (error) { + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + goto bad; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + goto bad; + } vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); if (error) goto bad; diff --git a/sys/miscfs/genfs/layer_extern.h b/sys/miscfs/genfs/layer_extern.h index 2f9698e..ab8da79 100644 --- a/sys/miscfs/genfs/layer_extern.h +++ b/sys/miscfs/genfs/layer_extern.h @@ -87,12 +87,12 @@ struct vnode *layer_node_find(struct mount *, struct vnode *); /* VFS routines */ int layerfs_start(struct mount *, int); -int layerfs_root(struct mount *, struct vnode **); +int layerfs_root(struct mount *, int, struct vnode **); int layerfs_quotactl(struct mount *, struct quotactl_args *); int layerfs_statvfs(struct mount *, struct statvfs *); int layerfs_sync(struct mount *, int, struct kauth_cred *); -int layerfs_vget(struct mount *, ino_t, struct vnode **); -int layerfs_fhtovp(struct mount *, struct fid *, struct vnode **); +int layerfs_vget(struct mount *, ino_t, int, struct vnode **); +int layerfs_fhtovp(struct mount *, struct fid *, int, struct vnode **); int layerfs_vptofh(struct vnode *, struct fid *, size_t *); int layerfs_snapshot(struct mount *, struct vnode *, struct timespec *); int layerfs_renamelock_enter(struct mount *); diff --git a/sys/miscfs/genfs/layer_vfsops.c b/sys/miscfs/genfs/layer_vfsops.c index 415309a..b0b83dd 100644 --- a/sys/miscfs/genfs/layer_vfsops.c +++ b/sys/miscfs/genfs/layer_vfsops.c @@ -133,7 +133,7 @@ layerfs_start(struct mount *mp, int flags) } int -layerfs_root(struct mount *mp, struct vnode **vpp) +layerfs_root(struct mount *mp, int flags, struct vnode **vpp) { struct vnode *vp; @@ -143,10 +143,11 @@ layerfs_root(struct mount *mp, struct vnode **vpp) return EINVAL; } /* - * Return root vnode with locked and with a reference held. + * Return root vnode with a reference held. */ vref(vp); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + VOP_UNLOCK(vp); *vpp = vp; return 0; } @@ -204,13 +205,20 @@ layerfs_sync(struct mount *mp, int waitfor, } int -layerfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) +layerfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { struct vnode *vp; int error; - error = VFS_VGET(MOUNTTOLAYERMOUNT(mp)->layerm_vfs, ino, &vp); + error = VFS_VGET(MOUNTTOLAYERMOUNT(mp)->layerm_vfs, ino, flags, &vp); + if (error) { + *vpp = NULL; + return error; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(vp, LK_EXCLUSIVE); if (error) { + vrele(*vpp); *vpp = NULL; return error; } @@ -221,39 +229,54 @@ layerfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) *vpp = NULL; return error; } + /* XXX Omit needless lock/unlock. */ error = vn_lock(*vpp, LK_EXCLUSIVE); if (error) { vrele(*vpp); *vpp = NULL; return error; } + VOP_UNLOCK(*vpp); return 0; } int -layerfs_fhtovp(struct mount *mp, struct fid *fidp, struct vnode **vpp) +layerfs_fhtovp(struct mount *mp, struct fid *fidp, int flags, + struct vnode **vpp) { struct vnode *vp; int error; - error = VFS_FHTOVP(MOUNTTOLAYERMOUNT(mp)->layerm_vfs, fidp, &vp); + error = VFS_FHTOVP(MOUNTTOLAYERMOUNT(mp)->layerm_vfs, fidp, flags, + &vp); if (error) { *vpp = NULL; return error; } + /* XXX Omit needless unlock. */ + error = vn_lock(vp, LK_EXCLUSIVE); + if (error) { + vrele(vp); + *vpp = NULL; + return error; + } VOP_UNLOCK(vp); error = layer_node_create(mp, vp, vpp); if (error) { + /* XXX I think this should be vrele, not vput. */ vput(vp); *vpp = NULL; return (error); } + /* XXX Omit needless unlock. */ error = vn_lock(*vpp, LK_EXCLUSIVE); if (error) { vrele(*vpp); + vrele(vp); *vpp = NULL; return error; } + VOP_UNLOCK(*vpp); return 0; } diff --git a/sys/miscfs/kernfs/kernfs.h b/sys/miscfs/kernfs/kernfs.h index 9e856ac..d2b5f51 100644 --- a/sys/miscfs/kernfs/kernfs.h +++ b/sys/miscfs/kernfs/kernfs.h @@ -127,13 +127,13 @@ extern dev_t rrootdev; struct secasvar; struct secpolicy; -int kernfs_root(struct mount *, struct vnode **); +int kernfs_root(struct mount *, int, struct vnode **); void kernfs_hashinit(void); void kernfs_hashreinit(void); void kernfs_hashdone(void); int kernfs_freevp(struct vnode *); -int kernfs_allocvp(struct mount *, struct vnode **, kfstype, +int kernfs_allocvp(struct mount *, int, struct vnode **, kfstype, const struct kern_target *, u_int32_t); void kernfs_revoke_sa(struct secasvar *); diff --git a/sys/miscfs/kernfs/kernfs_subr.c b/sys/miscfs/kernfs/kernfs_subr.c index f998243..9822735 100644 --- a/sys/miscfs/kernfs/kernfs_subr.c +++ b/sys/miscfs/kernfs/kernfs_subr.c @@ -130,18 +130,21 @@ static kmutex_t kfs_ihash_lock; * the vnode free list. */ int -kernfs_allocvp(struct mount *mp, struct vnode **vpp, kfstype kfs_type, - const struct kern_target *kt, u_int32_t value) +kernfs_allocvp(struct mount *mp, int flags, struct vnode **vpp, + kfstype kfs_type, const struct kern_target *kt, u_int32_t value) { struct kernfs_node *kfs = NULL, *kfsp; struct vnode *vp = NULL; int error; long *cookie; - if ((*vpp = kernfs_hashget(kfs_type, mp, kt, value)) != NULL) + if ((*vpp = kernfs_hashget(kfs_type, mp, kt, value)) != NULL) { + VOP_UNLOCK(*vpp); return (0); + } mutex_enter(&kfs_hashlock); + /* XXX Can't vget under kfs_hashlock. */ if ((*vpp = kernfs_hashget(kfs_type, mp, kt, value)) != NULL) { mutex_exit(&kfs_hashlock); return (0); @@ -164,10 +167,12 @@ kernfs_allocvp(struct mount *mp, struct vnode **vpp, kfstype kfs_type, return (ENOENT); } vp = fvp; + /* XXX Omit needless lock/unlock. */ if (vn_lock(fvp, LK_EXCLUSIVE)) { vrele(fvp); goto loop; } + VOP_UNLOCK(vp); *vpp = vp; mutex_exit(&kfs_hashlock); return (0); @@ -229,6 +234,7 @@ again: mutex_exit(&kfs_hashlock); vready(vp); + VOP_UNLOCK(vp); *vpp = vp; return (0); } diff --git a/sys/miscfs/kernfs/kernfs_vfsops.c b/sys/miscfs/kernfs/kernfs_vfsops.c index 4529e89..524ec4b 100644 --- a/sys/miscfs/kernfs/kernfs_vfsops.c +++ b/sys/miscfs/kernfs/kernfs_vfsops.c @@ -188,11 +188,11 @@ kernfs_unmount(struct mount *mp, int mntflags) } int -kernfs_root(struct mount *mp, struct vnode **vpp) +kernfs_root(struct mount *mp, int flags, struct vnode **vpp) { /* setup "." */ - return (kernfs_allocvp(mp, vpp, KFSkern, &kern_targets[0], 0)); + return (kernfs_allocvp(mp, flags, vpp, KFSkern, &kern_targets[0], 0)); } /*ARGSUSED*/ @@ -209,7 +209,7 @@ kernfs_sync(struct mount *mp, int waitfor, * Currently unsupported. */ int -kernfs_vget(struct mount *mp, ino_t ino, +kernfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { diff --git a/sys/miscfs/kernfs/kernfs_vnops.c b/sys/miscfs/kernfs/kernfs_vnops.c index 7e77770..8c8c6c7 100644 --- a/sys/miscfs/kernfs/kernfs_vnops.c +++ b/sys/miscfs/kernfs/kernfs_vnops.c @@ -519,9 +519,17 @@ kernfs_lookup(void *v) break; found: - error = kernfs_allocvp(dvp->v_mount, vpp, kt->kt_tag, kt, 0); + error = kernfs_allocvp(dvp->v_mount, 0, vpp, kt->kt_tag, kt, + 0); if (error) return error; + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + return error; + } VOP_UNLOCK(*vpp); return 0; @@ -829,9 +837,13 @@ kernfs_setdirentfileno_kt(struct dirent *d, const struct kern_target *kt, struct vnode *vp; int error; - if ((error = kernfs_allocvp(ap->a_vp->v_mount, &vp, kt->kt_tag, kt, + if ((error = kernfs_allocvp(ap->a_vp->v_mount, 0, &vp, kt->kt_tag, kt, value)) != 0) return error; + if ((error = vn_lock(vp, LK_EXCLUSIVE)) != 0) { + vrele(vp); + return error; + } if (kt->kt_tag == KFSdevice) { struct vattr va; diff --git a/sys/miscfs/procfs/procfs.h b/sys/miscfs/procfs/procfs.h index 170368f..1341750 100644 --- a/sys/miscfs/procfs/procfs.h +++ b/sys/miscfs/procfs/procfs.h @@ -253,7 +253,7 @@ int procfs_getcpuinfstr(char *, int *); extern int (**procfs_vnodeop_p)(void *); extern struct vfsops procfs_vfsops; -int procfs_root(struct mount *, struct vnode **); +int procfs_root(struct mount *, int, struct vnode **); #ifdef __HAVE_PROCFS_MACHDEP struct vattr; diff --git a/sys/miscfs/procfs/procfs_vfsops.c b/sys/miscfs/procfs/procfs_vfsops.c index 664f633..b32d9e8 100644 --- a/sys/miscfs/procfs/procfs_vfsops.c +++ b/sys/miscfs/procfs/procfs_vfsops.c @@ -197,17 +197,19 @@ procfs_unmount(struct mount *mp, int mntflags) } int -procfs_root(struct mount *mp, struct vnode **vpp) +procfs_root(struct mount *mp, int flags, struct vnode **vpp) { int error; error = procfs_allocvp(mp, vpp, 0, PFSroot, -1, NULL); if (error == 0) { + /* XXX Omit needless lock/unlock. */ error = vn_lock(*vpp, LK_EXCLUSIVE); if (error != 0) { vrele(*vpp); *vpp = NULL; } + VOP_UNLOCK(*vpp); } return error; @@ -254,7 +256,7 @@ procfs_sync( /*ARGSUSED*/ int -procfs_vget(struct mount *mp, ino_t ino, +procfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { return (EOPNOTSUPP); diff --git a/sys/nfs/nfs_export.c b/sys/nfs/nfs_export.c index 0e92306..72c08a4 100644 --- a/sys/nfs/nfs_export.c +++ b/sys/nfs/nfs_export.c @@ -764,8 +764,12 @@ setpublicfs(struct mount *mp, struct netexport *nep, /* * Get real filehandle for root of exported FS. */ - if ((error = VFS_ROOT(mp, &rvp))) + if ((error = VFS_ROOT(mp, 0, &rvp))) return error; + if ((error = vn_lock(rvp, LK_EXCLUSIVE))) { + vrele(rvp); + return error; + } fhsize = 0; error = vfs_composefh(rvp, NULL, &fhsize); diff --git a/sys/nfs/nfs_node.c b/sys/nfs/nfs_node.c index a600eb6..cf3f610 100644 --- a/sys/nfs/nfs_node.c +++ b/sys/nfs/nfs_node.c @@ -157,8 +157,8 @@ nfs_rbtinit(struct nfsmount *nmp) * nfsnode structure is returned. */ int -nfs_nget1(struct mount *mntp, nfsfh_t *fhp, int fhsize, struct nfsnode **npp, - int lkflags) +nfs_nget1(struct mount *mntp, nfsfh_t *fhp, int fhsize, int flags, + struct nfsnode **npp, int lkflags) { struct nfsnode *np; struct vnode *vp; @@ -181,6 +181,7 @@ loop: return error; if (error) goto loop; + VOP_UNLOCK(vp); *npp = np; return(0); } @@ -237,6 +238,7 @@ loop: rw_exit(&nmp->nm_rbtlock); vready(vp); + VOP_UNLOCK(vp); *npp = np; return (0); } diff --git a/sys/nfs/nfs_serv.c b/sys/nfs/nfs_serv.c index 8e1fe34..b28f00b 100644 --- a/sys/nfs/nfs_serv.c +++ b/sys/nfs/nfs_serv.c @@ -3039,11 +3039,11 @@ again: * even be here otherwise. */ if (!getret) { - if ((getret = VFS_VGET(vp->v_mount, at.va_fileid, &nvp))) + if ((getret = VFS_VGET(vp->v_mount, at.va_fileid, 0, &nvp))) getret = (getret == EOPNOTSUPP) ? NFSERR_NOTSUPP : NFSERR_IO; else - vput(nvp); + vrele(nvp); } if (!cookies && !error) @@ -3127,8 +3127,12 @@ 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, 0, &nvp)) + goto invalid; + if (vn_lock(nvp, LK_EXCLUSIVE)) { + vrele(nvp); goto invalid; + } if (nfsrv_composefh(nvp, &nnsfh, true)) { vput(nvp); goto invalid; diff --git a/sys/nfs/nfs_srvsubs.c b/sys/nfs/nfs_srvsubs.c index 60b0830..e405329 100644 --- a/sys/nfs/nfs_srvsubs.c +++ b/sys/nfs/nfs_srvsubs.c @@ -311,9 +311,15 @@ nfsrv_fhtovp(nfsrvfh_t *nsfh, int lockflag, struct vnode **vpp, return error; } - error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); + error = VFS_FHTOVP(mp, &fhp->fh_fid, 0, vpp); if (error) return (error); + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + return (error); + } if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { saddr = mtod(nam, struct sockaddr_in *); diff --git a/sys/nfs/nfs_var.h b/sys/nfs/nfs_var.h index 33724a6..54ca20c 100644 --- a/sys/nfs/nfs_var.h +++ b/sys/nfs/nfs_var.h @@ -84,9 +84,9 @@ void nfs_rbtinit(struct nfsmount *); void nfs_node_init(void); void nfs_node_done(void); -int nfs_nget1(struct mount *, nfsfh_t *, int, struct nfsnode **, int); -#define nfs_nget(mp, fhp, fhsize, npp) \ - nfs_nget1((mp), (fhp), (fhsize), (npp), 0) +int nfs_nget1(struct mount *, nfsfh_t *, int, int, struct nfsnode **, int); +#define nfs_nget(mp, fhp, fhsize, flags, npp) \ + nfs_nget1((mp), (fhp), (fhsize), (flags), (npp), 0) /* nfs_vnops.c */ int nfs_null(struct vnode *, kauth_cred_t, struct lwp *); diff --git a/sys/nfs/nfs_vfsops.c b/sys/nfs/nfs_vfsops.c index b0f1b3f..62661ba 100644 --- a/sys/nfs/nfs_vfsops.c +++ b/sys/nfs/nfs_vfsops.c @@ -782,10 +782,15 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct mbuf *nam, const char * * point. */ mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA; - error = nfs_nget(mp, (nfsfh_t *)argp->fh, argp->fhsize, &np); + error = nfs_nget(mp, (nfsfh_t *)argp->fh, argp->fhsize, 0, &np); if (error) goto bad; vp = NFSTOV(np); + error = vn_lock(vp, LK_EXCLUSIVE); + if (error) { + vrele(vp); + goto bad; + } attrs = malloc(sizeof(struct vattr), M_TEMP, M_WAITOK); VOP_GETATTR(vp, attrs, l->l_cred); if ((nmp->nm_flag & NFSMNT_NFSV3) && (vp->v_type == VDIR)) { @@ -915,7 +920,7 @@ nfs_unmount(struct mount *mp, int mntflags) * Return root of a filesystem */ int -nfs_root(struct mount *mp, struct vnode **vpp) +nfs_root(struct mount *mp, int flags, struct vnode **vpp) { struct vnode *vp; struct nfsmount *nmp; @@ -929,6 +934,8 @@ nfs_root(struct mount *mp, struct vnode **vpp) vrele(vp); return error; } + /* XXX Omit needless lock/unlock. */ + VOP_UNLOCK(vp); *vpp = vp; return (0); } @@ -977,7 +984,7 @@ nfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) */ /* ARGSUSED */ int -nfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) +nfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { return (EOPNOTSUPP); @@ -1042,7 +1049,7 @@ nfs_sysctl_fini(void) /* ARGSUSED */ int -nfs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp) +nfs_fhtovp(struct mount *mp, struct fid *fid, int flags, struct vnode **vpp) { size_t fidsize; size_t fhsize; @@ -1067,16 +1074,27 @@ nfs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp) return EINVAL; } } - error = nfs_nget(mp, (void *)fid->fid_data, fhsize, &np); + error = nfs_nget(mp, (void *)fid->fid_data, fhsize, flags, &np); if (error) { return error; } + /* + * XXX Can we avoid having to take the lock by pushing the + * getattr into nfs_nget before vready? + */ + error = vn_lock(NFSTOV(np), LK_EXCLUSIVE); + if (error) { + vrele(NFSTOV(np)); + return error; + } *vpp = NFSTOV(np); error = VOP_GETATTR(*vpp, &va, kauth_cred_get()); if (error != 0) { vput(*vpp); *vpp = NULLVP; + return error; } + VOP_UNLOCK(*vpp); return error; } diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c index 99abea3..7315961 100644 --- a/sys/nfs/nfs_vnops.c +++ b/sys/nfs/nfs_vnops.c @@ -922,11 +922,18 @@ dorpc: m_freem(mrep); return (EISDIR); } - error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); + error = nfs_nget(dvp->v_mount, fhp, fhsize, 0, &np); if (error) { m_freem(mrep); return error; } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(NFSTOV(np), LK_EXCLUSIVE); + if (error) { + vrele(NFSTOV(np)); + m_freem(mrep); + return error; + } newvp = NFSTOV(np); #ifndef NFS_V2_ONLY if (v3) { @@ -965,12 +972,21 @@ dorpc: * ".." lookup */ VOP_UNLOCK(dvp); - error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + error = nfs_nget(dvp->v_mount, fhp, fhsize, 0, &np); + if (error) { + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + m_freem(mrep); + return error; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(NFSTOV(np), LK_EXCLUSIVE); if (error) { + vrele(NFSTOV(np)); + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); m_freem(mrep); return error; } + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); newvp = NFSTOV(np); #ifndef NFS_V2_ONLY @@ -984,12 +1000,19 @@ dorpc: /* * Other lookups. */ - error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); + error = nfs_nget(dvp->v_mount, fhp, fhsize, 0, &np); if (error) { m_freem(mrep); return error; } newvp = NFSTOV(np); + /* XXX Omit needless lock/unlock. */ + error = vn_lock(newvp, LK_EXCLUSIVE); + if (error) { + vrele(newvp); + m_freem(mrep); + return error; + } #ifndef NFS_V2_ONLY if (v3) { nfsm_postop_attr(newvp, attrflag, 0); @@ -2775,9 +2798,16 @@ nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop, kauth_cred_t cred) np = dnp; } else { error = nfs_nget1(vp->v_mount, fhp, - fhsize, &np, LK_NOWAIT); - if (!error) + fhsize, 0, &np, LK_NOWAIT); + if (!error) { newvp = NFSTOV(np); + /* XXX Lock necessary? */ + error = vn_lock(newvp, LK_EXCLUSIVE); + if (error) { + vrele(newvp); + newvp = NULL; + } + } } if (!error) { nfs_loadattrcache(&newvp, &fattr, 0, 0); @@ -2977,12 +3007,19 @@ nfs_lookitup(struct vnode *dvp, const char *name, int len, kauth_cred_t cred, st newvp = dvp; np = dnp; } else { - error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np); + error = nfs_nget(dvp->v_mount, nfhp, fhlen, 0, &np); if (error) { m_freem(mrep); return (error); } newvp = NFSTOV(np); + /* XXX Omit needless lock/unlock. */ + error = vn_lock(newvp, LK_EXCLUSIVE); + if (error) { + vrele(newvp); + m_freem(mrep); + return (error); + } } #ifndef NFS_V2_ONLY if (v3) { diff --git a/sys/nfs/nfsm_subs.h b/sys/nfs/nfsm_subs.h index b10b9e2..db63815 100644 --- a/sys/nfs/nfsm_subs.h +++ b/sys/nfs/nfsm_subs.h @@ -163,7 +163,13 @@ if (f) { \ nfsm_getfh(ttfhp, ttfhsize, (v3)); \ if ((t1 = nfs_nget((d)->v_mount, ttfhp, ttfhsize, \ - &ttnp)) != 0) { \ + 0, &ttnp)) != 0) { \ + error = t1; \ + m_freem(mrep); \ + goto nfsmout; \ + } \ + if ((t1 = vn_lock(NFSTOV(ttnp), LK_EXCLUSIVE)) != 0) {\ + vrele(NFSTOV(ttnp)); \ error = t1; \ m_freem(mrep); \ goto nfsmout; \ diff --git a/sys/rump/librump/rumpvfs/rump_vfs.c b/sys/rump/librump/rumpvfs/rump_vfs.c index f664af0..a53384b 100644 --- a/sys/rump/librump/rumpvfs/rump_vfs.c +++ b/sys/rump/librump/rumpvfs/rump_vfs.c @@ -403,18 +403,10 @@ rump_vfs_unmount(struct mount *mp, int mntflags) } int -rump_vfs_root(struct mount *mp, struct vnode **vpp, int lock) +rump_vfs_root(struct mount *mp, int flags, struct vnode **vpp) { - int rv; - - rv = VFS_ROOT(mp, vpp); - if (rv) - return rv; - if (!lock) - VOP_UNLOCK(*vpp); - - return 0; + return VFS_ROOT(mp, flags, vpp); } int @@ -432,10 +424,11 @@ rump_vfs_sync(struct mount *mp, int wait, kauth_cred_t cred) } int -rump_vfs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp) +rump_vfs_fhtovp(struct mount *mp, struct fid *fid, int flags, + struct vnode **vpp) { - return VFS_FHTOVP(mp, fid, vpp); + return VFS_FHTOVP(mp, fid, flags, vpp); } int diff --git a/sys/rump/librump/rumpvfs/rumpfs.c b/sys/rump/librump/rumpvfs/rumpfs.c index b6caa22..527cc32 100644 --- a/sys/rump/librump/rumpvfs/rumpfs.c +++ b/sys/rump/librump/rumpvfs/rumpfs.c @@ -1812,18 +1812,19 @@ rumpfs_unmount(struct mount *mp, int mntflags) } int -rumpfs_root(struct mount *mp, struct vnode **vpp) +rumpfs_root(struct mount *mp, int flags, struct vnode **vpp) { struct rumpfs_mount *rfsmp = mp->mnt_data; vref(rfsmp->rfsmp_rvp); vn_lock(rfsmp->rfsmp_rvp, LK_EXCLUSIVE | LK_RETRY); + VOP_UNLOCK(rfsmp->rfsmp_rvp); *vpp = rfsmp->rfsmp_rvp; return 0; } int -rumpfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) +rumpfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { return EOPNOTSUPP; diff --git a/sys/rump/librump/rumpvfs/rumpvfs.ifspec b/sys/rump/librump/rumpvfs/rumpvfs.ifspec index 80649e4..60d7f06 100644 --- a/sys/rump/librump/rumpvfs/rumpvfs.ifspec +++ b/sys/rump/librump/rumpvfs/rumpvfs.ifspec @@ -40,10 +40,11 @@ struct componentname *|makecn |u_long, u_long, const char *, size_t, \ struct kauth_cred *, struct lwp * int |vfs_unmount |struct mount *, int -int |vfs_root |struct mount *, struct vnode **, int +int |vfs_root |struct mount *, int, struct vnode ** int |vfs_statvfs |struct mount *, struct statvfs * int |vfs_sync |struct mount *, int, struct kauth_cred * -int |vfs_fhtovp |struct mount *, struct fid *, struct vnode ** +int |vfs_fhtovp |struct mount *, struct fid *, int, \ + struct vnode ** int |vfs_vptofh |struct vnode *, struct fid *, size_t * int |vfs_extattrctl |struct mount *, int, struct vnode *, \ int, const char * diff --git a/sys/sys/mount.h b/sys/sys/mount.h index bb4f2e6..0c55893 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -215,12 +215,12 @@ struct vfsops { size_t *); int (*vfs_start) (struct mount *, int); int (*vfs_unmount) (struct mount *, int); - int (*vfs_root) (struct mount *, struct vnode **); + int (*vfs_root) (struct mount *, int, struct vnode **); int (*vfs_quotactl) (struct mount *, struct quotactl_args *); int (*vfs_statvfs) (struct mount *, struct statvfs *); int (*vfs_sync) (struct mount *, int, struct kauth_cred *); - int (*vfs_vget) (struct mount *, ino_t, struct vnode **); - int (*vfs_fhtovp) (struct mount *, struct fid *, + int (*vfs_vget) (struct mount *, ino_t, int, struct vnode **); + int (*vfs_fhtovp) (struct mount *, struct fid *, int, struct vnode **); int (*vfs_vptofh) (struct vnode *, struct fid *, size_t *); void (*vfs_init) (void); @@ -241,7 +241,7 @@ struct vfsops { }; /* XXX vget is actually file system internal. */ -#define VFS_VGET(MP, INO, VPP) (*(MP)->mnt_op->vfs_vget)(MP, INO, VPP) +#define VFS_VGET(MP, INO, F, VPP) (*(MP)->mnt_op->vfs_vget)(MP, INO, F, VPP) #define VFS_RENAMELOCK_ENTER(MP) (*(MP)->mnt_op->vfs_renamelock_enter)(MP) #define VFS_RENAMELOCK_EXIT(MP) (*(MP)->mnt_op->vfs_renamelock_exit)(MP) @@ -250,11 +250,11 @@ struct vfsops { int VFS_MOUNT(struct mount *, const char *, void *, size_t *); int VFS_START(struct mount *, int); int VFS_UNMOUNT(struct mount *, int); -int VFS_ROOT(struct mount *, struct vnode **); +int VFS_ROOT(struct mount *, int, struct vnode **); int VFS_QUOTACTL(struct mount *, struct quotactl_args *); int VFS_STATVFS(struct mount *, struct statvfs *); int VFS_SYNC(struct mount *, int, struct kauth_cred *); -int VFS_FHTOVP(struct mount *, struct fid *, struct vnode **); +int VFS_FHTOVP(struct mount *, struct fid *, int, struct vnode **); int VFS_VPTOFH(struct vnode *, struct fid *, size_t *); int VFS_SNAPSHOT(struct mount *, struct vnode *, struct timespec *); int VFS_EXTATTRCTL(struct mount *, int, struct vnode *, int, const char *); @@ -276,12 +276,12 @@ int fsname##_mount(struct mount *, const char *, void *, \ size_t *); \ int fsname##_start(struct mount *, int); \ int fsname##_unmount(struct mount *, int); \ -int fsname##_root(struct mount *, struct vnode **); \ +int fsname##_root(struct mount *, int, struct vnode **); \ int fsname##_quotactl(struct mount *, struct quotactl_args *); \ int fsname##_statvfs(struct mount *, struct statvfs *); \ int fsname##_sync(struct mount *, int, struct kauth_cred *); \ -int fsname##_vget(struct mount *, ino_t, struct vnode **); \ -int fsname##_fhtovp(struct mount *, struct fid *, struct vnode **); \ +int fsname##_vget(struct mount *, ino_t, int, struct vnode **); \ +int fsname##_fhtovp(struct mount *, struct fid *, int, struct vnode **); \ int fsname##_vptofh(struct vnode *, struct fid *, size_t *); \ void fsname##_init(void); \ void fsname##_reinit(void); \ @@ -393,7 +393,7 @@ struct mount *vfs_getvfs(fsid_t *); /* return vfs given fsid */ int vfs_composefh(struct vnode *, fhandle_t *, size_t *); int vfs_composefh_alloc(struct vnode *, fhandle_t **); void vfs_composefh_free(fhandle_t *); -int vfs_fhtovp(fhandle_t *, struct vnode **); +int vfs_fhtovp(fhandle_t *, int, struct vnode **); int vfs_mountedon(struct vnode *);/* is a vfs mounted on vp */ int vfs_mountroot(void); void vfs_shutdown(void); /* unmount and sync file systems */ diff --git a/sys/sys/pty.h b/sys/sys/pty.h index 3031eef..c10acaa 100644 --- a/sys/sys/pty.h +++ b/sys/sys/pty.h @@ -49,8 +49,8 @@ int pty_getmp(struct lwp *, struct mount **); * in the case BSDPTY can be NULL, and arg must be NULL. */ struct ptm_pty { - int (*allocvp)(struct mount *, struct lwp *, struct vnode **, dev_t, - char); + int (*allocvp)(struct mount *, struct lwp *, int, struct vnode **, + dev_t, char); int (*makename)(struct mount *, struct lwp *, char *, size_t, dev_t, char); void (*getvattr)(struct mount *, struct lwp *, struct vattr *); int (*getmp)(struct lwp *, struct mount **); diff --git a/sys/ufs/chfs/chfs_vfsops.c b/sys/ufs/chfs/chfs_vfsops.c index 955142c..a5dc713 100644 --- a/sys/ufs/chfs/chfs_vfsops.c +++ b/sys/ufs/chfs/chfs_vfsops.c @@ -70,9 +70,9 @@ MODULE(MODULE_CLASS_VFS, chfs, "flash"); static int chfs_mount(struct mount *, const char *, void *, size_t *); static int chfs_unmount(struct mount *, int); -static int chfs_root(struct mount *, struct vnode **); -static int chfs_vget(struct mount *, ino_t, struct vnode **); -static int chfs_fhtovp(struct mount *, struct fid *, struct vnode **); +static int chfs_root(struct mount *, int, struct vnode **); +static int chfs_vget(struct mount *, ino_t, int, struct vnode **); +static int chfs_fhtovp(struct mount *, struct fid *, int, struct vnode **); static int chfs_vptofh(struct vnode *, struct fid *, size_t *); static int chfs_start(struct mount *, int); static int chfs_statvfs(struct mount *, struct statvfs *); @@ -338,11 +338,18 @@ chfs_mountfs(struct vnode *devvp, struct mount *mp) ump->um_maxfilesize = 1048512 * 1024; /* Allocate the root vnode. */ - err = VFS_VGET(mp, CHFS_ROOTINO, &vp); + err = VFS_VGET(mp, CHFS_ROOTINO, 0, &vp); if (err) { dbg("error: %d while allocating root node\n", err); return err; } + /* XXX Omit needless lock/unlock. */ + err = vn_lock(vp, LK_EXCLUSIVE); + if (err) { + dbg("error: %d while locking root node\n", err); + return err; + } + /* XXX Why vget it only to immediately vput it? */ vput(vp); /* Start GC. */ @@ -428,12 +435,12 @@ chfs_unmount(struct mount *mp, int mntflags) /* --------------------------------------------------------------------- */ static int -chfs_root(struct mount *mp, struct vnode **vpp) +chfs_root(struct mount *mp, int flags, struct vnode **vpp) { struct vnode *vp; int error; - if ((error = VFS_VGET(mp, (ino_t)UFS_ROOTINO, &vp)) != 0) + if ((error = VFS_VGET(mp, (ino_t)UFS_ROOTINO, flags, &vp)) != 0) return error; *vpp = vp; return 0; @@ -444,7 +451,7 @@ chfs_root(struct mount *mp, struct vnode **vpp) extern rb_tree_ops_t frag_rbtree_ops; static int -chfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) +chfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { struct chfs_mount *chmp; struct chfs_inode *ip; @@ -461,12 +468,14 @@ chfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) ump = VFSTOUFS(mp); dev = ump->um_dev; retry: + /* XXX Whisky tango foxtrot? */ if (!vpp) { vpp = kmem_alloc(sizeof(struct vnode*), KM_SLEEP); } /* Get node from inode hash. */ if ((*vpp = chfs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) { + VOP_UNLOCK(*vpp); return 0; } @@ -572,6 +581,7 @@ retry: vready_fail(vp); vput(vp); *vpp = NULL; + /* XXX Holding a lock here is wrong. */ mutex_exit(&chmp->chm_lock_mountfields); return (error); } @@ -585,6 +595,7 @@ retry: vready_fail(vp); vput(vp); *vpp = NULL; + /* XXX Holding a lock here is wrong. */ mutex_exit(&chmp->chm_lock_mountfields); return (error); } @@ -618,6 +629,7 @@ retry: vready_fail(vp); vput(vp); *vpp = NULL; + /* XXX Holding a lock here is wrong. */ mutex_exit(&chmp->chm_lock_mountfields); return (error); } @@ -657,6 +669,7 @@ retry: uvm_vnp_setsize(vp, ip->size); vready(vp); + VOP_UNLOCK(vp); *vpp = vp; return 0; @@ -665,7 +678,7 @@ retry: /* --------------------------------------------------------------------- */ static int -chfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) +chfs_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) { return ENODEV; } diff --git a/sys/ufs/chfs/chfs_vnode.c b/sys/ufs/chfs/chfs_vnode.c index f1c6a56..840114b 100644 --- a/sys/ufs/chfs/chfs_vnode.c +++ b/sys/ufs/chfs/chfs_vnode.c @@ -200,9 +200,14 @@ chfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp, /* number of vnode will be the new maximum */ vno = ++(chmp->chm_max_vno); - error = VFS_VGET(dvp->v_mount, vno, &vp); + error = VFS_VGET(dvp->v_mount, vno, 0, &vp); if (error) return (error); + error = vn_lock(vp, LK_EXCLUSIVE); + if (error) { + vrele(vp); + return error; + } /* setup vnode cache */ mutex_enter(&chmp->chm_lock_vnocache); diff --git a/sys/ufs/chfs/chfs_vnops.c b/sys/ufs/chfs/chfs_vnops.c index 51c2ada..5793658 100644 --- a/sys/ufs/chfs/chfs_vnops.c +++ b/sys/ufs/chfs/chfs_vnops.c @@ -108,7 +108,19 @@ chfs_lookup(void *v) if (cnp->cn_flags & ISDOTDOT) { VOP_UNLOCK(dvp); - error = VFS_VGET(dvp->v_mount, ip->chvc->pvno, vpp); + error = VFS_VGET(dvp->v_mount, ip->chvc->pvno, 0, vpp); + if (error) { + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + goto out; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + goto out; + } vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { vref(dvp); @@ -149,7 +161,16 @@ chfs_lookup(void *v) dbg("vno@allocating new vnode: %llu\n", (unsigned long long)fd->vno); - error = VFS_VGET(dvp->v_mount, fd->vno, vpp); + error = VFS_VGET(dvp->v_mount, fd->vno, 0, vpp); + if (error) + goto out; + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + goto out; + } } } /* Store the result of this lookup in the cache. Avoid this if the @@ -1151,7 +1172,11 @@ chfs_rename(void *v) newparent, tcnp->cn_nameptr, tcnp->cn_namelen); vput(tvp); } - VFS_VGET(tdvp->v_mount, old->ino, &tvp); + /* + * XXX WHISKY TANGO FOXTROT? What is this even supposed to do? + * Hello? Error branches? These things can fail! + */ + VFS_VGET(tdvp->v_mount, old->ino, 0, &tvp); ip = VTOI(tvp); /* link new */ diff --git a/sys/ufs/ext2fs/ext2fs_alloc.c b/sys/ufs/ext2fs/ext2fs_alloc.c index 52a7b05..0b2f595 100644 --- a/sys/ufs/ext2fs/ext2fs_alloc.c +++ b/sys/ufs/ext2fs/ext2fs_alloc.c @@ -185,11 +185,19 @@ ext2fs_valloc(struct vnode *pvp, int mode, kauth_cred_t cred, ino = (ino_t)ext2fs_hashalloc(pip, cg, (long)ipref, mode, ext2fs_nodealloccg); if (ino == 0) goto noinodes; - error = VFS_VGET(pvp->v_mount, ino, vpp); + error = VFS_VGET(pvp->v_mount, ino, 0, vpp); if (error) { ext2fs_vfree(pvp, ino, mode); return (error); } + /* XXX Should use vready instead of the lock for this stuff. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + ext2fs_vfree(pvp, ino, mode); + return (error); + } ip = VTOI(*vpp); if (ip->i_e2fs_mode && ip->i_e2fs_nlink != 0) { printf("mode = 0%o, nlinks %d, inum = %llu, fs = %s\n", diff --git a/sys/ufs/ext2fs/ext2fs_lookup.c b/sys/ufs/ext2fs/ext2fs_lookup.c index 6b1214c..c32f149 100644 --- a/sys/ufs/ext2fs/ext2fs_lookup.c +++ b/sys/ufs/ext2fs/ext2fs_lookup.c @@ -596,11 +596,22 @@ found: } else { if (flags & ISDOTDOT) VOP_UNLOCK(vdp); /* race to get the inode */ - error = VFS_VGET(vdp->v_mount, foundino, &tdp); + error = VFS_VGET(vdp->v_mount, foundino, 0, &tdp); + if (error) { + if (flags & ISDOTDOT) + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + return (error); + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + if (flags & ISDOTDOT) + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + return (error); + } if (flags & ISDOTDOT) vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); - if (error) - return (error); } /* * Write access to directory required to delete files. @@ -654,11 +665,22 @@ found: return (EISDIR); if (flags & ISDOTDOT) VOP_UNLOCK(vdp); /* race to get the inode */ - error = VFS_VGET(vdp->v_mount, foundino, &tdp); + error = VFS_VGET(vdp->v_mount, foundino, 0, &tdp); + if (error) { + if (flags & ISDOTDOT) + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + return (error); + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + if (flags & ISDOTDOT) + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + return (error); + } if (flags & ISDOTDOT) vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); - if (error) - return (error); if (tdp != vdp) VOP_UNLOCK(tdp); *vpp = tdp; @@ -687,19 +709,33 @@ found: pdp = vdp; if (flags & ISDOTDOT) { VOP_UNLOCK(pdp); /* race to get the inode */ - error = VFS_VGET(vdp->v_mount, foundino, &tdp); - vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); + error = VFS_VGET(vdp->v_mount, foundino, 0, &tdp); if (error) { + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); return (error); } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); + return (error); + } + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); *vpp = tdp; } else if (dp->i_number == foundino) { vref(vdp); /* we want ourself, ie "." */ *vpp = vdp; } else { - error = VFS_VGET(vdp->v_mount, foundino, &tdp); + error = VFS_VGET(vdp->v_mount, foundino, 0, &tdp); if (error) return (error); + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + return (error); + } *vpp = tdp; } @@ -1036,6 +1072,8 @@ ext2fs_dirempty(struct inode *ip, ino_t parentino, kauth_cred_t cred) * Check if source directory is in the path of the target directory. * Target is supplied locked, source is unlocked. * The target is always vput before returning. + * + * XXX Vestige of old ext2fs_rename? Can we kill this? */ int ext2fs_checkpath(struct inode *source, struct inode *target, @@ -1082,8 +1120,14 @@ ext2fs_checkpath(struct inode *source, struct inode *target, if (ino == rootino) break; vput(vp); - error = VFS_VGET(vp->v_mount, ino, &vp); + error = VFS_VGET(vp->v_mount, ino, 0, &vp); + if (error != 0) { + vp = NULL; + break; + } + error = vn_lock(vp, LK_EXCLUSIVE); if (error != 0) { + vrele(vp); vp = NULL; break; } diff --git a/sys/ufs/ext2fs/ext2fs_rename.c b/sys/ufs/ext2fs/ext2fs_rename.c index 5d20575..c2bc54b 100644 --- a/sys/ufs/ext2fs/ext2fs_rename.c +++ b/sys/ufs/ext2fs/ext2fs_rename.c @@ -856,10 +856,18 @@ ext2fs_gro_genealogy(struct mount *mp, kauth_cred_t cred, * be recycled, but why can't dotdot_ino be recycled? */ VOP_UNLOCK(vp); - error = VFS_VGET(mp, dotdot_ino, &dvp); - vrele(vp); - if (error) + error = VFS_VGET(mp, dotdot_ino, 0, &dvp); + if (error) { + vrele(vp); + return error; + } + error = vn_lock(dvp, LK_EXCLUSIVE); + if (error) { + vrele(dvp); + vrele(vp); return error; + } + vrele(vp); KASSERT(dvp != NULL); KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); diff --git a/sys/ufs/ext2fs/ext2fs_vfsops.c b/sys/ufs/ext2fs/ext2fs_vfsops.c index 5b4d144..a48f931 100644 --- a/sys/ufs/ext2fs/ext2fs_vfsops.c +++ b/sys/ufs/ext2fs/ext2fs_vfsops.c @@ -947,7 +947,7 @@ ext2fs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) * done by the calling routine. */ int -ext2fs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) +ext2fs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { struct m_ext2fs *fs; struct inode *ip; @@ -961,8 +961,10 @@ ext2fs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) ump = VFSTOUFS(mp); dev = ump->um_dev; retry: - if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) + if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) { + VOP_UNLOCK(*vpp); return (0); + } /* Allocate a new vnode/inode. */ error = getnewvnode(VT_EXT2FS, mp, ext2fs_vnodeop_p, NULL, 0, &vp); @@ -1066,6 +1068,7 @@ retry: } uvm_vnp_setsize(vp, ext2fs_size(ip)); vready(vp); + VOP_UNLOCK(vp); *vpp = vp; return (0); } @@ -1079,7 +1082,7 @@ retry: * - check for an unallocated inode (i_mode == 0) */ int -ext2fs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) +ext2fs_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) { struct inode *ip; struct vnode *nvp; @@ -1096,10 +1099,22 @@ ext2fs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) ufh.ufid_ino >= fs->e2fs_ncg * fs->e2fs.e2fs_ipg) return (ESTALE); - if ((error = VFS_VGET(mp, ufh.ufid_ino, &nvp)) != 0) { + if ((error = VFS_VGET(mp, ufh.ufid_ino, flags, &nvp)) != 0) { *vpp = NULLVP; return (error); } + + /* XXX Omit needless lock/unlock. */ + error = vn_lock(nvp, LK_EXCLUSIVE); + if (error) { + vrele(nvp); + return (error); + } + + /* + * XXX This check shouldn't be necessary -- vget should refuse + * to return invalid vnodes. + */ ip = VTOI(nvp); if (ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime != 0 || ip->i_e2fs_gen != ufh.ufid_gen) { @@ -1107,6 +1122,8 @@ ext2fs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) *vpp = NULLVP; return (ESTALE); } + + VOP_UNLOCK(nvp); *vpp = nvp; return (0); } diff --git a/sys/ufs/ext2fs/ext2fs_vnops.c b/sys/ufs/ext2fs/ext2fs_vnops.c index 152aa0b..d517918 100644 --- a/sys/ufs/ext2fs/ext2fs_vnops.c +++ b/sys/ufs/ext2fs/ext2fs_vnops.c @@ -188,11 +188,18 @@ ext2fs_mknod(void *v) (*vpp)->v_type = VNON; VOP_UNLOCK(*vpp); vgone(*vpp); - error = VFS_VGET(mp, ino, vpp); + error = VFS_VGET(mp, ino, 0, vpp); if (error != 0) { *vpp = NULL; return (error); } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + return (error); + } VOP_UNLOCK(*vpp); return (0); } diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index ffa9235..c7b4a06 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -602,7 +602,7 @@ ffs_valloc(struct vnode *pvp, int mode, kauth_cred_t cred, if (ino == 0) goto noinodes; UFS_WAPBL_END(pvp->v_mount); - error = VFS_VGET(pvp->v_mount, ino, vpp); + error = VFS_VGET(pvp->v_mount, ino, 0, vpp); if (error) { int err; err = UFS_WAPBL_BEGIN(pvp->v_mount); @@ -612,6 +612,19 @@ ffs_valloc(struct vnode *pvp, int mode, kauth_cred_t cred, UFS_WAPBL_END(pvp->v_mount); return (error); } + /* XXX Should use vready instead of the lock for this stuff. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + int err; + vrele(*vpp); + *vpp = NULL; + err = UFS_WAPBL_BEGIN(pvp->v_mount); + if (err == 0) + ffs_vfree(pvp, ino, mode); + if (err == 0) + UFS_WAPBL_END(pvp->v_mount); + return (error); + } KASSERT((*vpp)->v_type == VNON); ip = VTOI(*vpp); if (ip->i_mode) { diff --git a/sys/ufs/ffs/ffs_quota2.c b/sys/ufs/ffs/ffs_quota2.c index b3d45b3..b5eb9a3 100644 --- a/sys/ufs/ffs/ffs_quota2.c +++ b/sys/ufs/ffs/ffs_quota2.c @@ -82,12 +82,20 @@ ffs_quota2_mount(struct mount *mp) if (fs->fs_quota_flags & FS_Q2_DO_TYPE(USRQUOTA) && ump->um_quotas[USRQUOTA] == NULLVP) { - error = VFS_VGET(mp, fs->fs_quotafile[USRQUOTA], &vp); + error = VFS_VGET(mp, fs->fs_quotafile[USRQUOTA], 0, &vp); if (error) { printf("%s: can't vget() user quota inode: %d\n", mp->mnt_stat.f_mntonname, error); return error; } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(vp, LK_EXCLUSIVE); + if (error) { + printf("%s: can't lock user quota inode: %d\n", + mp->mnt_stat.f_mntonname, error); + vrele(vp); + return error; + } ump->um_quotas[USRQUOTA] = vp; ump->um_cred[USRQUOTA] = l->l_cred; mutex_enter(vp->v_interlock); @@ -97,8 +105,18 @@ ffs_quota2_mount(struct mount *mp) } if (fs->fs_quota_flags & FS_Q2_DO_TYPE(GRPQUOTA) && ump->um_quotas[GRPQUOTA] == NULLVP) { - error = VFS_VGET(mp, fs->fs_quotafile[GRPQUOTA], &vp); + error = VFS_VGET(mp, fs->fs_quotafile[GRPQUOTA], 0, &vp); + if (error) { + vn_close(ump->um_quotas[USRQUOTA], + FREAD|FWRITE, l->l_cred); + printf("%s: can't vget() group quota inode: %d\n", + mp->mnt_stat.f_mntonname, error); + return error; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(vp, LK_EXCLUSIVE); if (error) { + vrele(vp); vn_close(ump->um_quotas[USRQUOTA], FREAD|FWRITE, l->l_cred); printf("%s: can't vget() group quota inode: %d\n", diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index bd9dbea..98b092c 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -627,9 +627,15 @@ snapshot_expunge(struct mount *mp, struct vnode *vp, struct fs *copy_fs, if ((fs->fs_flags & FS_DOWAPBL) && fs->fs_journal_location == UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM) { error = VFS_VGET(mp, - fs->fs_journallocs[UFS_WAPBL_INFS_INO], &logvp); + fs->fs_journallocs[UFS_WAPBL_INFS_INO], 0, &logvp); if (error) goto out; + error = vn_lock(logvp, LK_EXCLUSIVE); + if (error) { + vrele(logvp); + logvp = NULL; + goto out; + } } /* * We also calculate the needed size for the snapshot list. @@ -1728,11 +1734,18 @@ ffs_snapshot_mount(struct mount *mp) for (snaploc = 0; snaploc < FSMAXSNAP; snaploc++) { if (fs->fs_snapinum[snaploc] == 0) break; - if ((error = VFS_VGET(mp, fs->fs_snapinum[snaploc], + if ((error = VFS_VGET(mp, fs->fs_snapinum[snaploc], 0, &vp)) != 0) { + vp = NULL; /* paranoia */ printf("ffs_snapshot_mount: vget failed %d\n", error); continue; } + if ((error = vn_lock(vp, LK_EXCLUSIVE)) != 0) { + vrele(vp); + vp = NULL; + printf("ffs_snapshot_mount: lock failed %d\n", error); + continue; + } ip = VTOI(vp); if ((ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) != SF_SNAPSHOT) { diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index a3cd05d..9db6ab7 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -1729,7 +1729,7 @@ ffs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) * done by the calling routine. */ int -ffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) +ffs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { struct fs *fs; struct inode *ip; @@ -1743,8 +1743,10 @@ ffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) dev = ump->um_dev; retry: - if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) + if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) { + VOP_UNLOCK(*vpp); return (0); + } /* Allocate a new vnode/inode. */ error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, NULL, 0, &vp); @@ -1851,6 +1853,7 @@ ffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) } /* XXX */ uvm_vnp_setsize(vp, ip->i_size); vready(vp); + VOP_UNLOCK(vp); *vpp = vp; return (0); } @@ -1866,7 +1869,7 @@ ffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) * those rights via. exflagsp and credanonp */ int -ffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) +ffs_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) { struct ufid ufh; struct fs *fs; @@ -1879,7 +1882,7 @@ ffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) if (ufh.ufid_ino < UFS_ROOTINO || ufh.ufid_ino >= fs->fs_ncg * fs->fs_ipg) return (ESTALE); - return (ufs_fhtovp(mp, &ufh, vpp)); + return (ufs_fhtovp(mp, &ufh, flags, vpp)); } /* diff --git a/sys/ufs/ffs/ffs_wapbl.c b/sys/ufs/ffs/ffs_wapbl.c index 5a87a8e..7f5a169 100644 --- a/sys/ufs/ffs/ffs_wapbl.c +++ b/sys/ufs/ffs/ffs_wapbl.c @@ -124,13 +124,22 @@ ffs_wapbl_replay_finish(struct mount *mp) for (i = 0; i < wr->wr_inodescnt; i++) { struct vnode *vp; struct inode *ip; - error = VFS_VGET(mp, wr->wr_inodes[i].wr_inumber, &vp); + error = VFS_VGET(mp, wr->wr_inodes[i].wr_inumber, 0, &vp); if (error) { printf("ffs_wapbl_replay_finish: " "unable to cleanup inode %" PRIu32 "\n", wr->wr_inodes[i].wr_inumber); continue; } + error = vn_lock(vp, LK_EXCLUSIVE); + if (error) { + vrele(vp); + vp = NULL; + printf("ffs_wapbl_replay_finish: " + "unable to lock inode %" PRIu32 "\n", + wr->wr_inodes[i].wr_inumber); + continue; + } ip = VTOI(vp); KDASSERT(wr->wr_inodes[i].wr_inumber == ip->i_number); #ifdef WAPBL_DEBUG @@ -242,13 +251,22 @@ wapbl_remove_log(struct mount *mp) /* if no existing log inode, just clear all fields and bail */ if (log_ino == 0) goto done; - error = VFS_VGET(mp, log_ino, &vp); + error = VFS_VGET(mp, log_ino, 0, &vp); if (error != 0) { printf("ffs_wapbl: vget failed %d\n", error); /* clear out log info on error */ goto done; } + error = vn_lock(vp, LK_EXCLUSIVE); + if (error != 0) { + vrele(vp); + vp = NULL; + printf("ffs_wapbl: lock failed %d\n", + error); + /* clear out log info on error */ + goto done; + } ip = VTOI(vp); KASSERT(log_ino == ip->i_number); if ((ip->i_flags & SF_LOG) == 0) { @@ -605,8 +623,12 @@ wapbl_create_infs_log(struct mount *mp, struct fs *fs, struct vnode *devvp, struct inode *ip; int error; - if ((error = VFS_ROOT(mp, &rvp)) != 0) + if ((error = VFS_ROOT(mp, 0, &rvp)) != 0) + return error; + if ((error = vn_lock(rvp, LK_EXCLUSIVE)) != 0) { + vrele(rvp); return error; + } error = UFS_VALLOC(rvp, 0 | S_IFREG, NOCRED, &vp); if (mp->mnt_flag & MNT_UPDATE) { diff --git a/sys/ufs/lfs/lfs_extern.h b/sys/ufs/lfs/lfs_extern.h index 7e3da2b..031a46f 100644 --- a/sys/ufs/lfs/lfs_extern.h +++ b/sys/ufs/lfs/lfs_extern.h @@ -231,8 +231,8 @@ int lfs_mount(struct mount *, const char *, void *, size_t *); int lfs_unmount(struct mount *, int); int lfs_statvfs(struct mount *, struct statvfs *); int lfs_sync(struct mount *, int, kauth_cred_t); -int lfs_vget(struct mount *, ino_t, struct vnode **); -int lfs_fhtovp(struct mount *, struct fid *, struct vnode **); +int lfs_vget(struct mount *, ino_t, int, struct vnode **); +int lfs_fhtovp(struct mount *, struct fid *, int, struct vnode **); int lfs_vptofh(struct vnode *, struct fid *, size_t *); void lfs_vinit(struct mount *, struct vnode **); int lfs_resize_fs(struct lfs *, int); diff --git a/sys/ufs/lfs/lfs_rename.c b/sys/ufs/lfs/lfs_rename.c index 720629b..0fca0ce 100644 --- a/sys/ufs/lfs/lfs_rename.c +++ b/sys/ufs/lfs/lfs_rename.c @@ -741,10 +741,18 @@ ulfs_gro_genealogy(struct mount *mp, kauth_cred_t cred, * be recycled, but why can't dotdot_ino be recycled? */ VOP_UNLOCK(vp); - error = VFS_VGET(mp, dotdot_ino, &dvp); - vrele(vp); - if (error) + error = VFS_VGET(mp, dotdot_ino, 0, &dvp); + if (error) { + vrele(vp); + return error; + } + error = vn_lock(dvp, LK_EXCLUSIVE); + if (error) { + vrele(dvp); + vrele(vp); return error; + } + vrele(vp); KASSERT(dvp != NULL); KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); diff --git a/sys/ufs/lfs/lfs_rfw.c b/sys/ufs/lfs/lfs_rfw.c index ca7137e..2e2e2bf 100644 --- a/sys/ufs/lfs/lfs_rfw.c +++ b/sys/ufs/lfs/lfs_rfw.c @@ -116,7 +116,14 @@ lfs_rf_valloc(struct lfs *fs, ino_t ino, int vers, struct lwp *l, * we don't have to do anything else. If the version number is wrong, * take appropriate action. */ - error = VFS_VGET(fs->lfs_ivnode->v_mount, ino, &vp); + error = VFS_VGET(fs->lfs_ivnode->v_mount, ino, 0, &vp); + if (error == 0) { /* XXX ugh bletch error == 0 branches */ + error = vn_lock(vp, LK_EXCLUSIVE); + if (error) { + vrele(vp); + vp = NULL; + } + } if (error == 0) { DLOG((DLOG_RF, "lfs_rf_valloc[1]: ino %d vp %p\n", ino, vp)); diff --git a/sys/ufs/lfs/lfs_syscalls.c b/sys/ufs/lfs/lfs_syscalls.c index 3349e05..332a37b 100644 --- a/sys/ufs/lfs/lfs_syscalls.c +++ b/sys/ufs/lfs/lfs_syscalls.c @@ -740,6 +740,9 @@ lfs_bmapv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt) /* * A regular call to VFS_VGET could deadlock * here. Instead, we try an unlocked access. + * + * XXX Once VFS_VGET stops spuriously locking, + * this should be revisited. */ mutex_enter(&ulfs_ihash_lock); vp = ulfs_ihashlookup(ump->um_dev, blkp->bi_inode); @@ -762,7 +765,14 @@ lfs_bmapv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt) v_daddr = LFS_UNUSED_DADDR; continue; } - error = VFS_VGET(mntp, blkp->bi_inode, &vp); + error = VFS_VGET(mntp, blkp->bi_inode, 0, &vp); + if (error == 0) { /* XXX ugh bletch */ + error = vn_lock(vp, LK_EXCLUSIVE); + if (error) { + vrele(vp); + vp = NULL; + } + } if (error) { DLOG((DLOG_CLEAN, "lfs_bmapv: vget ino" "%d failed with %d", diff --git a/sys/ufs/lfs/lfs_vfsops.c b/sys/ufs/lfs/lfs_vfsops.c index adc78fd..57c0b81 100644 --- a/sys/ufs/lfs/lfs_vfsops.c +++ b/sys/ufs/lfs/lfs_vfsops.c @@ -1075,10 +1075,16 @@ lfs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l) * artificially increment the reference count and keep a pointer * to it in the incore copy of the superblock. */ - if ((error = VFS_VGET(mp, LFS_IFILE_INUM, &vp)) != 0) { + if ((error = VFS_VGET(mp, LFS_IFILE_INUM, 0, &vp)) != 0) { DLOG((DLOG_MOUNT, "lfs_mountfs: ifile vget failed, error=%d\n", error)); goto out; } + if ((error = vn_lock(vp, LK_EXCLUSIVE)) != 0) { + vrele(vp); + vp = NULL; + DLOG((DLOG_MOUNT, "lfs_mountfs: ifile lock failed, error=%d\n", error)); + goto out; + } fs->lfs_ivnode = vp; vref(vp); @@ -1435,7 +1441,7 @@ lfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) * Detection and handling of mount points must be done by the calling routine. */ int -lfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) +lfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { struct lfs *fs; struct ulfs1_dinode *dip; @@ -1466,8 +1472,10 @@ lfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) mutex_exit(&lfs_lock); retry: - if ((*vpp = ulfs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) + if ((*vpp = ulfs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) { + VOP_UNLOCK(*vpp); return (0); + } error = getnewvnode(VT_LFS, mp, lfs_vnodeop_p, NULL, 0, &vp); if (error) { @@ -1601,6 +1609,7 @@ retry: *vpp = vp; KASSERT(VOP_ISLOCKED(vp)); + VOP_UNLOCK(vp); return (0); } @@ -1609,7 +1618,7 @@ retry: * File handle to vnode */ int -lfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) +lfs_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) { struct lfid lfh; struct buf *bp; @@ -1645,7 +1654,7 @@ lfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) return ESTALE; } - return (ulfs_fhtovp(mp, &lfh.lfid_ufid, vpp)); + return (ulfs_fhtovp(mp, &lfh.lfid_ufid, flags, vpp)); } /* diff --git a/sys/ufs/lfs/lfs_vnops.c b/sys/ufs/lfs/lfs_vnops.c index fab2baf..0b307e1 100644 --- a/sys/ufs/lfs/lfs_vnops.c +++ b/sys/ufs/lfs/lfs_vnops.c @@ -654,7 +654,15 @@ lfs_mknod(void *v) (*vpp)->v_type = VNON; VOP_UNLOCK(*vpp); vgone(*vpp); - error = VFS_VGET(mp, ino, vpp); + error = VFS_VGET(mp, ino, 0, vpp); + if (error == 0) { /* XXX ugh bletch error == 0 branches */ + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + } + } fstrans_done(ap->a_dvp->v_mount); if (error != 0) { diff --git a/sys/ufs/lfs/ulfs_extattr.c b/sys/ufs/lfs/ulfs_extattr.c index 64ed1e1..da21f23 100644 --- a/sys/ufs/lfs/ulfs_extattr.c +++ b/sys/ufs/lfs/ulfs_extattr.c @@ -643,12 +643,19 @@ ulfs_extattr_autostart(struct mount *mp, struct lwp *l) * Does ULFS_EXTATTR_FSROOTSUBDIR exist off the filesystem root? * If so, automatically start EA's. */ - error = VFS_ROOT(mp, &rvp); + error = VFS_ROOT(mp, 0, &rvp); if (error) { printf("ulfs_extattr_autostart.VFS_ROOT() returned %d\n", error); return (error); } + error = vn_lock(rvp, LK_EXCLUSIVE); + if (error) { + vrele(rvp); + printf("ulfs_extattr_autostart.vn_lock() returned %d\n", + error); + return (error); + } KASSERT(VOP_ISLOCKED(rvp) == LK_EXCLUSIVE); diff --git a/sys/ufs/lfs/ulfs_extern.h b/sys/ufs/lfs/ulfs_extern.h index 63f2f13..79f6d80 100644 --- a/sys/ufs/lfs/ulfs_extern.h +++ b/sys/ufs/lfs/ulfs_extern.h @@ -165,9 +165,9 @@ void ulfs_init(void); void ulfs_reinit(void); void ulfs_done(void); int ulfs_start(struct mount *, int); -int ulfs_root(struct mount *, struct vnode **); +int ulfs_root(struct mount *, int, struct vnode **); int ulfs_quotactl(struct mount *, struct quotactl_args *); -int ulfs_fhtovp(struct mount *, struct ulfs_ufid *, struct vnode **); +int ulfs_fhtovp(struct mount *, struct ulfs_ufid *, int, struct vnode **); /* ulfs_vnops.c */ void ulfs_vinit(struct mount *, int (**)(void *), diff --git a/sys/ufs/lfs/ulfs_lookup.c b/sys/ufs/lfs/ulfs_lookup.c index 0b666fe..371e065 100644 --- a/sys/ufs/lfs/ulfs_lookup.c +++ b/sys/ufs/lfs/ulfs_lookup.c @@ -568,11 +568,23 @@ found: } else { if (flags & ISDOTDOT) VOP_UNLOCK(vdp); /* race to get the inode */ - error = VFS_VGET(vdp->v_mount, foundino, &tdp); + error = VFS_VGET(vdp->v_mount, foundino, 0, &tdp); + if (error) { + if (flags & ISDOTDOT) + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + goto out; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + tdp = NULL; + if (flags & ISDOTDOT) + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + goto out; + } if (flags & ISDOTDOT) vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); - if (error) - goto out; } /* * Write access to directory required to delete files. @@ -629,11 +641,23 @@ found: } if (flags & ISDOTDOT) VOP_UNLOCK(vdp); /* race to get the inode */ - error = VFS_VGET(vdp->v_mount, foundino, &tdp); + error = VFS_VGET(vdp->v_mount, foundino, 0, &tdp); + if (error) { + if (flags & ISDOTDOT) + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + goto out; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + tdp = NULL; + if (flags & ISDOTDOT) + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + goto out; + } if (flags & ISDOTDOT) vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); - if (error) - goto out; *vpp = tdp; error = 0; goto out; @@ -661,19 +685,35 @@ found: pdp = vdp; if (flags & ISDOTDOT) { VOP_UNLOCK(pdp); /* race to get the inode */ - error = VFS_VGET(vdp->v_mount, foundino, &tdp); - vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); + error = VFS_VGET(vdp->v_mount, foundino, 0, &tdp); + if (error) { + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); + goto out; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); if (error) { + vrele(tdp); + tdp = NULL; + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); goto out; } + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); *vpp = tdp; } else if (dp->i_number == foundino) { vref(vdp); /* we want ourself, ie "." */ *vpp = vdp; } else { - error = VFS_VGET(vdp->v_mount, foundino, &tdp); + error = VFS_VGET(vdp->v_mount, foundino, 0, &tdp); if (error) goto out; + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + tdp = NULL; + goto out; + } *vpp = tdp; } @@ -1320,12 +1360,21 @@ ulfs_checkpath(struct inode *source, struct inode *target, kauth_cred_t cred) break; VOP_UNLOCK(vp); error = VFS_VGET(vp->v_mount, - ulfs_rw32(dirbuf.dotdot_ino, needswap), &nextvp); - vrele(vp); + ulfs_rw32(dirbuf.dotdot_ino, needswap), 0, &nextvp); if (error) { + vrele(vp); vp = NULL; break; } + error = vn_lock(nextvp, LK_EXCLUSIVE); + if (error) { + vrele(nextvp); + nextvp = NULL; + vrele(vp); + vp = NULL; + break; + } + vrele(vp); vp = nextvp; } @@ -1391,6 +1440,9 @@ ulfs_readdotdot(struct vnode *vp, int needswap, kauth_cred_t cred, ino_t *result * * Note that UPPER and LOWER must be on the same volume, and because * we inspect only that volume NEEDSWAP can be constant. + * + * XXX I think this routine is dead, obsoleted by the genfs-based + * ufs_rename. */ int ulfs_parentcheck(struct vnode *upper, struct vnode *lower, kauth_cred_t cred, @@ -1438,8 +1490,14 @@ ulfs_parentcheck(struct vnode *upper, struct vnode *lower, kauth_cred_t cred, return 0; } VOP_UNLOCK(current); - error = VFS_VGET(current->v_mount, found_ino, &next); + error = VFS_VGET(current->v_mount, found_ino, 0, &next); + if (error) { + vrele(current); + return error; + } + error = vn_lock(next, LK_EXCLUSIVE); if (error) { + vrele(next); vrele(current); return error; } diff --git a/sys/ufs/lfs/ulfs_quota2.c b/sys/ufs/lfs/ulfs_quota2.c index 8b67b2b..4de958a 100644 --- a/sys/ufs/lfs/ulfs_quota2.c +++ b/sys/ufs/lfs/ulfs_quota2.c @@ -1589,12 +1589,20 @@ lfs_quota2_mount(struct mount *mp) if (fs->lfs_quota_flags & FS_Q2_DO_TYPE(ULFS_USRQUOTA) && ump->um_quotas[ULFS_USRQUOTA] == NULLVP) { - error = VFS_VGET(mp, fs->lfs_quotaino[ULFS_USRQUOTA], &vp); + error = VFS_VGET(mp, fs->lfs_quotaino[ULFS_USRQUOTA], 0, &vp); if (error) { printf("%s: can't vget() user quota inode: %d\n", mp->mnt_stat.f_mntonname, error); return error; } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(vp, LK_EXCLUSIVE); + if (error) { + vrele(vp); + printf("%s: can't lock user quota inode: %d\n", + mp->mnt_stat.f_mntonname, error); + return error; + } ump->um_quotas[ULFS_USRQUOTA] = vp; ump->um_cred[ULFS_USRQUOTA] = l->l_cred; mutex_enter(vp->v_interlock); @@ -1604,8 +1612,18 @@ lfs_quota2_mount(struct mount *mp) } if (fs->lfs_quota_flags & FS_Q2_DO_TYPE(ULFS_GRPQUOTA) && ump->um_quotas[ULFS_GRPQUOTA] == NULLVP) { - error = VFS_VGET(mp, fs->lfs_quotaino[ULFS_GRPQUOTA], &vp); + error = VFS_VGET(mp, fs->lfs_quotaino[ULFS_GRPQUOTA], 0, &vp); + if (error) { + vn_close(ump->um_quotas[ULFS_USRQUOTA], + FREAD|FWRITE, l->l_cred); + printf("%s: can't vget() group quota inode: %d\n", + mp->mnt_stat.f_mntonname, error); + return error; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(vp, LK_EXCLUSIVE); if (error) { + vrele(vp); vn_close(ump->um_quotas[ULFS_USRQUOTA], FREAD|FWRITE, l->l_cred); printf("%s: can't vget() group quota inode: %d\n", diff --git a/sys/ufs/lfs/ulfs_vfsops.c b/sys/ufs/lfs/ulfs_vfsops.c index b0c7c9f..fe0eba5 100644 --- a/sys/ufs/lfs/ulfs_vfsops.c +++ b/sys/ufs/lfs/ulfs_vfsops.c @@ -87,12 +87,12 @@ ulfs_start(struct mount *mp, int flags) * Return the root of a filesystem. */ int -ulfs_root(struct mount *mp, struct vnode **vpp) +ulfs_root(struct mount *mp, int flags, struct vnode **vpp) { struct vnode *nvp; int error; - if ((error = VFS_VGET(mp, (ino_t)ULFS_ROOTINO, &nvp)) != 0) + if ((error = VFS_VGET(mp, (ino_t)ULFS_ROOTINO, flags, &nvp)) != 0) return (error); *vpp = nvp; return (0); @@ -214,16 +214,30 @@ ulfs_quotactl(struct mount *mp, struct quotactl_args *args) * filesystem has validated the file handle. */ int -ulfs_fhtovp(struct mount *mp, struct ulfs_ufid *ufhp, struct vnode **vpp) +ulfs_fhtovp(struct mount *mp, struct ulfs_ufid *ufhp, int flags, + struct vnode **vpp) { struct vnode *nvp; struct inode *ip; int error; - if ((error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) != 0) { + if ((error = VFS_VGET(mp, ufhp->ufid_ino, flags, &nvp)) != 0) { *vpp = NULLVP; return (error); } + + + /* XXX Omit needless lock/unlock. */ + error = vn_lock(nvp, LK_EXCLUSIVE); + if (error) { + vrele(nvp); + return (error); + } + + /* + * XXX This check shouldn't be necessary -- vget should refuse + * to return invalid vnodes. + */ ip = VTOI(nvp); KASSERT(ip != NULL); if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen) { @@ -231,6 +245,8 @@ ulfs_fhtovp(struct mount *mp, struct ulfs_ufid *ufhp, struct vnode **vpp) *vpp = NULLVP; return (ESTALE); } + + VOP_UNLOCK(nvp); *vpp = nvp; return (0); } diff --git a/sys/ufs/ufs/ufs_extattr.c b/sys/ufs/ufs/ufs_extattr.c index e6745d1..2b26a5a 100644 --- a/sys/ufs/ufs/ufs_extattr.c +++ b/sys/ufs/ufs/ufs_extattr.c @@ -643,12 +643,19 @@ ufs_extattr_autostart(struct mount *mp, struct lwp *l) * Does UFS_EXTATTR_FSROOTSUBDIR exist off the filesystem root? * If so, automatically start EA's. */ - error = VFS_ROOT(mp, &rvp); + error = VFS_ROOT(mp, 0, &rvp); if (error) { printf("ufs_extattr_autostart.VFS_ROOT() returned %d\n", error); return (error); } + error = vn_lock(rvp, LK_EXCLUSIVE); + if (error) { + vrele(rvp); + printf("ufs_extattr_autostart.vn_lock() returned %d\n", + error); + return (error); + } KASSERT(VOP_ISLOCKED(rvp) == LK_EXCLUSIVE); diff --git a/sys/ufs/ufs/ufs_extern.h b/sys/ufs/ufs/ufs_extern.h index f279d03..db91181 100644 --- a/sys/ufs/ufs/ufs_extern.h +++ b/sys/ufs/ufs/ufs_extern.h @@ -187,9 +187,9 @@ void ufs_init(void); void ufs_reinit(void); void ufs_done(void); int ufs_start(struct mount *, int); -int ufs_root(struct mount *, struct vnode **); +int ufs_root(struct mount *, int, struct vnode **); int ufs_quotactl(struct mount *, struct quotactl_args *); -int ufs_fhtovp(struct mount *, struct ufid *, struct vnode **); +int ufs_fhtovp(struct mount *, struct ufid *, int, struct vnode **); /* ufs_vnops.c */ void ufs_vinit(struct mount *, int (**)(void *), diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c index 1afa4ad7..bc98f44 100644 --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -568,11 +568,23 @@ found: } else { if (flags & ISDOTDOT) VOP_UNLOCK(vdp); /* race to get the inode */ - error = VFS_VGET(vdp->v_mount, foundino, &tdp); + error = VFS_VGET(vdp->v_mount, foundino, 0, &tdp); + if (error) { + if (flags & ISDOTDOT) + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + goto out; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + tdp = NULL; + if (flags & ISDOTDOT) + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + goto out; + } if (flags & ISDOTDOT) vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); - if (error) - goto out; } /* * Write access to directory required to delete files. @@ -629,11 +641,23 @@ found: } if (flags & ISDOTDOT) VOP_UNLOCK(vdp); /* race to get the inode */ - error = VFS_VGET(vdp->v_mount, foundino, &tdp); + error = VFS_VGET(vdp->v_mount, foundino, 0, &tdp); + if (error) { + if (flags & ISDOTDOT) + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + goto out; + } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + tdp = NULL; + if (flags & ISDOTDOT) + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + goto out; + } if (flags & ISDOTDOT) vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); - if (error) - goto out; *vpp = tdp; error = 0; goto out; @@ -661,19 +685,35 @@ found: pdp = vdp; if (flags & ISDOTDOT) { VOP_UNLOCK(pdp); /* race to get the inode */ - error = VFS_VGET(vdp->v_mount, foundino, &tdp); - vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); + error = VFS_VGET(vdp->v_mount, foundino, 0, &tdp); if (error) { + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); goto out; } + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + tdp = NULL; + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); + goto out; + } + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); *vpp = tdp; } else if (dp->i_number == foundino) { vref(vdp); /* we want ourself, ie "." */ *vpp = vdp; } else { - error = VFS_VGET(vdp->v_mount, foundino, &tdp); + error = VFS_VGET(vdp->v_mount, foundino, 0, &tdp); if (error) goto out; + /* XXX Omit needless lock/unlock. */ + error = vn_lock(tdp, LK_EXCLUSIVE); + if (error) { + vrele(tdp); + tdp = NULL; + goto out; + } *vpp = tdp; } @@ -1274,6 +1314,9 @@ ufs_dirempty(struct inode *ip, ino_t parentino, kauth_cred_t cred) * Check if source directory is in the path of the target directory. * Target is supplied locked, source is unlocked. * The target is always vput before returning. + * + * XXX I think this routine is dead, obsoleted by the genfs-based + * ufs_rename. */ int ufs_checkpath(struct inode *source, struct inode *target, kauth_cred_t cred) @@ -1328,12 +1371,21 @@ ufs_checkpath(struct inode *source, struct inode *target, kauth_cred_t cred) break; VOP_UNLOCK(vp); error = VFS_VGET(vp->v_mount, - ufs_rw32(dirbuf.dotdot_ino, needswap), &nextvp); - vrele(vp); + ufs_rw32(dirbuf.dotdot_ino, needswap), 0, &nextvp); if (error) { + vrele(vp); vp = NULL; break; } + error = vn_lock(nextvp, LK_EXCLUSIVE); + if (error) { + vrele(nextvp); + nextvp = NULL; + vrele(vp); + vp = NULL; + break; + } + vrele(vp); vp = nextvp; } @@ -1399,6 +1451,9 @@ ufs_readdotdot(struct vnode *vp, int needswap, kauth_cred_t cred, ino_t *result) * * Note that UPPER and LOWER must be on the same volume, and because * we inspect only that volume NEEDSWAP can be constant. + * + * XXX I think this routine is dead, obsoleted by the genfs-based + * ufs_rename. */ int ufs_parentcheck(struct vnode *upper, struct vnode *lower, kauth_cred_t cred, @@ -1446,8 +1501,14 @@ ufs_parentcheck(struct vnode *upper, struct vnode *lower, kauth_cred_t cred, return 0; } VOP_UNLOCK(current); - error = VFS_VGET(current->v_mount, found_ino, &next); + error = VFS_VGET(current->v_mount, found_ino, 0, &next); + if (error) { + vrele(current); + return error; + } + error = vn_lock(next, LK_EXCLUSIVE); if (error) { + vrele(next); vrele(current); return error; } diff --git a/sys/ufs/ufs/ufs_rename.c b/sys/ufs/ufs/ufs_rename.c index 113bf6d..178ac7f 100644 --- a/sys/ufs/ufs/ufs_rename.c +++ b/sys/ufs/ufs/ufs_rename.c @@ -989,10 +989,18 @@ ufs_gro_genealogy(struct mount *mp, kauth_cred_t cred, * be recycled, but why can't dotdot_ino be recycled? */ VOP_UNLOCK(vp); - error = VFS_VGET(mp, dotdot_ino, &dvp); - vrele(vp); - if (error) + error = VFS_VGET(mp, dotdot_ino, 0, &dvp); + if (error) { + vrele(vp); + return error; + } + error = vn_lock(dvp, LK_EXCLUSIVE); + if (error) { + vrele(dvp); + vrele(vp); return error; + } + vrele(vp); KASSERT(dvp != NULL); KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); diff --git a/sys/ufs/ufs/ufs_vfsops.c b/sys/ufs/ufs/ufs_vfsops.c index 9be9992..a368d46 100644 --- a/sys/ufs/ufs/ufs_vfsops.c +++ b/sys/ufs/ufs/ufs_vfsops.c @@ -85,12 +85,12 @@ ufs_start(struct mount *mp, int flags) * Return the root of a filesystem. */ int -ufs_root(struct mount *mp, struct vnode **vpp) +ufs_root(struct mount *mp, int flags, struct vnode **vpp) { struct vnode *nvp; int error; - if ((error = VFS_VGET(mp, (ino_t)UFS_ROOTINO, &nvp)) != 0) + if ((error = VFS_VGET(mp, (ino_t)UFS_ROOTINO, flags, &nvp)) != 0) return (error); *vpp = nvp; return (0); @@ -212,16 +212,28 @@ ufs_quotactl(struct mount *mp, struct quotactl_args *args) * filesystem has validated the file handle. */ int -ufs_fhtovp(struct mount *mp, struct ufid *ufhp, struct vnode **vpp) +ufs_fhtovp(struct mount *mp, struct ufid *ufhp, int flags, struct vnode **vpp) { struct vnode *nvp; struct inode *ip; int error; - if ((error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) != 0) { + if ((error = VFS_VGET(mp, ufhp->ufid_ino, flags, &nvp)) != 0) { *vpp = NULLVP; return (error); } + + /* XXX Omit needless lock/unlock. */ + error = vn_lock(nvp, LK_EXCLUSIVE); + if (error) { + vrele(nvp); + return (error); + } + + /* + * XXX This check shouldn't be necessary -- vget should refuse + * to return invalid vnodes. + */ ip = VTOI(nvp); KASSERT(ip != NULL); if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen) { @@ -229,6 +241,8 @@ ufs_fhtovp(struct mount *mp, struct ufid *ufhp, struct vnode **vpp) *vpp = NULLVP; return (ESTALE); } + + VOP_UNLOCK(nvp); *vpp = nvp; return (0); } diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index ef604f8..3f1bc2e 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -232,7 +232,16 @@ ufs_mknod(void *v) (*vpp)->v_type = VNON; VOP_UNLOCK(*vpp); vgone(*vpp); - error = VFS_VGET(mp, ino, vpp); + error = VFS_VGET(mp, ino, 0, vpp); + if (error) + goto out; + /* XXX Omit needless lock/unlock. */ + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + goto out; + } out: fstrans_done(ap->a_dvp->v_mount); if (error != 0) { diff --git a/usr.sbin/makefs/msdos.c b/usr.sbin/makefs/msdos.c index 5a7b103..f8c7dcf 100644 --- a/usr.sbin/makefs/msdos.c +++ b/usr.sbin/makefs/msdos.c @@ -175,7 +175,7 @@ msdos_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts) if ((pmp = msdosfs_mount(&vp, 0)) == NULL) err(1, "msdosfs_mount"); - if (msdosfs_root(pmp, &rootvp) != 0) + if (msdosfs_root(pmp, 0, &rootvp) != 0) err(1, "msdosfs_root"); if (debug & DEBUG_FS_MAKEFS) diff --git a/usr.sbin/makefs/msdos.h b/usr.sbin/makefs/msdos.h index 3571bef..ee4141b 100644 --- a/usr.sbin/makefs/msdos.h +++ b/usr.sbin/makefs/msdos.h @@ -36,7 +36,7 @@ struct vnode; struct denode; struct msdosfsmount *msdosfs_mount(struct vnode *, int); -int msdosfs_root(struct msdosfsmount *, struct vnode *); +int msdosfs_root(struct msdosfsmount *, int, struct vnode *); struct denode *msdosfs_mkfile(const char *, struct denode *, fsnode *); struct denode *msdosfs_mkdire(const char *, struct denode *, fsnode *); diff --git a/usr.sbin/makefs/msdos/msdosfs_denode.c b/usr.sbin/makefs/msdos/msdosfs_denode.c index 47ebee0..4b21938 100644 --- a/usr.sbin/makefs/msdos/msdosfs_denode.c +++ b/usr.sbin/makefs/msdos/msdosfs_denode.c @@ -80,7 +80,7 @@ __KERNEL_RCSID(0, "$NetBSD: msdosfs_denode.c,v 1.6 2013/10/19 17:16:37 christos */ int deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, - struct denode **depp) + int flags, struct denode **depp) /* pmp: so we know the maj/min number */ /* dirclust: cluster this dir entry came from */ /* diroffset: index of entry within the cluster */ diff --git a/usr.sbin/makefs/msdos/msdosfs_vfsops.c b/usr.sbin/makefs/msdos/msdosfs_vfsops.c index 29461c7..33d19d6 100644 --- a/usr.sbin/makefs/msdos/msdosfs_vfsops.c +++ b/usr.sbin/makefs/msdos/msdosfs_vfsops.c @@ -411,12 +411,13 @@ error_exit: } int -msdosfs_root(struct msdosfsmount *pmp, struct vnode *vp) { +msdosfs_root(struct msdosfsmount *pmp, int flags, struct vnode *vp) { struct denode *ndep; int error; *vp = *pmp->pm_devvp; - if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep)) != 0) { + if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, flags, &ndep)) + != 0) { errno = error; return -1; } -- 1.8.3.1