kernel - Performance tuning
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 9 Nov 2013 04:59:32 +0000 (20:59 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 9 Nov 2013 04:59:32 +0000 (20:59 -0800)
* Use a shared lock in the exec*() code, open, close, chdir, fchdir,
  access, stat, and readlink.

* Adjust nlookup() to allow the last namecache record in a path to be
  locked shared if it is already resolved, and the caller requests it.

* Remove nearly all global locks from critical dsched paths.  Defer
  creation of the tdio until an I/O actually occurs (huge savings in
  the fork/exit paths).

* Improves fork/exec concurrency on monster of static binaries from
  14200/sec to 55000/sec+.  For dynamic binaries improve from around
  2500/sec to 9000/sec or so (48 cores fork/exec'ing different dynamic
  binaries).  For the same dynamic binary it's more around 5000/sec or
  so.

  Lots of issues here including the fact that all dynamic binaries load
  many shared resources, even hen the binaries are different programs.
  AKA libc.so.X and ld-elf.so.2, as well as /dev/urandom (from libc),
  and access numerous common path elements.

  Nearly all of these paths are now non-contending.  The major remaining
  contention is in per-vm_page/PMAP manipulation.  This is per-page and
  concurrent execs of the same program tend to pipeline so it isn't a
  big problem.

29 files changed:
sys/kern/imgact_elf.c
sys/kern/kern_dsched.c
sys/kern/kern_exec.c
sys/kern/vfs_cache.c
sys/kern/vfs_default.c
sys/kern/vfs_nlookup.c
sys/kern/vfs_syscalls.c
sys/kern/vfs_vnops.c
sys/sys/dsched.h
sys/sys/nlookup.h
sys/vfs/deadfs/dead_vnops.c
sys/vfs/devfs/devfs_vnops.c
sys/vfs/dirfs/dirfs_vnops.c
sys/vfs/hammer/hammer_ondisk.c
sys/vfs/hammer/hammer_volume.c
sys/vfs/hammer2/hammer2_vfsops.c
sys/vfs/hpfs/hpfs_vfsops.c
sys/vfs/isofs/cd9660/cd9660_vfsops.c
sys/vfs/msdosfs/msdosfs_vfsops.c
sys/vfs/nfs/nfs_vnops.c
sys/vfs/ntfs/ntfs_vfsops.c
sys/vfs/nwfs/nwfs_vnops.c
sys/vfs/procfs/procfs_vnops.c
sys/vfs/puffs/puffs_vnops.c
sys/vfs/smbfs/smbfs_vnops.c
sys/vfs/udf/udf_vfsops.c
sys/vfs/ufs/ffs_vfsops.c
sys/vfs/union/union_subr.c
sys/vfs/union/union_vnops.c

index cf2e555..33b1c0a 100644 (file)
@@ -439,7 +439,8 @@ __elfN(load_file)(struct proc *p, const char *file, u_long *addr, u_long *entry)
        if (error == 0)
                error = nlookup(nd);
        if (error == 0)
-               error = cache_vget(&nd->nl_nch, nd->nl_cred, LK_EXCLUSIVE, &imgp->vp);
+               error = cache_vget(&nd->nl_nch, nd->nl_cred,
+                                  LK_SHARED, &imgp->vp);
        topmnt = nd->nl_nch.mount;
        nlookup_done(nd);
        if (error)
index c3a8196..fd802e2 100644 (file)
@@ -67,6 +67,10 @@ static void dsched_disk_ctx_destroy(struct dsched_disk_ctx *diskctx);
 static void dsched_thread_io_destroy(struct dsched_thread_io *tdio);
 static void dsched_thread_ctx_destroy(struct dsched_thread_ctx *tdctx);
 
+static struct dsched_thread_io *dsched_thread_io_alloc(
+               struct disk *dp, struct dsched_thread_ctx *tdctx,
+               struct dsched_policy *pol, int tdctx_locked);
+
 static int     dsched_inited = 0;
 static int     default_set = 0;
 
@@ -86,9 +90,6 @@ static struct objcache        *dsched_diskctx_cache;
 static struct objcache *dsched_tdctx_cache;
 static struct objcache *dsched_tdio_cache;
 
-TAILQ_HEAD(, dsched_thread_ctx)        dsched_tdctx_list =
-               TAILQ_HEAD_INITIALIZER(dsched_tdctx_list);
-
 struct lock    dsched_tdctx_lock;
 
 static struct dsched_policy_head dsched_policy_list =
@@ -256,15 +257,27 @@ dsched_disk_destroy_callback(struct disk *dp)
 }
 
 
