summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2009-03-11 14:13:47 +0000
committerjhb <jhb@FreeBSD.org>2009-03-11 14:13:47 +0000
commit520acdaf6926bd9375ce8e27092559997f111882 (patch)
tree9729e7549d110dca0074d289abb6591d48654669
parent8609dfd41ccae53505ee519fd6426fc876675ebd (diff)
downloadFreeBSD-src-520acdaf6926bd9375ce8e27092559997f111882.zip
FreeBSD-src-520acdaf6926bd9375ce8e27092559997f111882.tar.gz
Add a new internal mount flag (MNTK_EXTENDED_SHARED) to indicate that a
filesystem supports additional operations using shared vnode locks. Currently this is used to enable shared locks for open() and close() of read-only file descriptors. - When an ISOPEN namei() request is performed with LOCKSHARED, use a shared vnode lock for the leaf vnode only if the mount point has the extended shared flag set. - Set LOCKSHARED in vn_open_cred() for requests that specify O_RDONLY but not O_CREAT. - Use a shared vnode lock around VOP_CLOSE() if the file was opened with O_RDONLY and the mountpoint has the extended shared flag set. - Adjust md(4) to upgrade the vnode lock on the vnode it gets back from vn_open() since it now may only have a shared vnode lock. - Don't enable shared vnode locks on FIFO vnodes in ZFS and UFS since FIFO's require exclusive vnode locks for their open() and close() routines. (My recent MPSAFE patches for UDF and cd9660 already included this change.) - Enable extended shared operations on UFS, cd9660, and UDF. Submitted by: ups Reviewed by: pjd (ZFS bits) MFC after: 1 month
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c4
-rw-r--r--sys/dev/md/md.c30
-rw-r--r--sys/fs/cd9660/cd9660_vfsops.c3
-rw-r--r--sys/fs/udf/udf_vfsops.c3
-rw-r--r--sys/kern/vfs_lookup.c42
-rw-r--r--sys/kern/vfs_vnops.c14
-rw-r--r--sys/kern/vnode_if.src2
-rw-r--r--sys/sys/mount.h3
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c10
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
OpenPOWER on IntegriCloud