kernel - swapcache - Fix snocache and cache flags propagation, fix PG_NOTMETA
authorMatthew Dillon <dillon@apollo.backplane.com>
Mon, 22 Feb 2010 07:44:27 +0000 (23:44 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Mon, 22 Feb 2010 07:44:27 +0000 (23:44 -0800)
* The namecache was not always propagating the snocache and cache
  chflags flags.  Now it is.  However, the flags no longer propagate
  across mount points.

* The vm_page PG_NOMETA flag was being improperly applied to regular
  files.  It only applies to VCHR vnodes.

* blogbench tests show significant improvement but swapcache is still
  missing some data or meta-data somewhere.

sys/kern/vfs_cache.c
sys/kern/vfs_nlookup.c
sys/vm/vm_swapcache.c
test/debug/vnodeinfo.c

index 03d160d..ca250a6 100644 (file)
@@ -522,6 +522,18 @@ _cache_link_parent(struct namecache *ncp, struct namecache *par,
        KKASSERT(ncp->nc_parent == NULL);
        ncp->nc_parent = par;
        ncp->nc_head = nchpp;
+
+       /*
+        * Set inheritance flags.  Note that the parent flags may be
+        * stale due to getattr potentially not having been run yet
+        * (it gets run during nlookup()'s).
+        */
+       ncp->nc_flag &= ~(NCF_SF_PNOCACHE | NCF_UF_PCACHE);
+       if (par->nc_flag & (NCF_SF_NOCACHE | NCF_SF_PNOCACHE))
+               ncp->nc_flag |= NCF_SF_PNOCACHE;
+       if (par->nc_flag & (NCF_UF_CACHE | NCF_UF_PCACHE))
+               ncp->nc_flag |= NCF_UF_PCACHE;
+
        LIST_INSERT_HEAD(&nchpp->list, ncp, nc_hash);
 
        if (TAILQ_EMPTY(&par->nc_list)) {
index 59e24d3..f7377b0 100644 (file)
@@ -72,7 +72,7 @@
 #endif
 
 static int naccess(struct nchandle *nch, int vmode, struct ucred *cred,
-               int *stickyp, int *cflagsp);
+               int *stickyp);
 
 /*
  * Initialize a nlookup() structure, early error return for copyin faults
@@ -375,7 +375,6 @@ nlookup(struct nlookupdata *nd)
     int error;
     int len;
     int dflags;
-    int cflags;
 
 #ifdef KTRACE
     if (KTRPOINT(nd->nl_td, KTR_NAMEI))
@@ -399,7 +398,6 @@ nlookup(struct nlookupdata *nd)
      * Loop on the path components.  At the top of the loop nd->nl_nch
      * is ref'd and unlocked and represents our current position.
      */
-    cflags = nd->nl_nch.ncp->nc_flag & (NCF_SF_PNOCACHE | NCF_UF_PCACHE);
     for (;;) {
        /*
         * Make sure nl_nch is locked so we can access the vnode, resolution
@@ -444,7 +442,7 @@ nlookup(struct nlookupdata *nd)
         * Check directory search permissions.
         */
        dflags = 0;
-       error = naccess(&nd->nl_nch, NLC_EXEC, nd->nl_cred, &dflags, &cflags);
+       error = naccess(&nd->nl_nch, NLC_EXEC, nd->nl_cred, &dflags);
        if (error)
            break;
 
@@ -539,8 +537,7 @@ nlookup(struct nlookupdata *nd)
                par.mount = nch.mount;
                cache_hold(&par);
                cache_lock(&par);
-               cflags = par.ncp->nc_flag & (NCF_SF_PNOCACHE | NCF_UF_PCACHE);
-               error = naccess(&par, 0, nd->nl_cred, &dflags, &cflags);
+               error = naccess(&par, 0, nd->nl_cred, &dflags);
                cache_put(&par);
            }
        }
@@ -593,7 +590,7 @@ nlookup(struct nlookupdata *nd)
                        error = EROFS;
                } else {
                        error = naccess(&nch, nd->nl_flags | dflags,
-                                       nd->nl_cred, NULL, &cflags);
+                                       nd->nl_cred, NULL);
                }
            }
            if (error == 0 && wasdotordotdot &&
@@ -744,7 +741,7 @@ nlookup(struct nlookupdata *nd)
         */
        if (nch.ncp->nc_vp && (nd->nl_flags & NLC_ALLCHKS)) {
            error = naccess(&nch, nd->nl_flags | dflags,
-                           nd->nl_cred, NULL, &cflags);
+                           nd->nl_cred, NULL);
            if (error) {
                cache_put(&nch);
                break;
@@ -887,43 +884,45 @@ fail:
  * The passed ncp must be referenced and locked.
  */
 int
-naccess(struct nchandle *nch, int nflags, struct ucred *cred,
-       int *nflagsp, int *cflagsp)
+naccess(struct nchandle *nch, int nflags, struct ucred *cred, int *nflagsp)
 {
     struct vnode *vp;
     struct vattr va;
+    struct namecache *ncp;
     int error;
     int cflags;
 
     ASSERT_NCH_LOCKED(nch);
-    if (nch->ncp->nc_flag & NCF_UNRESOLVED) {
+    ncp = nch->ncp;
+    if (ncp->nc_flag & NCF_UNRESOLVED) {
        cache_resolve(nch, cred);
+       ncp = nch->ncp;
     }
-    error = nch->ncp->nc_error;
+    error = ncp->nc_error;
 
     /*
      * Directory permissions checks.  Silently ignore ENOENT if these
      * tests pass.  It isn't an error.
      *
-     * We have to lock nch.ncp to safely resolve nch.ncp->nc_parent
+     * We can safely resolve ncp->nc_parent because ncp is currently
+     * locked.
      */
     if (nflags & (NLC_CREATE | NLC_DELETE | NLC_RENAME_SRC | NLC_RENAME_DST)) {
-       if (((nflags & NLC_CREATE) && nch->ncp->nc_vp == NULL) ||
-           ((nflags & NLC_DELETE) && nch->ncp->nc_vp != NULL) ||
-           ((nflags & NLC_RENAME_SRC) && nch->ncp->nc_vp != NULL) ||
+       if (((nflags & NLC_CREATE) && ncp->nc_vp == NULL) ||
+           ((nflags & NLC_DELETE) && ncp->nc_vp != NULL) ||
+           ((nflags & NLC_RENAME_SRC) && ncp->nc_vp != NULL) ||
            (nflags & NLC_RENAME_DST)
        ) {
            struct nchandle par;
 
-           if ((par.ncp = nch->ncp->nc_parent) == NULL) {
+           if ((par.ncp = ncp->nc_parent) == NULL) {
                if (error != EAGAIN)
                        error = EINVAL;
            } else if (error == 0 || error == ENOENT) {
                par.mount = nch->mount;
                cache_hold(&par);
                cache_lock(&par);
-               cflags = par.ncp->nc_flag & (NCF_SF_PNOCACHE | NCF_UF_PCACHE);
-               error = naccess(&par, NLC_WRITE, cred, NULL, &cflags);
+               error = naccess(&par, NLC_WRITE, cred, NULL);
                cache_put(&par);
            }
        }
@@ -932,7 +931,7 @@ naccess(struct nchandle *nch, int nflags, struct ucred *cred,
     /*
      * NLC_EXCL check.  Target file must not exist.
      */
-    if (error == 0 && (nflags & NLC_EXCL) && nch->ncp->nc_vp != NULL)
+    if (error == 0 && (nflags & NLC_EXCL) && ncp->nc_vp != NULL)
        error = EEXIST;
 
     /*
@@ -1015,21 +1014,30 @@ naccess(struct nchandle *nch, int nflags, struct ucred *cred,
 
                /*
                 * Track swapcache management flags in the namecache.
-                * (*cflagsp) tracks and returns the cumulative parent state
-                * while nc_flag gets the old parent state and the new
-                * flags state from the vap.
+                *
+                * Calculate the flags based on the current vattr info
+                * and recalculate the inherited flags from the parent
+                * (the original cache linkage may have occurred without
+                * getattrs and thus have stale flags).
                 */
-               cflags = *cflagsp;
-               nch->ncp->nc_flag &= ~(NCF_SF_PNOCACHE | NCF_UF_PCACHE);
-               nch->ncp->nc_flag |= cflags;
-
+               cflags = 0;
                if (va.va_flags & SF_NOCACHE)
-                       cflags |= NCF_SF_PNOCACHE | NCF_SF_NOCACHE;
+                       cflags |= NCF_SF_NOCACHE;
                if (va.va_flags & UF_CACHE)
-                       cflags |= NCF_UF_PCACHE | NCF_UF_CACHE;
-               *cflagsp = cflags & (NCF_SF_PNOCACHE | NCF_UF_PCACHE);
-               nch->ncp->nc_flag &= ~(NCF_SF_NOCACHE | NCF_UF_CACHE);
-               nch->ncp->nc_flag |= cflags & (NCF_SF_NOCACHE | NCF_UF_CACHE);
+                       cflags |= NCF_UF_CACHE;
+               if (ncp->nc_parent) {
+                       if (ncp->nc_parent->nc_flag &
+                           (NCF_SF_NOCACHE | NCF_SF_PNOCACHE)) {
+                               cflags |= NCF_SF_PNOCACHE;
+                       }
+                       if (ncp->nc_parent->nc_flag &
+                           (NCF_UF_CACHE | NCF_UF_PCACHE)) {
+                               cflags |= NCF_UF_PCACHE;
+                       }
+               }
+               ncp->nc_flag &= ~(NCF_SF_NOCACHE | NCF_UF_CACHE |
+                                 NCF_SF_PNOCACHE | NCF_UF_PCACHE);
+               ncp->nc_flag |= cflags;
 
                /*
                 * Process general access.
index a015088..6e38849 100644 (file)
@@ -79,7 +79,7 @@
 
 /* the kernel process "vm_pageout"*/
 static void vm_swapcached (void);
-static int vm_swapcached_flush (vm_page_t m);
+static int vm_swapcached_flush (vm_page_t m, int isblkdev);
 static int vm_swapcache_test(vm_page_t m);
 static void vm_swapcache_writing(vm_page_t marker);
 static void vm_swapcache_cleaning(vm_object_t marker);
@@ -251,6 +251,7 @@ vm_swapcache_writing(vm_page_t marker)
        struct vnode *vp;
        vm_page_t m;
        int count;
+       int isblkdev;
 
        /*
         * Deal with an overflow of the heuristic counter or if the user
@@ -311,10 +312,18 @@ vm_swapcache_writing(vm_page_t marker)
                            (vm_swapcache_maxfilesize >> PAGE_SHIFT)) {
                                continue;
                        }
+                       isblkdev = 0;
                        break;
                case VCHR:
+                       /*
+                        * The PG_NOTMETA flag only applies to pages
+                        * associated with block devices.
+                        */
+                       if (m->flags & PG_NOTMETA)
+                               continue;
                        if (vm_swapcache_meta_enable == 0)
                                continue;
+                       isblkdev = 1;
                        break;
                default:
                        continue;
@@ -331,7 +340,7 @@ vm_swapcache_writing(vm_page_t marker)
                 *
                 * (adjust for the --count which also occurs in the loop)
                 */
-               count -= vm_swapcached_flush(m) - 1;
+               count -= vm_swapcached_flush(m, isblkdev) - 1;
 
                /*
                 * Setup for next loop using marker.
@@ -375,7 +384,7 @@ vm_swapcache_writing(vm_page_t marker)
  */
 static
 int
-vm_swapcached_flush(vm_page_t m)
+vm_swapcached_flush(vm_page_t m, int isblkdev)
 {
        vm_object_t object;
        vm_page_t marray[SWAP_META_PAGES];
@@ -404,6 +413,8 @@ vm_swapcached_flush(vm_page_t m)
                        break;
                if (vm_swapcache_test(m))
                        break;
+               if (isblkdev && (m->flags & PG_NOTMETA))
+                       break;
                vm_page_io_start(m);
                vm_page_protect(m, VM_PROT_READ);
                if (m->queue - m->pc == PQ_CACHE) {
@@ -420,6 +431,8 @@ vm_swapcached_flush(vm_page_t m)
                        break;
                if (vm_swapcache_test(m))
                        break;
+               if (isblkdev && (m->flags & PG_NOTMETA))
+                       break;
                vm_page_io_start(m);
                vm_page_protect(m, VM_PROT_READ);
                if (m->queue - m->pc == PQ_CACHE) {
@@ -456,7 +469,7 @@ vm_swapcache_test(vm_page_t m)
 {
        vm_object_t object;
 
-       if (m->flags & (PG_BUSY | PG_UNMANAGED | PG_NOTMETA))
+       if (m->flags & (PG_BUSY | PG_UNMANAGED))
                return(1);
        if (m->busy || m->hold_count || m->wire_count)
                return(1);
index 5632328..0b4ca2f 100644 (file)
@@ -245,6 +245,10 @@ dumpvp(kvm_t *kd, struct vnode *vp, int whichlist)
 #endif
     if (vn.v_flag & VOBJBUF)
        printf(" VOBJBUF");
+#ifdef VSWAPCACHE
+    if (vn.v_flag & VSWAPCACHE)
+       printf(" VSWAPCACHE");
+#endif
     switch(vn.v_flag & (VAGE0 | VAGE1)) {
     case 0:
        printf(" VAGE0");