+/*
+ * Caller must have dp->diskctx locked
+ */
 void
 dsched_queue(struct disk *dp, struct bio *bio)
 {
        struct dsched_thread_ctx        *tdctx;
        struct dsched_thread_io         *tdio;
        struct dsched_disk_ctx          *diskctx;
+       int     found;
+       int     error;
 
-       int found = 0, error = 0;
+       if (dp->d_sched_policy == &dsched_noop_policy) {
+               dsched_clr_buf_priv(bio->bio_buf);
+               atomic_add_int(&dsched_stats.no_tdctx, 1);
+               dsched_strategy_raw(dp, bio);
+               return;
+       }
 
+       found = 0;
+       error = 0;
        tdctx = dsched_get_buf_priv(bio->bio_buf);
        if (tdctx == NULL) {
                /* We don't handle this case, let dsched dispatch */
@@ -275,7 +288,6 @@ dsched_queue(struct disk *dp, struct bio *bio)
 
        DSCHED_THREAD_CTX_LOCK(tdctx);
 
-       KKASSERT(!TAILQ_EMPTY(&tdctx->tdio_list));
        /*
         * XXX:
         * iterate in reverse to make sure we find the most up-to-date
@@ -285,10 +297,13 @@ dsched_queue(struct disk *dp, struct bio *bio)
        TAILQ_FOREACH_REVERSE(tdio, &tdctx->tdio_list, tdio_list_head, link) {
                if (tdio->dp == dp) {
                        dsched_thread_io_ref(tdio);
-                       found = 1;
                        break;
                }
        }
+       if (tdio == NULL) {
+               tdio = dsched_thread_io_alloc(dp, tdctx, dp->d_sched_policy, 1);
+               dsched_thread_io_ref(tdio);
+       }
 
        DSCHED_THREAD_CTX_UNLOCK(tdctx);
        dsched_clr_buf_priv(bio->bio_buf);
@@ -419,10 +434,10 @@ dsched_set_policy(struct disk *dp, struct dsched_policy *new_policy)
        policy_new(dp, new_policy);
        new_policy->prepare(dsched_get_disk_priv(dp));
        dp->d_sched_policy = new_policy;
+       atomic_add_int(&new_policy->ref_count, 1);
 
        DSCHED_GLOBAL_THREAD_CTX_UNLOCK();
 
-       atomic_add_int(&new_policy->ref_count, 1);
        kprintf("disk scheduler: set policy of %s to %s\n", dp->d_cdev->si_name,
            new_policy->name);
 
@@ -936,12 +951,6 @@ dsched_thread_ctx_destroy(struct dsched_thread_ctx *tdctx)
 {
        struct dsched_thread_io *tdio;
 
-#if 0
-       kprintf("tdctx (%p) destruction started, trace:\n", tdctx);
-       print_backtrace(8);
-#endif
-       DSCHED_GLOBAL_THREAD_CTX_LOCK();
-
        lockmgr(&tdctx->lock, LK_EXCLUSIVE);
 
        while ((tdio = TAILQ_FIRST(&tdctx->tdio_list)) != NULL) {
@@ -954,12 +963,9 @@ dsched_thread_ctx_destroy(struct dsched_thread_ctx *tdctx)
                lockmgr(&tdctx->lock, LK_EXCLUSIVE);
        }
        KKASSERT(tdctx->refcount == 0x80000000);
-       TAILQ_REMOVE(&dsched_tdctx_list, tdctx, link);
 
        lockmgr(&tdctx->lock, LK_RELEASE);
 
-       DSCHED_GLOBAL_THREAD_CTX_UNLOCK();
-
        objcache_put(dsched_tdctx_cache, tdctx);
        atomic_subtract_int(&dsched_stats.tdctx_allocations, 1);
 }
@@ -967,15 +973,16 @@ dsched_thread_ctx_destroy(struct dsched_thread_ctx *tdctx)
 /*
  * Ensures that a tdio is assigned to tdctx and disk.
  */
-void
+static
+struct dsched_thread_io *
 dsched_thread_io_alloc(struct disk *dp, struct dsched_thread_ctx *tdctx,
-                      struct dsched_policy *pol)
+                      struct dsched_policy *pol, int tdctx_locked)
 {
        struct dsched_thread_io *tdio;
 #if 0
        dsched_disk_ctx_ref(dsched_get_disk_priv(dp));
 #endif
-       tdio = objcache_get(dsched_tdio_cache, M_WAITOK);
+       tdio = objcache_get(dsched_tdio_cache, M_INTWAIT);
        bzero(tdio, DSCHED_THREAD_IO_MAX_SZ);
 
        dsched_thread_io_ref(tdio);     /* prevent ripout */
@@ -993,19 +1000,20 @@ dsched_thread_io_alloc(struct disk *dp, struct dsched_thread_ctx *tdctx,
        lockmgr(&tdio->diskctx->lock, LK_EXCLUSIVE);
        TAILQ_INSERT_TAIL(&tdio->diskctx->tdio_list, tdio, dlink);
        atomic_set_int(&tdio->flags, DSCHED_LINKED_DISK_CTX);
-       lockmgr(&tdio->diskctx->lock, LK_RELEASE);
 
        if (tdctx) {
                /*
                 * Put the tdio in the tdctx list.  Inherit the temporary
                 * ref (one ref for each list).
                 */
-               DSCHED_THREAD_CTX_LOCK(tdctx);
+               if (tdctx_locked == 0)
+                       DSCHED_THREAD_CTX_LOCK(tdctx);
                tdio->tdctx = tdctx;
                tdio->p = tdctx->p;
                TAILQ_INSERT_TAIL(&tdctx->tdio_list, tdio, link);
                atomic_set_int(&tdio->flags, DSCHED_LINKED_THREAD_CTX);
-               DSCHED_THREAD_CTX_UNLOCK(tdctx);
+               if (tdctx_locked == 0)
+                       DSCHED_THREAD_CTX_UNLOCK(tdctx);
        } else {
                dsched_thread_io_unref(tdio);
        }
@@ -1014,6 +1022,8 @@ dsched_thread_io_alloc(struct disk *dp, struct dsched_thread_ctx *tdctx,
        tdio->debug_inited = 0xF00F1234;
 
        atomic_add_int(&dsched_stats.tdio_allocations, 1);
+
+       return(tdio);
 }
 
 
@@ -1047,8 +1057,6 @@ struct dsched_thread_ctx *
 dsched_thread_ctx_alloc(struct proc *p)
 {
        struct dsched_thread_ctx        *tdctx;
-       struct disk marker;
-       struct disk *dp;
 
        tdctx = objcache_get(dsched_tdctx_cache, M_WAITOK);
        bzero(tdctx, DSCHED_THREAD_CTX_MAX_SZ);
@@ -1060,33 +1068,20 @@ dsched_thread_ctx_alloc(struct proc *p)
        TAILQ_INIT(&tdctx->tdio_list);
        tdctx->p = p;
 
-       DSCHED_GLOBAL_THREAD_CTX_LOCK();
-       dp = NULL;
-       while ((dp = disk_enumerate(&marker, dp)) != NULL)
-               dsched_thread_io_alloc(dp, tdctx, dp->d_sched_policy);
-
-       TAILQ_INSERT_TAIL(&dsched_tdctx_list, tdctx, link);
-       DSCHED_GLOBAL_THREAD_CTX_UNLOCK();
-
        atomic_add_int(&dsched_stats.tdctx_allocations, 1);
        /* XXX: no callback here */
+
        return tdctx;
 }
 
 void
-policy_new(struct disk *dp, struct dsched_policy *pol) {
-       struct dsched_thread_ctx *tdctx;
+policy_new(struct disk *dp, struct dsched_policy *pol)
+{
        struct dsched_disk_ctx *diskctx;
 
        diskctx = dsched_disk_ctx_alloc(dp, pol);
        dsched_disk_ctx_ref(diskctx);
        dsched_set_disk_priv(dp, diskctx);
-
-       /*
-        * XXX this is really really expensive!
-        */
-       TAILQ_FOREACH(tdctx, &dsched_tdctx_list, link)
-               dsched_thread_io_alloc(dp, tdctx, pol);
 }
 
 void
@@ -1236,13 +1231,9 @@ dsched_new_policy_thread_tdio(struct dsched_disk_ctx *diskctx,
 {
        struct dsched_thread_ctx *tdctx;
 
-       DSCHED_GLOBAL_THREAD_CTX_LOCK();
-
        tdctx = dsched_get_thread_priv(curthread);
        KKASSERT(tdctx != NULL);
-       dsched_thread_io_alloc(diskctx->dp, tdctx, pol);
-
-       DSCHED_GLOBAL_THREAD_CTX_UNLOCK();
+       dsched_thread_io_alloc(diskctx->dp, tdctx, pol, 0);
 }
 
 /* DEFAULT NOOP POLICY */
@@ -1267,7 +1258,7 @@ noop_cancel(struct dsched_disk_ctx *diskctx)
 
 static int
 noop_queue(struct dsched_disk_ctx *diskctx, struct dsched_thread_io *tdio,
-    struct bio *bio)
+          struct bio *bio)
 {
        dsched_strategy_raw(diskctx->dp, bio);
 #if 0
index 28d0e00..3716370 100644 (file)
@@ -246,9 +246,10 @@ interpret:
         * Translate the file name to a vnode.  Unlock the cache entry to
         * improve parallelism for programs exec'd in parallel.
         */
+       nd->nl_flags |= NLC_SHAREDLOCK;
        if ((error = nlookup(nd)) != 0)
                goto exec_fail;
-       error = cache_vget(&nd->nl_nch, nd->nl_cred, LK_EXCLUSIVE, &imgp->vp);
+       error = cache_vget(&nd->nl_nch, nd->nl_cred, LK_SHARED, &imgp->vp);
        KKASSERT(nd->nl_flags & NLC_NCPISLOCKED);
        nd->nl_flags &= ~NLC_NCPISLOCKED;
        cache_unlock(&nd->nl_nch);
index b5b3e43..8349537 100644 (file)
@@ -1803,7 +1803,8 @@ _cache_unlink(struct namecache *ncp)
 
 /*
  * vget the vnode associated with the namecache entry.  Resolve the namecache
- * entry if necessary.  The passed ncp must be referenced and locked.
+ * entry if necessary.  The passed ncp must be referenced and locked.  If
+ * the ncp is resolved it might be locked shared.
  *
  * lk_type may be LK_SHARED, LK_EXCLUSIVE.  A ref'd, possibly locked
  * (depending on the passed lk_type) will be returned in *vpp with an error
@@ -1847,6 +1848,9 @@ again:
                if (error) {
                        /*
                         * VRECLAIM race
+                        *
+                        * The ncp may have been locked shared, we must relock
+                        * it exclusively before we can set it to unresolved.
                         */
                        if (error == ENOENT) {
                                kprintf("Warning: vnode reclaim race detected "
index af8634d..760d5f3 100644 (file)
@@ -1183,9 +1183,9 @@ vop_stdopen(struct vop_open_args *ap)
                vref(vp);
        }
        if (ap->a_mode & FWRITE)
-               ++vp->v_writecount;
+               atomic_add_int(&vp->v_writecount, 1);
        KKASSERT(vp->v_opencount >= 0 && vp->v_opencount != INT_MAX);
-       ++vp->v_opencount;
+       atomic_add_int(&vp->v_opencount, 1);
        return (0);
 }
 
@@ -1208,9 +1208,9 @@ vop_stdclose(struct vop_close_args *ap)
                KASSERT(vp->v_writecount > 0,
                        ("VOP_STDCLOSE: BAD WRITECOUNT %p %d",
                        vp, vp->v_writecount));
-               --vp->v_writecount;
+               atomic_add_int(&vp->v_writecount, -1);
        }
-       --vp->v_opencount;
+       atomic_add_int(&vp->v_opencount, -1);
        return (0);
 }
 
index bcc865a..c1a6c7d 100644 (file)
@@ -379,6 +379,37 @@ nlookup_simple(const char *str, enum uio_seg seg,
     return(nch);
 }
 
+/*
+ * Returns non-zero if the path element is the last element
+ */
+static
+int
+islastelement(const char *ptr)
+{
+       while (*ptr == '/')
+               ++ptr;
+       return (*ptr == 0);
+}
+
+/*
+ * Returns non-zero if we need to lock the namecache element
+ * exclusively.  Unless otherwise requested by NLC_SHAREDLOCK,
+ * the last element of the namecache lookup will be locked
+ * exclusively.
+ *
+ * NOTE: Even if we return on-zero, an unresolved namecache record
+ *      will always be locked exclusively.
+ */
+static __inline
+int
+wantsexcllock(struct nlookupdata *nd, const char *ptr)
+{
+       if ((nd->nl_flags & NLC_SHAREDLOCK) == 0)
+               return(islastelement(ptr));
+       return(0);
+}
+
+
 /*
  * Do a generic nlookup.  Note that the passed nd is not nlookup_done()'d
  * on return, even if an error occurs.  If no error occurs or NLC_CREATE
@@ -412,15 +443,6 @@ nlookup_simple(const char *str, enum uio_seg seg,
  *      on any intermediate elements.  On success, the returned element
  *      is ALWAYS locked exclusively.
  */
-static
-int
-islastelement(const char *ptr)
-{
-       while (*ptr == '/')
-               ++ptr;
-       return (*ptr == 0);
-}
-
 int
 nlookup(struct nlookupdata *nd)
 {
@@ -467,7 +489,7 @@ nlookup(struct nlookupdata *nd)
         */
        if ((nd->nl_flags & NLC_NCPISLOCKED) == 0) {
                nd->nl_flags |= NLC_NCPISLOCKED;
-               cache_lock_maybe_shared(&nd->nl_nch, islastelement(ptr));
+               cache_lock_maybe_shared(&nd->nl_nch, wantsexcllock(nd, ptr));
        }
 
        /*
@@ -482,7 +504,7 @@ nlookup(struct nlookupdata *nd)
            } while (*ptr == '/');
            cache_unlock(&nd->nl_nch);
            cache_get_maybe_shared(&nd->nl_rootnch, &nch,
-                                  islastelement(ptr));
+                                  wantsexcllock(nd, ptr));
            cache_drop(&nd->nl_nch);
            nd->nl_nch = nch;           /* remains locked */
 
@@ -550,7 +572,7 @@ nlookup(struct nlookupdata *nd)
        if (nlc.nlc_namelen == 1 && nlc.nlc_nameptr[0] == '.') {
            cache_unlock(&nd->nl_nch);
            nd->nl_flags &= ~NLC_NCPISLOCKED;
-           cache_get_maybe_shared(&nd->nl_nch, &nch, islastelement(ptr));
+           cache_get_maybe_shared(&nd->nl_nch, &nch, wantsexcllock(nd, ptr));
            wasdotordotdot = 1;
        } else if (nlc.nlc_namelen == 2 && 
                   nlc.nlc_nameptr[0] == '.' && nlc.nlc_nameptr[1] == '.') {
@@ -562,7 +584,8 @@ nlookup(struct nlookupdata *nd)
                 */
                cache_unlock(&nd->nl_nch);
                nd->nl_flags &= ~NLC_NCPISLOCKED;
-               cache_get_maybe_shared(&nd->nl_nch, &nch, islastelement(ptr));
+               cache_get_maybe_shared(&nd->nl_nch, &nch,
+                                      wantsexcllock(nd, ptr));
            } else {
                /*
                 * Locate the parent ncp.  If we are at the root of a
@@ -581,7 +604,7 @@ nlookup(struct nlookupdata *nd)
                cache_hold(&nctmp);
                cache_unlock(&nd->nl_nch);
                nd->nl_flags &= ~NLC_NCPISLOCKED;
-               cache_get_maybe_shared(&nctmp, &nch, islastelement(ptr));
+               cache_get_maybe_shared(&nctmp, &nch, wantsexcllock(nd, ptr));
                cache_drop(&nctmp);             /* NOTE: zero's nctmp */
            }
            wasdotordotdot = 2;
@@ -605,7 +628,7 @@ nlookup(struct nlookupdata *nd)
            cache_unlock(&nd->nl_nch);
            nd->nl_flags &= ~NLC_NCPISLOCKED;
            error = cache_nlookup_maybe_shared(&nd->nl_nch, &nlc,
-                                              islastelement(ptr), &nch);
+                                              wantsexcllock(nd, ptr), &nch);
            if (error == EWOULDBLOCK) {
                    nch = cache_nlookup(&nd->nl_nch, &nlc);
                    if (nch.ncp->nc_flag & NCF_UNRESOLVED)
@@ -640,7 +663,7 @@ nlookup(struct nlookupdata *nd)
            if ((par.ncp = nch.ncp->nc_parent) != NULL) {
                par.mount = nch.mount;
                cache_hold(&par);
-               cache_lock_maybe_shared(&par, islastelement(ptr));
+               cache_lock_maybe_shared(&par, wantsexcllock(nd, ptr));
                error = naccess(&par, 0, nd->nl_cred, &dflags);
                cache_put(&par);
            }
@@ -791,7 +814,7 @@ again:
                }
            }
            cache_get_maybe_shared(&mp->mnt_ncmountpt, &nch,
-                                  islastelement(ptr));
+                                  wantsexcllock(nd, ptr));
 
            if (nch.ncp->nc_flag & NCF_UNRESOLVED) {
                if (vfs_do_busy == 0) {
index 50992f1..b7ee2d1 100644 (file)
@@ -1565,7 +1565,7 @@ sys_fchdir(struct fchdir_args *uap)
        lwkt_gettoken(&p->p_token);
        vp = (struct vnode *)fp->f_data;
        vref(vp);
-       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+       vn_lock(vp, LK_SHARED | LK_RETRY);
        if (fp->f_nchandle.ncp == NULL)
                error = ENOTDIR;
        else
@@ -1624,6 +1624,7 @@ kern_chdir(struct nlookupdata *nd)
        struct nchandle onch;
        int error;
 
+       nd->nl_flags |= NLC_SHAREDLOCK;
        if ((error = nlookup(nd)) != 0)
                return (error);
        if ((vp = nd->nl_nch.ncp->nc_vp) == NULL)
@@ -1882,10 +1883,16 @@ kern_open(struct nlookupdata *nd, int oflags, int mode, int *res)
         * file pointer.  vn_open() does not change the ref count on fp
         * and the vnode, on success, will be inherited by the file pointer
         * and unlocked.
+        *
+        * Request a shared lock on the vnode if possible.
         */
        nd->nl_flags |= NLC_LOCKVP;
+       if ((flags & (O_CREAT|O_TRUNC)) == 0)
+               nd->nl_flags |= NLC_SHAREDLOCK;
+
        error = vn_open(nd, fp, flags, cmode);
        nlookup_done(nd);
+
        if (error) {
                /*
                 * handle special fdopen() case.  bleh.  dupfdopen() is
@@ -2628,10 +2635,11 @@ kern_access(struct nlookupdata *nd, int amode, int flags)
 
        if (flags & ~AT_EACCESS)
                return (EINVAL);
+       nd->nl_flags |= NLC_SHAREDLOCK;
        if ((error = nlookup(nd)) != 0)
                return (error);
 retry:
-       error = cache_vget(&nd->nl_nch, nd->nl_cred, LK_EXCLUSIVE, &vp);
+       error = cache_vget(&nd->nl_nch, nd->nl_cred, LK_SHARED, &vp);
        if (error)
                return (error);
 
@@ -2725,13 +2733,13 @@ sys_faccessat(struct faccessat_args *uap)
        return (error);
 }
 
-
 int
 kern_stat(struct nlookupdata *nd, struct stat *st)
 {
        int error;
        struct vnode *vp;
 
+       nd->nl_flags |= NLC_SHAREDLOCK;
        if ((error = nlookup(nd)) != 0)
                return (error);
 again:
@@ -2890,9 +2898,10 @@ kern_readlink(struct nlookupdata *nd, char *buf, int count, int *res)
        struct uio auio;
        int error;
 
+       nd->nl_flags |= NLC_SHAREDLOCK;
        if ((error = nlookup(nd)) != 0)
                return (error);
-       error = cache_vget(&nd->nl_nch, nd->nl_cred, LK_EXCLUSIVE, &vp);
+       error = cache_vget(&nd->nl_nch, nd->nl_cred, LK_SHARED, &vp);
        if (error)
                return (error);
        if (vp->v_type != VLNK) {
@@ -4709,7 +4718,7 @@ sys_extattr_get_file(struct extattr_get_file_args *uap)
        if (error == 0)
                error = nlookup(&nd);
        if (error == 0)
-               error = cache_vget(&nd.nl_nch, nd.nl_cred, LK_EXCLUSIVE, &vp);
+               error = cache_vget(&nd.nl_nch, nd.nl_cred, LK_SHARED, &vp);
        if (error) {
                nlookup_done(&nd);
                return (error);
index 99dcf30..33d42f2 100644 (file)
@@ -87,8 +87,12 @@ struct fileops vnode_fileops = {
  * locked vnode.  A locked vnode is requested via NLC_LOCKVP.  If fp
  * is non-NULL the vnode will be installed in the file pointer.
  *
+ * NOTE: If the caller wishes the namecache entry to be operated with
+ *      a shared lock it must use NLC_SHAREDLOCK.  If NLC_LOCKVP is set
+ *      then the vnode lock will also be shared.
+ *
  * NOTE: The vnode is referenced just once on return whether or not it
- * is also installed in the file pointer.
+ *      is also installed in the file pointer.
  */
 int
 vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode)
@@ -186,7 +190,12 @@ again:
                        fmode &= ~O_CREAT;
                }
        } else {
-               error = cache_vget(&nd->nl_nch, cred, LK_EXCLUSIVE, &vp);
+               if (nd->nl_flags & NLC_SHAREDLOCK) {
+                       error = cache_vget(&nd->nl_nch, cred, LK_SHARED, &vp);
+               } else {
+                       error = cache_vget(&nd->nl_nch, cred,
+                                          LK_EXCLUSIVE, &vp);
+               }
                if (error)
                        return (error);
        }
@@ -222,8 +231,13 @@ again:
                                if (error == ESTALE) {
                                        vput(vp);
                                        vp = NULL;
+                                       if (nd->nl_flags & NLC_SHAREDLOCK) {
+                                               cache_unlock(&nd->nl_nch);
+                                               cache_lock(&nd->nl_nch);
+                                       }
                                        cache_setunresolved(&nd->nl_nch);
-                                       error = cache_resolve(&nd->nl_nch, cred);
+                                       error = cache_resolve(&nd->nl_nch,
+                                                             cred);
                                        if (error == 0)
                                                goto again;
                                }
@@ -402,7 +416,7 @@ vn_close(struct vnode *vp, int flags)
 {
        int error;
 
-       error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+       error = vn_lock(vp, LK_SHARED | LK_RETRY);
        if (error == 0) {
                error = VOP_CLOSE(vp, flags);
                vn_unlock(vp);
index c964030..20025c1 100644 (file)
@@ -279,9 +279,6 @@ void        dsched_thread_ctx_unref(struct dsched_thread_ctx *tdctx);
 
 void   dsched_new_policy_thread_tdio(struct dsched_disk_ctx *diskctx,
                        struct dsched_policy *pol);
-void   dsched_thread_io_alloc(struct disk *dp,
-                       struct dsched_thread_ctx *tdctx,
-                       struct dsched_policy *pol);
 struct dsched_disk_ctx *dsched_disk_ctx_alloc(struct disk *dp,
                        struct dsched_policy *pol);
 struct dsched_thread_ctx *dsched_thread_ctx_alloc(struct proc *p);
index d058174..e503d24 100644 (file)
@@ -116,7 +116,7 @@ struct nlookupdata {
 #define NLC_TRUNCATE           0x00000800      /* do truncation checks */
 #define NLC_HLINK              0x00001000      /* do hardlink checks */
 #define NLC_RENAME_SRC         0x00002000      /* do rename checks (source) */
-#define NLC_UNUSED00004000     0x00004000
+#define NLC_SHAREDLOCK         0x00004000      /* allow shared ncp & vp lock */
 #define NLC_UNUSED00008000     0x00008000
 #define NLC_NFS_RDONLY         0x00010000      /* set by nfs_namei() only */
 #define NLC_NFS_NOSOFTLINKTRAV 0x00020000      /* do not traverse softlnks */
index 8e37661..1a379b7 100644 (file)
@@ -123,10 +123,11 @@ dead_close(struct vop_close_args *ap)
 {
        struct vnode *vp = ap->a_vp;
 
+       vn_lock(vp, LK_UPGRADE | LK_RETRY);     /* safety */
        if (vp->v_opencount > 0) {
                if ((ap->a_fflag & FWRITE) && vp->v_writecount > 0)
-                       --vp->v_writecount;
-               --vp->v_opencount;
+                       atomic_add_int(&vp->v_writecount, -1);
+               atomic_add_int(&vp->v_opencount, -1);
        }
        return (0);
 }
index 21f9907..975f0e4 100644 (file)
@@ -861,12 +861,15 @@ devfs_spec_open(struct vop_open_args *ap)
        if ((dev = vp->v_rdev) == NULL)
                return ENXIO;
 
+       vn_lock(vp, LK_UPGRADE | LK_RETRY);
+
        if (node && ap->a_fp) {
                devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_spec_open: -1.1-\n");
                lockmgr(&devfs_lock, LK_EXCLUSIVE);
 
-               ndev = devfs_clone(dev, node->d_dir.d_name, node->d_dir.d_namlen,
-                                               ap->a_mode, ap->a_cred);
+               ndev = devfs_clone(dev, node->d_dir.d_name,
+                                  node->d_dir.d_namlen,
+                                  ap->a_mode, ap->a_cred);
                if (ndev != NULL) {
                        newnode = devfs_create_device_node(
                                        DEVFS_MNTDATA(vp->v_mount)->root_node,
@@ -1003,7 +1006,6 @@ devfs_spec_open(struct vop_open_args *ap)
        return 0;
 }
 
-
 static int
 devfs_spec_close(struct vop_close_args *ap)
 {
@@ -1014,6 +1016,12 @@ devfs_spec_close(struct vop_close_args *ap)
        int error = 0;
        int needrelock;
 
+       /*
+        * We do special tests on the opencount so unfortunately we need
+        * an exclusive lock.
+        */
+       vn_lock(vp, LK_UPGRADE | LK_RETRY);
+
        if (dev)
                devfs_debug(DEVFS_DEBUG_DEBUG,
                            "devfs_spec_close() called on %s! \n",
index 2e0a92d..df08540 100644 (file)
@@ -348,6 +348,7 @@ dirfs_close(struct vop_close_args *ap)
         * XXX - Currently VOP_INACTIVE() is not being called unless there is
         * vnode pressure so, by now, call inactive directly on last close.
         */
+       vn_lock(vp, LK_UPGRADE | LK_RETRY);
        if (vp->v_opencount == 0 && vp->v_writecount == 0)
                VOP_INACTIVE(vp);
 
index e16f0ac..43b5866 100644 (file)
@@ -237,7 +237,9 @@ late_failure:
                /*vinvalbuf(volume->devvp, V_SAVE, 0, 0);*/
                if (setmp)
                        volume->devvp->v_rdev->si_mountpoint = NULL;
+               vn_lock(volume->devvp, LK_EXCLUSIVE | LK_RETRY);
                VOP_CLOSE(volume->devvp, ronly ? FREAD : FREAD|FWRITE);
+               vn_unlock(volume->devvp);
                hammer_free_volume(volume);
        }
        return (error);
@@ -324,15 +326,19 @@ hammer_unload_volume(hammer_volume_t volume, void *data __unused)
                         * (2).  Note that there may be dirty buffers in
                         * normal read-only mode from crash recovery.
                         */
+                       vn_lock(volume->devvp, LK_EXCLUSIVE | LK_RETRY);
                        vinvalbuf(volume->devvp, 0, 0, 0);
                        VOP_CLOSE(volume->devvp, FREAD);
+                       vn_unlock(volume->devvp);
                } else {
                        /*
                         * Normal termination, save any dirty buffers
                         * (XXX there really shouldn't be any).
                         */
+                       vn_lock(volume->devvp, LK_EXCLUSIVE | LK_RETRY);
                        vinvalbuf(volume->devvp, V_SAVE, 0, 0);
                        VOP_CLOSE(volume->devvp, FREAD|FWRITE);
+                       vn_unlock(volume->devvp);
                }
        }
 
index 0b1251d..5b3905a 100644 (file)
@@ -782,8 +782,10 @@ static void
 hammer_close_device(struct vnode **devvpp, int ronly)
 {
        if (*devvpp) {
+               vn_lock(*devvpp, LK_EXCLUSIVE | LK_RETRY);
                vinvalbuf(*devvpp, ronly ? 0 : V_SAVE, 0, 0);
                VOP_CLOSE(*devvpp, (ronly ? FREAD : FREAD|FWRITE));
+               vn_unlock(*devvpp);
                vrele(*devvpp);
                *devvpp = NULL;
        }
index 1c723e2..7ec4a77 100644 (file)
@@ -1471,10 +1471,12 @@ hammer2_vfs_unmount(struct mount *mp, int mntflags)
                         * Finish up with the device vnode
                         */
                        if ((devvp = hmp->devvp) != NULL) {
+                               vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
                                vinvalbuf(devvp, (ronly ? 0 : V_SAVE), 0, 0);
                                hmp->devvp = NULL;
                                VOP_CLOSE(devvp,
                                          (ronly ? FREAD : FREAD|FWRITE));
+                               vn_unlock(devvp);
                                vrele(devvp);
                                devvp = NULL;
                        }
index 7031e4c..ed9c894 100644 (file)
@@ -332,7 +332,9 @@ failed:
                brelse (bp);
        mp->mnt_data = NULL;
        dev->si_mountpoint = NULL;
+       vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
        VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE);
+       vn_unlock(devvp);
        return (error);
 }
 
@@ -361,8 +363,10 @@ hpfs_unmount(struct mount *mp, int mntflags)
 
        hpmp->hpm_devvp->v_rdev->si_mountpoint = NULL;
 
+       vn_lock(hpmp->hpm_devvp, LK_EXCLUSIVE | LK_RETRY);
        vinvalbuf(hpmp->hpm_devvp, V_SAVE, 0, 0);
        error = VOP_CLOSE(hpmp->hpm_devvp, ronly ? FREAD : FREAD|FWRITE);
+       vn_unlock(hpmp->hpm_devvp);
 
        vrele(hpmp->hpm_devvp);
 
index 512adc7..d8763ea 100644 (file)
@@ -165,7 +165,9 @@ iso_mountroot(struct mount *mp)
 
        args.ssector = iso_get_ssector(rootdev);
 
+       vn_lock(rootvp, LK_EXCLUSIVE | LK_RETRY);
        VOP_CLOSE(rootvp, FREAD);
+       vn_unlock(rootvp);
 
        if (bootverbose)
                kprintf("iso_mountroot(): using session at block %d\n",
@@ -535,8 +537,11 @@ out:
                brelse(pribp);
        if (supbp)
                brelse(supbp);
-       if (needclose)
+       if (needclose) {
+               vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
                VOP_CLOSE(devvp, FREAD);
+               vn_unlock(devvp);
+       }
        if (isomp) {
                kfree((caddr_t)isomp, M_ISOFSMNT);
                mp->mnt_data = (qaddr_t)0;
@@ -573,7 +578,9 @@ cd9660_unmount(struct mount *mp, int mntflags)
         }
 
        isomp->im_devvp->v_rdev->si_mountpoint = NULL;
+       vn_lock(isomp->im_devvp, LK_EXCLUSIVE | LK_RETRY);
        error = VOP_CLOSE(isomp->im_devvp, FREAD);
+       vn_unlock(isomp->im_devvp);
        vrele(isomp->im_devvp);
        kfree((caddr_t)isomp, M_ISOFSMNT);
        mp->mnt_data = (qaddr_t)0;
index 4e56563..b5ccce9 100644 (file)
@@ -196,8 +196,10 @@ msdosfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
                        error = vflush(mp, 0, flags);
                        if (error == 0) {
                                devvp = pmp->pm_devvp;
+                               vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
                                VOP_OPEN(devvp, FREAD, FSCRED, NULL);
                                VOP_CLOSE(devvp, FREAD|FWRITE);
+                               vn_unlock(devvp);
                                pmp->pm_flags |= MSDOSFSMNT_RONLY;
                        }
                }
@@ -612,7 +614,9 @@ error_exit:
                bp->b_flags |= B_RELBUF;
                brelse(bp);
        }
+       vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
        VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE);
+       vn_unlock(devvp);
        if (pmp) {
                if (pmp->pm_inusemap)
                        kfree(pmp->pm_inusemap, M_MSDOSFSFAT);
@@ -671,8 +675,10 @@ msdosfs_unmount(struct mount *mp, int mntflags)
                    ((u_int *)vp->v_data)[1]);
        }
 #endif
+       vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY);
        error = VOP_CLOSE(pmp->pm_devvp,
                    (pmp->pm_flags&MSDOSFSMNT_RONLY) ? FREAD : FREAD | FWRITE);
