commit 42f43d7a4d2748f5ebb178553ca4b9c6a0f36598 Author: Andriy Gapon Date: Fri Oct 19 19:59:42 2012 +0300 multiple changes to solaris vfs/gfs compat code and zfs ctldir handling - zfs ctldir / gfs: port solaris inactive to our inactive+reclaim - remove an incorrectly ported Solaris-ism - traverse now expects the starting node be locked and referenced - traverse now uses vfs_busy to avoid races in VFS_ROOT - mount_snapshot now expects the covered vnode to be locked and referenced, it releases the lock but keepts the reference as dounmount will drop it - gfs_dir_lookup/gfs_vop_lookup always return a resulting vnode locked, the 'flags' parameter is re-purposed for lock flags, which are always obeyed; e.g. a doomed vnode can not be returned unless LK_RETRY is specified - the ctldir code is made conforming to the above changes - the lookups are made to honor cn_lkflags - care is taken to handle the doomed vnodes properly diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_lookup.c b/sys/cddl/compat/opensolaris/kern/opensolaris_lookup.c index 94383d6..4854119 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_lookup.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_lookup.c @@ -67,12 +67,10 @@ int traverse(vnode_t **cvpp, int lktype) { vnode_t *cvp; - vnode_t *tvp; vfs_t *vfsp; int error; cvp = *cvpp; - tvp = NULL; /* * If this vnode is mounted on, then we transparently indirect @@ -89,13 +87,7 @@ traverse(vnode_t **cvpp, int lktype) if (vfsp == NULL) break; error = vfs_busy(vfsp, 0); - /* - * tvp is NULL for *cvpp vnode, which we can't unlock. - */ - if (tvp != NULL) - vput(cvp); - else - vrele(cvp); + vput(cvp); if (error) return (error); @@ -103,11 +95,10 @@ traverse(vnode_t **cvpp, int lktype) * The read lock must be held across the call to VFS_ROOT() to * prevent a concurrent unmount from destroying the vfs. */ - error = VFS_ROOT(vfsp, lktype, &tvp); + error = VFS_ROOT(vfsp, lktype, &cvp); vfs_unbusy(vfsp); if (error != 0) return (error); - cvp = tvp; } *cvpp = cvp; diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c b/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c index a2532f8..d04b3f3 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c @@ -134,13 +134,13 @@ mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath, return (ENODEV); vp = *vpp; + ASSERT_VOP_ELOCKED(vp, __func__); if (vp->v_type != VDIR) return (ENOTDIR); /* * We need vnode lock to protect v_mountedhere and vnode interlock * to protect v_iflag. */ - vn_lock(vp, LK_SHARED | LK_RETRY); VI_LOCK(vp); if ((vp->v_iflag & VI_MOUNT) != 0 || vp->v_mountedhere != NULL) { VI_UNLOCK(vp); @@ -228,7 +228,7 @@ mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath, vfs_event_signal(NULL, VQ_MOUNT, 0); if (VFS_ROOT(mp, LK_EXCLUSIVE, &mvp)) panic("mount: lost mount"); - vput(vp); + VOP_UNLOCK(vp, 0); vfs_unbusy(mp); *vpp = mvp; return (0); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/gfs.c b/sys/cddl/contrib/opensolaris/uts/common/fs/gfs.c index 59944a1..d338e6f 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/gfs.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/gfs.c @@ -433,8 +433,11 @@ gfs_readdir_fini(gfs_readdir_state_t *st, int error, int *eofp, int eof) * Performs a basic check for "." and ".." directory entries. */ int -gfs_lookup_dot(vnode_t **vpp, vnode_t *dvp, vnode_t *pvp, const char *nm) +gfs_lookup_dot(vnode_t **vpp, vnode_t *dvp, vnode_t *pvp, const char *nm, + int flags) { + int err; + if (*nm == '\0' || strcmp(nm, ".") == 0) { VN_HOLD(dvp); *vpp = dvp; @@ -444,12 +447,16 @@ gfs_lookup_dot(vnode_t **vpp, vnode_t *dvp, vnode_t *pvp, const char *nm) ASSERT(dvp->v_flag & VROOT); VN_HOLD(dvp); *vpp = dvp; + return (0); } else { VN_HOLD(pvp); - *vpp = pvp; + err = vn_lock(pvp, flags); + if (err != 0) + VN_RELE(pvp); + else + *vpp = pvp; + return (err); } - vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); - return (0); } return (-1); @@ -903,13 +910,16 @@ gfs_dir_lookup_static(int (*compare)(const char *, const char *), * a callback function we try a dynamic lookup via gfs_dir_lookup_dynamic(). * * This function returns 0 on success, non-zero on error. + * + * In FreeBSD the vnode is returned referenced and locked. + * The 'flag' argument is repurposed for the lock flags. */ int gfs_dir_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp, cred_t *cr, int flags, int *direntflags, pathname_t *realpnp) { gfs_dir_t *dp = dvp->v_data; - boolean_t casecheck; + boolean_t casecheck = B_FALSE;; vnode_t *dynvp = NULL; vnode_t *vp = NULL; int (*compare)(const char *, const char *); @@ -917,16 +927,19 @@ gfs_dir_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp, cred_t *cr, ASSERT(dvp->v_type == VDIR); - if (gfs_lookup_dot(vpp, dvp, dp->gfsd_file.gfs_parent, nm) == 0) - return (0); - + error = gfs_lookup_dot(vpp, dvp, dp->gfsd_file.gfs_parent, nm, flags); + if (error != -1) + return (error); +#ifdef sun casecheck = (flags & FIGNORECASE) != 0 && direntflags != NULL; if (vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) || (flags & FIGNORECASE)) compare = strcasecmp; else +#endif compare = strcmp; +retry_doomed: gfs_dir_lock(dp); error = gfs_dir_lookup_static(compare, dp, nm, dvp, &idx, &vp, realpnp); @@ -947,7 +960,7 @@ gfs_dir_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp, cred_t *cr, if ((error || casecheck) && dp->gfsd_lookup) error = gfs_dir_lookup_dynamic(dp->gfsd_lookup, dp, nm, dvp, - &dynvp, cr, flags, direntflags, vp ? NULL : realpnp); + &dynvp, cr, 0, direntflags, vp ? NULL : realpnp); if (vp && dynvp) { /* static and dynamic entries are case-insensitive conflict */ @@ -966,6 +979,16 @@ gfs_dir_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp, cred_t *cr, out: gfs_dir_unlock(dp); + if (vp != NULL) { + if (error == 0) + error = vn_lock(vp, flags); + if (error != 0) { + VN_RELE(vp); + vp = NULL; + } + } + if (error == ENOENT && (flags & LK_NOWAIT) == 0) + goto retry_doomed; *vpp = vp; return (error); } @@ -1223,7 +1246,7 @@ gfs_vop_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp, /* ARGSUSED */ int gfs_vop_inactive(ap) - struct vop_inactive_args /* { + struct vop_reclaim_args /* { struct vnode *a_vp; struct thread *a_td; } */ *ap; @@ -1236,6 +1259,8 @@ gfs_vop_inactive(ap) else gfs_file_inactive(vp); + vnode_destroy_vobject(vp); + VI_LOCK(vp); vp->v_data = NULL; VI_UNLOCK(vp); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c index 28ab1fa..d9900da 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c @@ -517,6 +517,9 @@ zfsctl_root_getattr(ap) /* * Special case the handling of "..". + * + * On FreeBSD the vnode is returned referenced and locked according + * to 'flags' repurposed for passing LK_ flags. */ /* ARGSUSED */ int @@ -536,9 +539,7 @@ zfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp, ZFS_ENTER(zfsvfs); if (strcmp(nm, "..") == 0) { - err = VFS_ROOT(dvp->v_vfsp, LK_EXCLUSIVE, vpp); - if (err == 0) - VOP_UNLOCK(*vpp, 0); + err = VFS_ROOT(dvp->v_vfsp, flags, vpp); } else { err = gfs_vop_lookup(dvp, nm, vpp, pnp, flags, rdir, cr, ct, direntflags, realpnp); @@ -600,6 +601,7 @@ zfsctl_freebsd_root_lookup(ap) vnode_t **vpp = ap->a_vpp; cred_t *cr = ap->a_cnp->cn_cred; int flags = ap->a_cnp->cn_flags; + int lkflags = ap->a_cnp->cn_lkflags; int nameiop = ap->a_cnp->cn_nameiop; char nm[NAME_MAX + 1]; int err; @@ -610,9 +612,9 @@ zfsctl_freebsd_root_lookup(ap) ASSERT(ap->a_cnp->cn_namelen < sizeof(nm)); strlcpy(nm, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen + 1); - err = zfsctl_root_lookup(dvp, nm, vpp, NULL, 0, NULL, cr, NULL, NULL, NULL); - if (err == 0 && (nm[0] != '.' || nm[1] != '\0')) - vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); + err = zfsctl_root_lookup(dvp, nm, vpp, NULL, lkflags, NULL, cr, + NULL, NULL, NULL); + return (err); } @@ -625,8 +627,8 @@ static struct vop_vector zfsctl_ops_root = { .vop_access = zfsctl_common_access, .vop_readdir = gfs_vop_readdir, .vop_lookup = zfsctl_freebsd_root_lookup, - .vop_inactive = gfs_vop_inactive, - .vop_reclaim = zfsctl_common_reclaim, + .vop_inactive = VOP_NULL, + .vop_reclaim = gfs_vop_inactive, #ifdef TODO .vop_pathconf = zfsctl_pathconf, #endif @@ -948,6 +950,7 @@ zfsctl_snapdir_lookup(ap) size_t mountpoint_len; avl_index_t where; zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; + int lkflags = cnp->cn_lkflags; int err; int flags = 0; @@ -974,9 +977,10 @@ zfsctl_snapdir_lookup(ap) ZFS_ENTER(zfsvfs); - if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) { + err = gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm, lkflags); + if (err != -1) { ZFS_EXIT(zfsvfs); - return (0); + return (err); } if (flags & FIGNORECASE) { @@ -998,15 +1002,22 @@ zfsctl_snapdir_lookup(ap) *direntflags = ED_CASE_CONFLICT; #endif } - +retry: mutex_enter(&sdp->sd_lock); search.se_name = (char *)nm; if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) != NULL) { *vpp = sep->se_root; - VN_HOLD(*vpp); - err = traverse(vpp, LK_EXCLUSIVE | LK_RETRY); - if (err != 0) { - VN_RELE(*vpp); + err = vget(*vpp, LK_EXCLUSIVE, curthread); + if (err == ENOENT && (lkflags & LK_NOWAIT) == 0) { + /* + * The vnode is doomed, the entry is being removed. + */ + mutex_exit(&sdp->sd_lock); + goto retry; + } + if (err == 0) + err = traverse(vpp, lkflags); + if (err) { *vpp = NULL; } else if (*vpp == sep->se_root) { /* @@ -1021,7 +1032,7 @@ zfsctl_snapdir_lookup(ap) * to clear it since we're pretending to be part * of our parent's vfs. */ - (*vpp)->v_flag &= ~VROOT; + (*vpp)->v_flag &= ~VROOT; /* XXX */ } mutex_exit(&sdp->sd_lock); ZFS_EXIT(zfsvfs); @@ -1129,9 +1140,10 @@ zfsctl_shares_lookup(ap) ASSERT(cnp->cn_namelen < sizeof(nm)); strlcpy(nm, cnp->cn_nameptr, cnp->cn_namelen + 1); - if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) { + error = gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm, cnp->cn_lkflags); + if (error != -1) { ZFS_EXIT(zfsvfs); - return (0); + return (error); } if (zfsvfs->z_shares_dir == 0) { @@ -1345,6 +1357,8 @@ zfsctl_snapdir_inactive(ap) zfsctl_snapdir_t *sdp = vp->v_data; zfs_snapentry_t *sep; + vnode_destroy_vobject(vp); + /* * On forced unmount we have to free snapshots from here. */ @@ -1361,6 +1375,9 @@ zfsctl_snapdir_inactive(ap) avl_destroy(&sdp->sd_snaps); kmem_free(sdp, sizeof (zfsctl_snapdir_t)); + VI_LOCK(vp); + vp->v_data = NULL; + VI_UNLOCK(vp); return (0); } @@ -1406,8 +1423,8 @@ static struct vop_vector zfsctl_ops_snapdir = { .vop_mkdir = zfsctl_freebsd_snapdir_mkdir, .vop_readdir = gfs_vop_readdir, .vop_lookup = zfsctl_snapdir_lookup, - .vop_inactive = zfsctl_snapdir_inactive, - .vop_reclaim = zfsctl_common_reclaim, + .vop_inactive = VOP_NULL, + .vop_reclaim = zfsctl_snapdir_inactive, .vop_fid = zfsctl_common_fid, }; @@ -1420,8 +1437,8 @@ static struct vop_vector zfsctl_ops_shares = { .vop_access = zfsctl_common_access, .vop_readdir = zfsctl_shares_readdir, .vop_lookup = zfsctl_shares_lookup, - .vop_inactive = gfs_vop_inactive, - .vop_reclaim = zfsctl_common_reclaim, + .vop_inactive = VOP_NULL, + .vop_reclaim = gfs_vop_inactive, .vop_fid = zfsctl_shares_fid, }; #endif /* !sun */ @@ -1444,32 +1461,44 @@ zfsctl_snapshot_mknode(vnode_t *pvp, uint64_t objset) VN_HOLD(vp); zcp = vp->v_data; zcp->zc_id = objset; - VOP_UNLOCK(vp, 0); return (vp); } + static int -zfsctl_snapshot_inactive(ap) +zfsctl_snapshot_freebsd_inactive(ap) struct vop_inactive_args /* { struct vnode *a_vp; struct thread *a_td; } */ *ap; { vnode_t *vp = ap->a_vp; + + vrecycle(vp); + return (0); +} + +static int +zfsctl_snapshot_inactive(ap) + struct vop_reclaim_args /* { + struct vnode *a_vp; + struct thread *a_td; + } */ *ap; +{ + vnode_t *vp = ap->a_vp; cred_t *cr = ap->a_td->td_ucred; - struct vop_inactive_args iap; + struct vop_reclaim_args iap; zfsctl_snapdir_t *sdp; zfs_snapentry_t *sep, *next; int locked; vnode_t *dvp; - if (vp->v_count > 0) + /* if snapdir is already reclaimed, just go to the end */ + if (gfs_dir_lookup(vp, "..", &dvp, cr, LK_EXCLUSIVE, NULL, NULL) != 0) goto end; - VERIFY(gfs_dir_lookup(vp, "..", &dvp, cr, 0, NULL, NULL) == 0); sdp = dvp->v_data; - VOP_UNLOCK(dvp, 0); if (!(locked = MUTEX_HELD(&sdp->sd_lock))) mutex_enter(&sdp->sd_lock); @@ -1492,6 +1521,7 @@ zfsctl_snapshot_inactive(ap) if (!locked) mutex_exit(&sdp->sd_lock); + VOP_UNLOCK(dvp, 0); VN_RELE(dvp); end: @@ -1503,14 +1533,19 @@ end: * creating a new vnode. */ iap.a_vp = vp; - return (gfs_vop_inactive(&iap)); + gfs_vop_inactive(&iap); + return (0); } static int zfsctl_traverse_begin(vnode_t **vpp, int lktype) { + int locked; - VN_HOLD(*vpp); + locked = VOP_ISLOCKED(*vpp); + ASSERT(locked == LK_EXCLUSIVE || locked == LK_SHARED); + /* traverse unlocks starting vnode, but we need to keep it locked */ + VERIFY(vget(*vpp, locked | LK_CANRECURSE, curthread) == 0); /* Snapshot should be already mounted, but just in case. */ if (vn_mountedvfs(*vpp) == NULL) return (ENOENT); @@ -1521,10 +1556,7 @@ static void zfsctl_traverse_end(vnode_t *vp, int err) { - if (err == 0) - vput(vp); - else - VN_RELE(vp); + vput(vp); } static int @@ -1538,7 +1570,7 @@ zfsctl_snapshot_getattr(ap) vnode_t *vp = ap->a_vp; int err; - err = zfsctl_traverse_begin(&vp, LK_SHARED | LK_RETRY); + err = zfsctl_traverse_begin(&vp, LK_SHARED); if (err == 0) err = VOP_GETATTR(vp, ap->a_vap, ap->a_cred); zfsctl_traverse_end(vp, err); @@ -1555,7 +1587,7 @@ zfsctl_snapshot_fid(ap) vnode_t *vp = ap->a_vp; int err; - err = zfsctl_traverse_begin(&vp, LK_SHARED | LK_RETRY); + err = zfsctl_traverse_begin(&vp, LK_SHARED); if (err == 0) err = VOP_VPTOFH(vp, (void *)ap->a_fid); zfsctl_traverse_end(vp, err); @@ -1575,6 +1607,7 @@ zfsctl_snapshot_lookup(ap) struct componentname *cnp = ap->a_cnp; cred_t *cr = ap->a_cnp->cn_cred; zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data; + int lkflags = ap->a_cnp->cn_lkflags; int error; if (cnp->cn_namelen != 2 || cnp->cn_nameptr[0] != '.' || @@ -1586,9 +1619,7 @@ zfsctl_snapshot_lookup(ap) ASSERT(zfsvfs->z_ctldir != NULL); error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", vpp, - NULL, 0, NULL, cr, NULL, NULL, NULL); - if (error == 0) - vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); + NULL, lkflags, NULL, cr, NULL, NULL, NULL); return (error); } @@ -1603,7 +1634,7 @@ zfsctl_snapshot_vptocnp(struct vop_vptocnp_args *ap) ASSERT(zfsvfs->z_ctldir != NULL); error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, - NULL, 0, NULL, kcred, NULL, NULL, NULL); + NULL, LK_EXCLUSIVE, NULL, kcred, NULL, NULL, NULL); if (error != 0) return (error); sdp = dvp->v_data; @@ -1629,6 +1660,7 @@ zfsctl_snapshot_vptocnp(struct vop_vptocnp_args *ap) vref(dvp); *ap->a_vpp = dvp; } + VOP_UNLOCK(dvp, 0); VN_RELE(dvp); return (error); @@ -1640,9 +1672,9 @@ zfsctl_snapshot_vptocnp(struct vop_vptocnp_args *ap) */ static struct vop_vector zfsctl_ops_snapshot = { .vop_default = &default_vnodeops, - .vop_inactive = zfsctl_snapshot_inactive, + .vop_inactive = zfsctl_snapshot_freebsd_inactive, .vop_lookup = zfsctl_snapshot_lookup, - .vop_reclaim = zfsctl_common_reclaim, + .vop_reclaim = zfsctl_snapshot_inactive, .vop_getattr = zfsctl_snapshot_getattr, .vop_fid = zfsctl_snapshot_fid, .vop_vptocnp = zfsctl_snapshot_vptocnp, @@ -1660,7 +1692,7 @@ zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp) ASSERT(zfsvfs->z_ctldir != NULL); error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, - NULL, 0, NULL, kcred, NULL, NULL, NULL); + NULL, LK_EXCLUSIVE, NULL, kcred, NULL, NULL, NULL); if (error != 0) return (error); sdp = dvp->v_data; @@ -1684,7 +1716,7 @@ zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp) * and returns the ZFS vnode mounted on top of the GFS node. * This ZFS vnode is the root of the vfs for objset 'objsetid'. */ - error = traverse(&vp, LK_SHARED | LK_RETRY); + error = traverse(&vp, LK_SHARED); if (error == 0) { if (vp == sep->se_root) error = SET_ERROR(EINVAL); @@ -1701,6 +1733,7 @@ zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp) mutex_exit(&sdp->sd_lock); } + VOP_UNLOCK(dvp, 0); VN_RELE(dvp); return (error); @@ -1722,7 +1755,7 @@ zfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr) ASSERT(zfsvfs->z_ctldir != NULL); error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp, - NULL, 0, NULL, cr, NULL, NULL, NULL); + NULL, LK_EXCLUSIVE, NULL, cr, NULL, NULL, NULL); if (error != 0) return (error); sdp = dvp->v_data; @@ -1759,6 +1792,7 @@ zfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr) } mutex_exit(&sdp->sd_lock); + VOP_UNLOCK(dvp, 0); VN_RELE(dvp); return (error); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c index 665627d..22e581a 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c @@ -2173,19 +2173,34 @@ zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, int flags, vnode_t **vpp) (zfsvfs->z_shares_dir != 0 && object == zfsvfs->z_shares_dir)) { *vpp = zfsvfs->z_ctldir; ASSERT(*vpp != NULL); + VN_HOLD(*vpp); + ZFS_EXIT(zfsvfs); if (object == ZFSCTL_INO_SNAPDIR) { - VERIFY(zfsctl_root_lookup(*vpp, "snapshot", vpp, NULL, - 0, NULL, NULL, NULL, NULL, NULL) == 0); + vnode_t *dvp = *vpp; + + err = vn_lock(dvp, LK_SHARED); + if (err == 0) { + err = zfsctl_root_lookup(dvp, "snapshot", vpp, + NULL, flags, NULL, NULL, NULL, NULL, NULL); + VOP_UNLOCK(dvp, 0); + } + VN_RELE(dvp); } else if (object == zfsvfs->z_shares_dir) { - VERIFY(zfsctl_root_lookup(*vpp, "shares", vpp, NULL, - 0, NULL, NULL, NULL, NULL, NULL) == 0); + vnode_t *dvp = *vpp; + + err = vn_lock(dvp, LK_SHARED); + if (err == 0) { + VERIFY(zfsctl_root_lookup(dvp, "shares", vpp, + NULL, flags, NULL, NULL, NULL, NULL, NULL) == 0); + } + VN_RELE(dvp); } else { - VN_HOLD(*vpp); + err = zfs_vnode_lock(*vpp, flags); + if (err != 0) { + VN_RELE(*vpp); + *vpp = NULL; + } } - ZFS_EXIT(zfsvfs); - err = vn_lock(*vpp, flags); - if (err != 0) - *vpp = NULL; return (err); } diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/gfs.h b/sys/cddl/contrib/opensolaris/uts/common/sys/gfs.h index f3fc634..77b74c2 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/gfs.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/gfs.h @@ -146,10 +146,10 @@ extern int gfs_get_parent_ino(vnode_t *, cred_t *, caller_context_t *, */ #define GFS_STATIC_ENTRY_OFFSET ((offset_t)2) -extern int gfs_lookup_dot(vnode_t **, vnode_t *, vnode_t *, const char *); +extern int gfs_lookup_dot(vnode_t **, vnode_t *, vnode_t *, const char *, int); extern int gfs_vop_readdir(struct vop_readdir_args *); -extern int gfs_vop_inactive(struct vop_inactive_args *); +extern int gfs_vop_inactive(struct vop_reclaim_args *); #ifdef __cplusplus