diff options
-rw-r--r-- | sys/conf/options | 1 | ||||
-rw-r--r-- | sys/kern/vfs_cache.c | 63 | ||||
-rw-r--r-- | sys/kern/vfs_extattr.c | 5 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 5 | ||||
-rw-r--r-- | sys/kern/vfs_vnops.c | 34 | ||||
-rw-r--r-- | sys/sys/namei.h | 7 |
6 files changed, 112 insertions, 3 deletions
diff --git a/sys/conf/options b/sys/conf/options index c3101df..fede7fd 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -383,6 +383,7 @@ BLKDEV_IOSIZE opt_global.h DEBUG opt_global.h DEBUG_LOCKS opt_global.h DEBUG_VFS_LOCKS opt_global.h +LOOKUP_SHARED opt_global.h DIAGNOSTIC opt_global.h ENABLE_VFS_IOOPT opt_global.h INVARIANT_SUPPORT opt_global.h diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 08e0397..529efd1 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -570,8 +570,35 @@ vfs_cache_lookup(ap) error = cache_lookup(dvp, vpp, cnp); +#ifdef LOOKUP_SHARED + if (!error) { + /* We do this because the rest of the system now expects to get + * a shared lock, which is later upgraded if LOCKSHARED is not + * set. We have so many cases here because of bugs that yield + * inconsistant lock states. This all badly needs to be fixed + */ + error = VOP_CACHEDLOOKUP(dvp, vpp, cnp); + if (!error) { + int flock; + + flock = VOP_ISLOCKED(*vpp, td); + if (flock != LK_EXCLUSIVE) { + if (flock == 0) { + if ((flags & ISLASTCN) && + (flags & LOCKSHARED)) + VOP_LOCK(*vpp, LK_SHARED, td); + else + VOP_LOCK(*vpp, LK_EXCLUSIVE, td); + } + } else if ((flags & ISLASTCN) && (flags & LOCKSHARED)) + VOP_LOCK(*vpp, LK_DOWNGRADE, td); + } + return (error); + } +#else if (!error) return (VOP_CACHEDLOOKUP(dvp, vpp, cnp)); +#endif if (error == ENOENT) return (error); @@ -585,13 +612,28 @@ vfs_cache_lookup(ap) } else if (flags & ISDOTDOT) { VOP_UNLOCK(dvp, 0, td); cnp->cn_flags |= PDIRUNLOCK; +#ifdef LOOKUP_SHARED + if ((flags & ISLASTCN) && (flags & LOCKSHARED)) + error = vget(vp, LK_SHARED, td); + else + error = vget(vp, LK_EXCLUSIVE, td); +#else error = vget(vp, LK_EXCLUSIVE, td); +#endif + if (!error && lockparent && (flags & ISLASTCN)) { if ((error = vn_lock(dvp, LK_EXCLUSIVE, td)) == 0) cnp->cn_flags &= ~PDIRUNLOCK; } } else { +#ifdef LOOKUP_SHARED + if ((flags & ISLASTCN) && (flags & LOCKSHARED)) + error = vget(vp, LK_SHARED, td); + else + error = vget(vp, LK_EXCLUSIVE, td); +#else error = vget(vp, LK_EXCLUSIVE, td); +#endif if (!lockparent || error || !(flags & ISLASTCN)) { VOP_UNLOCK(dvp, 0, td); cnp->cn_flags |= PDIRUNLOCK; @@ -616,7 +658,28 @@ vfs_cache_lookup(ap) return (error); cnp->cn_flags &= ~PDIRUNLOCK; } +#ifdef LOOKUP_SHARED + error = VOP_CACHEDLOOKUP(dvp, vpp, cnp); + + if (!error) { + int flock = 0; + + flock = VOP_ISLOCKED(*vpp, td); + if (flock != LK_EXCLUSIVE) { + if (flock == 0) { + if ((flags & ISLASTCN) && (flags & LOCKSHARED)) + VOP_LOCK(*vpp, LK_SHARED, td); + else + VOP_LOCK(*vpp, LK_EXCLUSIVE, td); + } + } else if ((flags & ISLASTCN) && (flags & LOCKSHARED)) + VOP_LOCK(*vpp, LK_DOWNGRADE, td); + } + + return (error); +#else return (VOP_CACHEDLOOKUP(dvp, vpp, cnp)); +#endif } diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index fd22602..31b1244 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -2029,8 +2029,13 @@ stat(td, uap) int error; struct nameidata nd; +#ifdef LOOKUP_SHARED + NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ, + UIO_USERSPACE, SCARG(uap, path), td); +#else NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, SCARG(uap, path), td); +#endif if ((error = namei(&nd)) != 0) return (error); error = vn_stat(nd.ni_vp, &sb, td); diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index fd22602..31b1244 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -2029,8 +2029,13 @@ stat(td, uap) int error; struct nameidata nd; +#ifdef LOOKUP_SHARED + NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ, + UIO_USERSPACE, SCARG(uap, path), td); +#else NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, SCARG(uap, path), td); +#endif if ((error = namei(&nd)) != 0) return (error); error = vn_stat(nd.ni_vp, &sb, td); diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 461cb1e..336086c 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -105,6 +105,11 @@ vn_open_cred(ndp, flagp, cmode, cred) struct vattr vat; struct vattr *vap = &vat; int mode, fmode, error; +#ifdef LOOKUP_SHARED + int exclusive; /* The current intended lock state */ + + exclusive = 0; +#endif restart: fmode = *flagp; @@ -143,6 +148,9 @@ restart: ASSERT_VOP_LOCKED(ndp->ni_vp, "create"); fmode &= ~O_TRUNC; vp = ndp->ni_vp; +#ifdef LOOKUP_SHARED + exclusive = 1; +#endif } else { if (ndp->ni_dvp == ndp->ni_vp) vrele(ndp->ni_dvp); @@ -158,8 +166,14 @@ restart: } } else { ndp->ni_cnd.cn_nameiop = LOOKUP; +#ifdef LOOKUP_SHARED + ndp->ni_cnd.cn_flags = + ((fmode & O_NOFOLLOW) ? NOFOLLOW : FOLLOW) | + LOCKSHARED | LOCKLEAF; +#else ndp->ni_cnd.cn_flags = ((fmode & O_NOFOLLOW) ? NOFOLLOW : FOLLOW) | LOCKLEAF; +#endif if ((error = namei(ndp)) != 0) return (error); vp = ndp->ni_vp; @@ -198,6 +212,21 @@ restart: * Make sure that a VM object is created for VMIO support. */ if (vn_canvmio(vp) == TRUE) { +#ifdef LOOKUP_SHARED + int flock; + + if (!exclusive && vp->v_object == NULL) + VOP_LOCK(vp, LK_UPGRADE, td); + /* + * In cases where the object is marked as dead object_create + * will unlock and relock exclusive. It is safe to call in + * here with a shared lock because we only examine fields that + * the shared lock guarantees will be stable. In the UPGRADE + * case it is not likely that anyone has used this vnode yet + * so there will be no contention. The logic after this call + * restores the requested locking state. + */ +#endif if ((error = vfs_object_create(vp, td, cred)) != 0) { VOP_UNLOCK(vp, 0, td); VOP_CLOSE(vp, fmode, cred, td); @@ -206,6 +235,11 @@ restart: *flagp = fmode; return (error); } +#ifdef LOOKUP_SHARED + flock = VOP_ISLOCKED(vp, td); + if (!exclusive && flock == LK_EXCLUSIVE) + VOP_LOCK(vp, LK_DOWNGRADE, td); +#endif } if (fmode & FWRITE) diff --git a/sys/sys/namei.h b/sys/sys/namei.h index 5b133cc..1ae6120 100644 --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -113,8 +113,9 @@ struct nameidata { #define NOCACHE 0x0020 /* name must not be left in cache */ #define FOLLOW 0x0040 /* follow symbolic links */ #define NOOBJ 0x0080 /* don't create object */ +#define LOCKSHARED 0x0100 /* Shared lock leaf */ #define NOFOLLOW 0x0000 /* do not follow symbolic links (pseudo) */ -#define MODMASK 0x00fc /* mask of operational modifiers */ +#define MODMASK 0x01fc /* mask of operational modifiers */ /* * Namei parameter descriptors. * @@ -129,7 +130,6 @@ struct nameidata { * name being sought. The caller is responsible for releasing the * buffer and for vrele'ing ni_startdir. */ -#define NOCROSSMOUNT 0x000100 /* do not cross mount points */ #define RDONLY 0x000200 /* lookup with read-only semantics */ #define HASBUF 0x000400 /* has allocated pathname buffer */ #define SAVENAME 0x000800 /* save pathname buffer */ @@ -143,7 +143,8 @@ struct nameidata { #define WILLBEDIR 0x080000 /* new files will be dirs; allow trailing / */ #define ISUNICODE 0x100000 /* current component name is unicode*/ #define PDIRUNLOCK 0x200000 /* file system lookup() unlocked parent dir */ -#define PARAMASK 0x1fff00 /* mask of parameter descriptors */ +#define NOCROSSMOUNT 0x400000 /* do not cross mount points */ +#define PARAMASK 0x3ffe00 /* mask of parameter descriptors */ /* * Initialization of an nameidata structure. |