+       vn_unlock(pmp->pm_devvp);
        vrele(pmp->pm_devvp);
        kfree(pmp->pm_inusemap, M_MSDOSFSFAT);
        kfree(pmp, M_MSDOSFSMNT);
index 2ef7999..c4cf40a 100644 (file)
@@ -609,6 +609,7 @@ nfs_close(struct vop_close_args *ap)
        int error = 0;
        thread_t td = curthread;
 
+       vn_lock(vp, LK_UPGRADE | LK_RETRY); /* XXX */
        lwkt_gettoken(&nmp->nm_token);
 
        if (vp->v_type == VREG) {
@@ -3609,6 +3610,7 @@ nfsfifo_close(struct vop_close_args *ap)
 
        /* no token access required */
 
+       vn_lock(vp, LK_UPGRADE | LK_RETRY); /* XXX */
        if (np->n_flag & (NACC | NUPD)) {
                getnanotime(&ts);
                if (np->n_flag & NACC)
index a1c64ee..7b4605f 100644 (file)
@@ -603,7 +603,9 @@ out:
        (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE);
        VOP__UNLOCK(devvp, 0);
 #else
+       vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
        (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE);
+       vn_unlock(devvp);
 #endif
        
        return (error);
@@ -659,9 +661,10 @@ ntfs_unmount(struct mount *mp, int mntflags)
        if (ntmp->ntm_devvp->v_type != VBAD)
                ntmp->ntm_devvp->v_rdev->si_mountpoint = NULL;
 
+       vn_lock(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY);
        vinvalbuf(ntmp->ntm_devvp, V_SAVE, 0, 0);
-
        error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE);
+       vn_unlock(ntmp->ntm_devvp);
 
        vrele(ntmp->ntm_devvp);
 
index 7dee2f1..1fab287 100644 (file)
@@ -215,6 +215,8 @@ nwfs_close(struct vop_close_args *ap)
 
        NCPVNDEBUG("name=%s,td=%p,c=%d\n",np->n_name,ap->a_td,np->opened);
 
+       vn_lock(vp, LK_UPGRADE | LK_RETRY);
+
        error = 0;
        if (vp->v_type == VDIR)
                goto done;
index 6e6a600..598512c 100644 (file)
@@ -227,6 +227,11 @@ procfs_close(struct vop_close_args *ap)
        struct pfsnode *pfs = VTOPFS(ap->a_vp);
        struct proc *p;
 
+       /*
+        * Make sure the lock is exclusive for opencount tests
+        */
+       vn_lock(ap->a_vp, LK_UPGRADE | LK_RETRY);
+
        switch (pfs->pfs_type) {
        case Pmem:
                if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL))
