Author: mjg
Date: Wed Sep 23 10:44:49 2020
New Revision: 366070
URL: https://svnweb.freebsd.org/changeset/base/366070

Log:
  cache: reimplement purgevfs to iterate vnodes instead of the entire hash
  
  The entire cache scan was a leftover from the old implementation.
  
  It is incredibly wasteful in presence of several mount points and does not
  win much even for single ones.

Modified:
  head/sys/kern/vfs_cache.c

Modified: head/sys/kern/vfs_cache.c
==============================================================================
--- head/sys/kern/vfs_cache.c   Wed Sep 23 10:42:41 2020        (r366069)
+++ head/sys/kern/vfs_cache.c   Wed Sep 23 10:44:49 2020        (r366070)
@@ -491,20 +491,6 @@ static int vn_fullpath_dir(struct vnode *vp, struct vn
 
 static MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries");
 
-static int cache_yield;
-SYSCTL_INT(_vfs_cache, OID_AUTO, yield, CTLFLAG_RD, &cache_yield, 0,
-    "Number of times cache called yield");
-
-static void __noinline
-cache_maybe_yield(void)
-{
-
-       if (should_yield()) {
-               cache_yield++;
-               kern_yield(PRI_USER);
-       }
-}
-
 static inline void
 cache_assert_vlp_locked(struct mtx *vlp)
 {
@@ -1212,51 +1198,6 @@ cache_zap_locked_bucket(struct namecache *ncp, struct 
        return (cache_zap_unlocked_bucket(ncp, cnp, dvp, dvlp, vlp, hash, blp));
 }
 
-static int
-cache_zap_locked_bucket_kl(struct namecache *ncp, struct mtx *blp,
-    struct mtx **vlpp1, struct mtx **vlpp2)
-{
-       struct mtx *dvlp, *vlp;
-
-       cache_assert_bucket_locked(ncp);
-
-       dvlp = VP2VNODELOCK(ncp->nc_dvp);
-       vlp = NULL;
-       if (!(ncp->nc_flag & NCF_NEGATIVE))
-               vlp = VP2VNODELOCK(ncp->nc_vp);
-       cache_sort_vnodes(&dvlp, &vlp);
-
-       if (*vlpp1 == dvlp && *vlpp2 == vlp) {
-               cache_zap_locked(ncp);
-               cache_unlock_vnodes(dvlp, vlp);
-               *vlpp1 = NULL;
-               *vlpp2 = NULL;
-               return (0);
-       }
-
-       if (*vlpp1 != NULL)
-               mtx_unlock(*vlpp1);
-       if (*vlpp2 != NULL)
-               mtx_unlock(*vlpp2);
-       *vlpp1 = NULL;
-       *vlpp2 = NULL;
-
-       if (cache_trylock_vnodes(dvlp, vlp) == 0) {
-               cache_zap_locked(ncp);
-               cache_unlock_vnodes(dvlp, vlp);
-               return (0);
-       }
-
-       mtx_unlock(blp);
-       *vlpp1 = dvlp;
-       *vlpp2 = vlp;
-       if (*vlpp1 != NULL)
-               mtx_lock(*vlpp1);
-       mtx_lock(*vlpp2);
-       mtx_lock(blp);
-       return (EAGAIN);
-}
-
 static __noinline int
 cache_remove_cnp(struct vnode *dvp, struct componentname *cnp)
 {
@@ -2316,14 +2257,26 @@ retry:
        }
 }
 
+/*
+ * Opportunistic check to see if there is anything to do.
+ */
+static bool
+cache_has_entries(struct vnode *vp)
+{
+
+       if (LIST_EMPTY(&vp->v_cache_src) && TAILQ_EMPTY(&vp->v_cache_dst) &&
+           vp->v_cache_dd == NULL)
+               return (false);
+       return (true);
+}
+
 void
 cache_purge(struct vnode *vp)
 {
        struct mtx *vlp;
 
        SDT_PROBE1(vfs, namecache, purge, done, vp);
-       if (LIST_EMPTY(&vp->v_cache_src) && TAILQ_EMPTY(&vp->v_cache_dst) &&
-           vp->v_cache_dd == NULL)
+       if (!cache_has_entries(vp))
                return;
        vlp = VP2VNODELOCK(vp);
        mtx_lock(vlp);
@@ -2418,49 +2371,25 @@ cache_rename(struct vnode *fdvp, struct vnode *fvp, st
 void
 cache_purgevfs(struct mount *mp, bool force)
 {
-       TAILQ_HEAD(, namecache) ncps;
-       struct mtx *vlp1, *vlp2;
-       struct mtx *blp;
-       struct nchashhead *bucket;
-       struct namecache *ncp, *nnp;
-       u_long i, j, n_nchash;
-       int error;
+       struct vnode *vp, *mvp;
 
-       /* Scan hash tables for applicable entries */
        SDT_PROBE1(vfs, namecache, purgevfs, done, mp);
        if (!force && mp->mnt_nvnodelistsize <= ncpurgeminvnodes)
                return;
-       TAILQ_INIT(&ncps);
-       n_nchash = nchash + 1;
-       vlp1 = vlp2 = NULL;
-       for (i = 0; i < numbucketlocks; i++) {
-               blp = (struct mtx *)&bucketlocks[i];
-               mtx_lock(blp);
-               for (j = i; j < n_nchash; j += numbucketlocks) {
-retry:
-                       bucket = &nchashtbl[j];
-                       CK_SLIST_FOREACH_SAFE(ncp, bucket, nc_hash, nnp) {
-                               cache_assert_bucket_locked(ncp);
-                               if (ncp->nc_dvp->v_mount != mp)
-                                       continue;
-                               error = cache_zap_locked_bucket_kl(ncp, blp,
-                                   &vlp1, &vlp2);
-                               if (error != 0)
-                                       goto retry;
-                               TAILQ_INSERT_HEAD(&ncps, ncp, nc_dst);
-                       }
-               }
-               mtx_unlock(blp);
-               if (vlp1 == NULL && vlp2 == NULL)
-                       cache_maybe_yield();
-       }
-       if (vlp1 != NULL)
-               mtx_unlock(vlp1);
-       if (vlp2 != NULL)
-               mtx_unlock(vlp2);
 
-       TAILQ_FOREACH_SAFE(ncp, &ncps, nc_dst, nnp) {
-               cache_free(ncp);
+       /*
+        * Somewhat wasteful iteration over all vnodes. Would be better to
+        * support filtering and avoid the interlock to begin with.
+        */
+       MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
+               if (!cache_has_entries(vp)) {
+                       VI_UNLOCK(vp);
+                       continue;
+               }
+               vholdl(vp);
+               VI_UNLOCK(vp);
+               cache_purge(vp);
+               vdrop(vp);
        }
 }
 
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to