diff options
-rw-r--r-- | sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c | 4 | ||||
-rw-r--r-- | sys/dev/md/md.c | 30 | ||||
-rw-r--r-- | sys/fs/cd9660/cd9660_vfsops.c | 3 | ||||
-rw-r--r-- | sys/fs/udf/udf_vfsops.c | 3 | ||||
-rw-r--r-- | sys/kern/vfs_lookup.c | 42 | ||||
-rw-r--r-- | sys/kern/vfs_vnops.c | 14 | ||||
-rw-r--r-- | sys/kern/vnode_if.src | 2 | ||||
-rw-r--r-- | sys/sys/mount.h | 3 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 10 |
9 files changed, 86 insertions, 25 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c index 5687522..a6172f8 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c @@ -153,7 +153,6 @@ zfs_znode_cache_constructor(void *buf, void *arg, int kmflags) zp->z_vnode = vp; vp->v_data = (caddr_t)zp; VN_LOCK_AREC(vp); - VN_LOCK_ASHARE(vp); list_link_init(&zp->z_link_node); @@ -610,6 +609,8 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz) vp->v_op = &zfs_fifoops; break; } + if (vp->v_type != VFIFO) + VN_LOCK_ASHARE(vp); mutex_enter(&zfsvfs->z_znodes_lock); list_insert_tail(&zfsvfs->z_all_znodes, zp); @@ -1491,6 +1492,7 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx) vp = ZTOV(rootzp); vp->v_type = VDIR; + VN_LOCK_ASHARE(vp); bzero(&zfsvfs, sizeof (zfsvfs_t)); diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c index d3e3da8..48d48fd 100644 --- a/sys/dev/md/md.c +++ b/sys/dev/md/md.c @@ -924,12 +924,20 @@ mdcreate_vnode(struct md_s *sc, struct md_ioctl *mdio, struct thread *td) return (error); vfslocked = NDHASGIANT(&nd); NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_vp->v_type != VREG || - (error = VOP_GETATTR(nd.ni_vp, &vattr, td->td_ucred))) { - VOP_UNLOCK(nd.ni_vp, 0); - (void)vn_close(nd.ni_vp, flags, td->td_ucred, td); - VFS_UNLOCK_GIANT(vfslocked); - return (error ? error : EINVAL); + if (nd.ni_vp->v_type != VREG) { + error = EINVAL; + goto bad; + } + error = VOP_GETATTR(nd.ni_vp, &vattr, td->td_ucred); + if (error != 0) + goto bad; + if (VOP_ISLOCKED(nd.ni_vp) != LK_EXCLUSIVE) { + vn_lock(nd.ni_vp, LK_UPGRADE | LK_RETRY); + if (nd.ni_vp->v_iflag & VI_DOOMED) { + /* Forced unmount. */ + error = EBADF; + goto bad; + } } nd.ni_vp->v_vflag |= VV_MD; VOP_UNLOCK(nd.ni_vp, 0); @@ -948,13 +956,15 @@ mdcreate_vnode(struct md_s *sc, struct md_ioctl *mdio, struct thread *td) sc->vnode = NULL; vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY); nd.ni_vp->v_vflag &= ~VV_MD; - VOP_UNLOCK(nd.ni_vp, 0); - (void)vn_close(nd.ni_vp, flags, td->td_ucred, td); - VFS_UNLOCK_GIANT(vfslocked); - return (error); + goto bad; } VFS_UNLOCK_GIANT(vfslocked); return (0); +bad: + VOP_UNLOCK(nd.ni_vp, 0); + (void)vn_close(nd.ni_vp, flags, td->td_ucred, td); + VFS_UNLOCK_GIANT(vfslocked); + return (error); } static int diff --git a/sys/fs/cd9660/cd9660_vfsops.c b/sys/fs/cd9660/cd9660_vfsops.c index e6001eb..95a9a23 100644 --- a/sys/fs/cd9660/cd9660_vfsops.c +++ b/sys/fs/cd9660/cd9660_vfsops.c @@ -371,7 +371,8 @@ iso_mountfs(devvp, mp) mp->mnt_maxsymlinklen = 0; MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; - mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED; + mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED | + MNTK_EXTENDED_SHARED; MNT_IUNLOCK(mp); isomp->im_mountp = mp; isomp->im_dev = dev; diff --git a/sys/fs/udf/udf_vfsops.c b/sys/fs/udf/udf_vfsops.c index 98a2a13..8519a07 100644 --- a/sys/fs/udf/udf_vfsops.c +++ b/sys/fs/udf/udf_vfsops.c @@ -353,7 +353,8 @@ udf_mountfs(struct vnode *devvp, struct mount *mp) mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; - mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED; + mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED | + MNTK_EXTENDED_SHARED; MNT_IUNLOCK(mp); udfmp->im_mountp = mp; udfmp->im_dev = dev; diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index c4840ce..a21af4f 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -353,6 +353,41 @@ compute_cn_lkflags(struct mount *mp, int lkflags) return (lkflags); } +static __inline int +needs_exclusive_leaf(struct mount *mp, int flags) +{ + + /* + * Intermediate nodes can use shared locks, we only need to + * force an exclusive lock for leaf nodes. + */ + if ((flags & (ISLASTCN | LOCKLEAF)) != (ISLASTCN | LOCKLEAF)) + return (0); + + /* Always use exclusive locks if LOCKSHARED isn't set. */ + if (!(flags & LOCKSHARED)) + return (1); + + /* + * For lookups during open(), if the mount point supports + * extended shared operations, then use a shared lock for the + * leaf node, otherwise use an exclusive lock. + */ + if (flags & ISOPEN) { + if (mp != NULL && + (mp->mnt_kern_flag & MNTK_EXTENDED_SHARED)) + return (0); + else + return (1); + } + + /* + * Lookup requests outside of open() that specify LOCKSHARED + * only need a shared lock on the leaf vnode. + */ + return (1); +} + /* * Search a pathname. * This is a very central and rather complicated routine. @@ -610,8 +645,7 @@ unionlookup: * If we're looking up the last component and we need an exclusive * lock, adjust our lkflags. */ - if ((cnp->cn_flags & (ISLASTCN|LOCKSHARED|LOCKLEAF)) == - (ISLASTCN|LOCKLEAF)) + if (needs_exclusive_leaf(dp->v_mount, cnp->cn_flags)) cnp->cn_lkflags = LK_EXCLUSIVE; #ifdef NAMEI_DIAGNOSTIC vprint("lookup in", dp); @@ -811,8 +845,8 @@ success: * Because of lookup_shared we may have the vnode shared locked, but * the caller may want it to be exclusively locked. */ - if ((cnp->cn_flags & (ISLASTCN | LOCKSHARED | LOCKLEAF)) == - (ISLASTCN | LOCKLEAF) && VOP_ISLOCKED(dp) != LK_EXCLUSIVE) { + if (needs_exclusive_leaf(dp->v_mount, cnp->cn_flags) && + VOP_ISLOCKED(dp) != LK_EXCLUSIVE) { vn_lock(dp, LK_UPGRADE | LK_RETRY); if (dp->v_iflag & VI_DOOMED) { error = ENOENT; diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index e210fee..681c0eb 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -188,6 +188,8 @@ restart: ndp->ni_cnd.cn_flags = ISOPEN | ((fmode & O_NOFOLLOW) ? NOFOLLOW : FOLLOW) | LOCKLEAF | MPSAFE | AUDITVNODE1; + if (!(fmode & FWRITE)) + ndp->ni_cnd.cn_flags |= LOCKSHARED; if ((error = namei(ndp)) != 0) return (error); if (!mpsafe) @@ -240,7 +242,7 @@ restart: if (fmode & FWRITE) vp->v_writecount++; *flagp = fmode; - ASSERT_VOP_ELOCKED(vp, "vn_open_cred"); + ASSERT_VOP_LOCKED(vp, "vn_open_cred"); if (!mpsafe) VFS_UNLOCK_GIANT(vfslocked); return (0); @@ -285,12 +287,18 @@ vn_close(vp, flags, file_cred, td) struct thread *td; { struct mount *mp; - int error; + int error, lock_flags; + + if (!(flags & FWRITE) && vp->v_mount != NULL && + vp->v_mount->mnt_kern_flag & MNTK_EXTENDED_SHARED) + lock_flags = LK_SHARED; + else + lock_flags = LK_EXCLUSIVE; VFS_ASSERT_GIANT(vp->v_mount); vn_start_write(vp, &mp, V_WAIT); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + vn_lock(vp, lock_flags | LK_RETRY); if (flags & FWRITE) { VNASSERT(vp->v_writecount > 0, vp, ("vn_close: negative writecount")); diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src index ad4d1f7..0e198bf 100644 --- a/sys/kern/vnode_if.src +++ b/sys/kern/vnode_if.src @@ -133,7 +133,7 @@ vop_open { }; -%% close vp E E E +%% close vp L L L vop_close { IN struct vnode *vp; diff --git a/sys/sys/mount.h b/sys/sys/mount.h index f83686c..45f21bc 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -324,14 +324,15 @@ void __mnt_vnode_markerfree(struct vnode **mvp, struct mount *mp); #define MNTK_NOINSMNTQ 0x00000008 /* insmntque is not allowed */ #define MNTK_DRAINING 0x00000010 /* lock draining is happening */ #define MNTK_REFEXPIRE 0x00000020 /* refcount expiring is happening */ +#define MNTK_EXTENDED_SHARED 0x00000040 /* Allow shared locking for more ops */ #define MNTK_UNMOUNT 0x01000000 /* unmount in progress */ #define MNTK_MWAIT 0x02000000 /* waiting for unmount to finish */ #define MNTK_SUSPEND 0x08000000 /* request write suspension */ #define MNTK_SUSPEND2 0x04000000 /* block secondary writes */ #define MNTK_SUSPENDED 0x10000000 /* write operations are suspended */ #define MNTK_MPSAFE 0x20000000 /* Filesystem is MPSAFE. */ -#define MNTK_NOKNOTE 0x80000000 /* Don't send KNOTEs from VOP hooks */ #define MNTK_LOOKUP_SHARED 0x40000000 /* FS supports shared lock lookups */ +#define MNTK_NOKNOTE 0x80000000 /* Don't send KNOTEs from VOP hooks */ /* * Sysctl CTL_VFS definitions. diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 3913d79..c6de7df 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -883,7 +883,8 @@ ffs_mountfs(devvp, mp, td) * Initialize filesystem stat information in mount struct. */ MNT_ILOCK(mp); - mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED; + mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED | + MNTK_EXTENDED_SHARED; MNT_IUNLOCK(mp); #ifdef UFS_EXTATTR #ifdef UFS_EXTATTR_AUTOSTART @@ -1440,10 +1441,9 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags) return (error); } /* - * FFS supports recursive and shared locking. + * FFS supports recursive locking. */ VN_LOCK_AREC(vp); - VN_LOCK_ASHARE(vp); vp->v_data = ip; vp->v_bufobj.bo_bsize = fs->fs_bsize; ip->i_vnode = vp; @@ -1516,6 +1516,10 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags) /* * Finish inode initialization. */ + if (vp->v_type != VFIFO) { + /* FFS supports shared locking for all files except fifos. */ + VN_LOCK_ASHARE(vp); + } /* * Set up a generation number for this inode if it does not |