index 7504bf5..e8446c0 100644 (file)
@@ -395,6 +395,8 @@ puffs_vnop_close(struct vop_close_args *ap)
        struct vnode *vp = ap->a_vp;
        struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
 
+       vn_lock(vp, LK_UPGRADE | LK_RETRY);
+
        if (!EXISTSOP(pmp, CLOSE))
                return vop_stdclose(ap);
 
index bac760f..f5cd0a6 100644 (file)
@@ -220,6 +220,7 @@ smbfs_closel(struct vop_close_args *ap)
        int error;
 
        SMBVDEBUG("name=%s, pid=%d, c=%d\n",np->n_name, p->p_pid, np->n_opencount);
+       vn_lock(vp, LK_UPGRADE | LK_RETRY);
 
        smb_makescred(&scred, curthread, proc0.p_ucred);
        error = 0;
index 5e63ecd..eeda5d1 100644 (file)
@@ -395,8 +395,11 @@ bail:
                kfree(udfmp, M_UDFMOUNT);
        if (bp != NULL)
                brelse(bp);
-       if (needclose)
+       if (needclose) {
+               vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
                VOP_CLOSE(devvp, FREAD);
+               vn_unlock(devvp);
+       }
        return(error);
 }
 
@@ -415,7 +418,9 @@ udf_unmount(struct mount *mp, int mntflags)
                return (error);
 
        udfmp->im_devvp->v_rdev->si_mountpoint = NULL;
+       vn_lock(udfmp->im_devvp, LK_EXCLUSIVE | LK_RETRY);
        error = VOP_CLOSE(udfmp->im_devvp, FREAD);
+       vn_unlock(udfmp->im_devvp);
        vrele(udfmp->im_devvp);
 
        if (udfmp->s_table)
index 1017675..329450c 100644 (file)
@@ -790,7 +790,9 @@ out:
        dev->si_mountpoint = NULL;
        if (bp)
                brelse(bp);
+       vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
        VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE);
+       vn_unlock(devvp);
        if (ump) {
                ufs_ihashuninit(ump);
                kfree(ump->um_fs, M_UFSMNT);
@@ -863,8 +865,10 @@ ffs_unmount(struct mount *mp, int mntflags)
        }
        ump->um_devvp->v_rdev->si_mountpoint = NULL;
 
+       vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
        vinvalbuf(ump->um_devvp, V_SAVE, 0, 0);
        error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE);
+       vn_unlock(ump->um_devvp);
 
        vrele(ump->um_devvp);
 
index 733370a..cf480d9 100644 (file)
@@ -747,8 +747,8 @@ union_copyup(struct union_node *un, int docopy, struct ucred *cred,
                error = VOP_OPEN(lvp, FREAD, cred, NULL);
                if (error == 0) {
                        error = union_copyfile(lvp, uvp, cred, td);
-                       vn_unlock(lvp);
                        (void) VOP_CLOSE(lvp, FREAD);
+                       vn_unlock(lvp);
                }
                if (error == 0)
                        UDEBUG(("union: copied up %s\n", un->un_path));
@@ -771,8 +771,12 @@ union_copyup(struct union_node *un, int docopy, struct ucred *cred,
                int i;
 
                for (i = 0; i < un->un_openl; i++) {
+                       vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY);
                        VOP_CLOSE(lvp, FREAD);
+                       vn_unlock(lvp);
+                       vn_lock(uvp, LK_EXCLUSIVE | LK_RETRY);
                        VOP_OPEN(uvp, FREAD, cred, NULL);
+                       vn_unlock(uvp);
                }
                un->un_openl = 0;
        }
index 4009504..479aa0b 100644 (file)
@@ -791,6 +791,7 @@ union_close(struct vop_close_args *ap)
        struct union_node *un = VTOUNION(ap->a_vp);
        struct vnode *vp;
 
+       vn_lock(vp, LK_UPGRADE | LK_RETRY);
        if ((vp = un->un_uppervp) == NULLVP) {
 #ifdef UNION_DIAGNOSTIC
                if (un->un_openl <= 0)