Whamcloud - gitweb
LU-9679 lnet: discard lnet_print_text_bufs()
[fs/lustre-release.git] / libcfs / libcfs / hash.c
index 559fc06..55a61fd 100644 (file)
  *
  * You should have received a copy of the GNU General Public License
  * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * GPL HEADER END
  */
@@ -27,7 +23,7 @@
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright (c) 2011, 2015, Intel Corporation.
+ * Copyright (c) 2011, 2016, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
  *   table. Also, user can break the iteration by return 1 in callback.
  */
 #include <linux/seq_file.h>
+#include <linux/log2.h>
 
+#include <libcfs/linux/linux-list.h>
 #include <libcfs/libcfs.h>
 
 #if CFS_HASH_DEBUG_LEVEL >= CFS_HASH_DEBUG_1
@@ -116,7 +114,7 @@ module_param(warn_on_depth, uint, 0644);
 MODULE_PARM_DESC(warn_on_depth, "warning when hash depth is high.");
 #endif
 
-struct cfs_wi_sched *cfs_sched_rehash;
+struct workqueue_struct *cfs_rehash_wq;
 
 static inline void
 cfs_hash_nl_lock(union cfs_hash_lock *lock, int exclusive) {}
@@ -158,6 +156,26 @@ cfs_hash_rw_unlock(union cfs_hash_lock *lock, int exclusive)
                write_unlock(&lock->rw);
 }
 
+static inline void
+cfs_hash_rw_sem_lock(union cfs_hash_lock *lock, int exclusive)
+       __acquires(&lock->rw_sem)
+{
+       if (!exclusive)
+               down_read(&lock->rw_sem);
+       else
+               down_write(&lock->rw_sem);
+}
+
+static inline void
+cfs_hash_rw_sem_unlock(union cfs_hash_lock *lock, int exclusive)
+       __releases(&lock->rw_sem)
+{
+       if (!exclusive)
+               up_read(&lock->rw_sem);
+       else
+               up_write(&lock->rw_sem);
+}
+
 /** No lock hash */
 static struct cfs_hash_lock_ops cfs_hash_nl_lops = {
        .hs_lock        = cfs_hash_nl_lock,
@@ -206,6 +224,22 @@ static struct cfs_hash_lock_ops cfs_hash_nr_bkt_rw_lops = {
        .hs_bkt_unlock  = cfs_hash_rw_unlock,
 };
 
+/** rw_sem bucket lock, rehash is disabled */
+static struct cfs_hash_lock_ops cfs_hash_nr_bkt_rw_sem_lops = {
+       .hs_lock        = cfs_hash_nl_lock,
+       .hs_unlock      = cfs_hash_nl_unlock,
+       .hs_bkt_lock    = cfs_hash_rw_sem_lock,
+       .hs_bkt_unlock  = cfs_hash_rw_sem_unlock,
+};
+
+/** rw_sem bucket lock, rehash is enabled */
+static struct cfs_hash_lock_ops cfs_hash_bkt_rw_sem_lops = {
+       .hs_lock        = cfs_hash_rw_sem_lock,
+       .hs_unlock      = cfs_hash_rw_sem_unlock,
+       .hs_bkt_lock    = cfs_hash_rw_sem_lock,
+       .hs_bkt_unlock  = cfs_hash_rw_sem_unlock,
+};
+
 static void
 cfs_hash_lock_setup(struct cfs_hash *hs)
 {
@@ -217,19 +251,26 @@ cfs_hash_lock_setup(struct cfs_hash *hs)
                spin_lock_init(&hs->hs_lock.spin);
 
        } else if (cfs_hash_with_rehash(hs)) {
-               rwlock_init(&hs->hs_lock.rw);
-
-                if (cfs_hash_with_rw_bktlock(hs))
-                        hs->hs_lops = &cfs_hash_bkt_rw_lops;
-                else if (cfs_hash_with_spin_bktlock(hs))
-                        hs->hs_lops = &cfs_hash_bkt_spin_lops;
-                else
-                        LBUG();
+               if (cfs_hash_with_rw_sem_bktlock(hs)) {
+                       init_rwsem(&hs->hs_lock.rw_sem);
+                       hs->hs_lops = &cfs_hash_bkt_rw_sem_lops;
+               } else {
+                       rwlock_init(&hs->hs_lock.rw);
+
+                       if (cfs_hash_with_rw_bktlock(hs))
+                               hs->hs_lops = &cfs_hash_bkt_rw_lops;
+                       else if (cfs_hash_with_spin_bktlock(hs))
+                               hs->hs_lops = &cfs_hash_bkt_spin_lops;
+                       else
+                               LBUG();
+               }
         } else {
                 if (cfs_hash_with_rw_bktlock(hs))
                         hs->hs_lops = &cfs_hash_nr_bkt_rw_lops;
                 else if (cfs_hash_with_spin_bktlock(hs))
                         hs->hs_lops = &cfs_hash_nr_bkt_spin_lops;
+               else if (cfs_hash_with_rw_sem_bktlock(hs))
+                       hs->hs_lops = &cfs_hash_nr_bkt_rw_sem_lops;
                 else
                         LBUG();
         }
@@ -521,7 +562,7 @@ cfs_hash_bd_dep_record(struct cfs_hash *hs, struct cfs_hash_bd *bd, int dep_cur)
        hs->hs_dep_bits = hs->hs_cur_bits;
        spin_unlock(&hs->hs_dep_lock);
 
-       cfs_wi_schedule(cfs_sched_rehash, &hs->hs_dep_wi);
+       queue_work(cfs_rehash_wq, &hs->hs_dep_work);
 # endif
 }
 
@@ -801,12 +842,8 @@ cfs_hash_bd_order(struct cfs_hash_bd *bd1, struct cfs_hash_bd *bd2)
         if (rc == 0) {
                 bd2->bd_bucket = NULL;
 
-        } else if (rc > 0) { /* swab bd1 and bd2 */
-               struct cfs_hash_bd tmp;
-
-                tmp = *bd2;
-                *bd2 = *bd1;
-                *bd1 = tmp;
+       } else if (rc > 0) {
+               swap(*bd1, *bd2); /* swab bd1 and bd2 */
         }
 }
 
@@ -931,6 +968,8 @@ cfs_hash_buckets_realloc(struct cfs_hash *hs, struct cfs_hash_bucket **old_bkts,
                        rwlock_init(&new_bkts[i]->hsb_lock.rw);
                else if (cfs_hash_with_spin_bktlock(hs))
                        spin_lock_init(&new_bkts[i]->hsb_lock.spin);
+               else if (cfs_hash_with_rw_sem_bktlock(hs))
+                       init_rwsem(&new_bkts[i]->hsb_lock.rw_sem);
                else
                        LBUG(); /* invalid use-case */
        }
@@ -946,12 +985,12 @@ cfs_hash_buckets_realloc(struct cfs_hash *hs, struct cfs_hash_bucket **old_bkts,
  * @flags    - CFS_HASH_REHASH enable synamic hash resizing
  *           - CFS_HASH_SORT enable chained hash sort
  */
-static int cfs_hash_rehash_worker(struct cfs_workitem *wi);
+static void cfs_hash_rehash_worker(struct work_struct *work);
 
 #if CFS_HASH_DEBUG_LEVEL >= CFS_HASH_DEBUG_1
-static int cfs_hash_dep_print(struct cfs_workitem *wi)
+static void cfs_hash_dep_print(struct work_struct *work)
 {
-       struct cfs_hash *hs = container_of(wi, struct cfs_hash, hs_dep_wi);
+       struct cfs_hash *hs = container_of(work, struct cfs_hash, hs_dep_work);
        int         dep;
        int         bkt;
        int         off;
@@ -975,21 +1014,12 @@ static int cfs_hash_dep_print(struct cfs_workitem *wi)
 static void cfs_hash_depth_wi_init(struct cfs_hash *hs)
 {
        spin_lock_init(&hs->hs_dep_lock);
-       cfs_wi_init(&hs->hs_dep_wi, hs, cfs_hash_dep_print);
+       INIT_WORK(&hs->hs_dep_work, cfs_hash_dep_print);
 }
 
 static void cfs_hash_depth_wi_cancel(struct cfs_hash *hs)
 {
-       if (cfs_wi_deschedule(cfs_sched_rehash, &hs->hs_dep_wi))
-               return;
-
-       spin_lock(&hs->hs_dep_lock);
-       while (hs->hs_dep_bits != 0) {
-               spin_unlock(&hs->hs_dep_lock);
-               cond_resched();
-               spin_lock(&hs->hs_dep_lock);
-       }
-       spin_unlock(&hs->hs_dep_lock);
+       cancel_work_sync(&hs->hs_dep_work);
 }
 
 #else /* CFS_HASH_DEBUG_LEVEL < CFS_HASH_DEBUG_1 */
@@ -1010,7 +1040,7 @@ cfs_hash_create(char *name, unsigned cur_bits, unsigned max_bits,
 
         ENTRY;
 
-        CLASSERT(CFS_HASH_THETA_BITS < 15);
+       BUILD_BUG_ON(CFS_HASH_THETA_BITS >= 15);
 
         LASSERT(name != NULL);
         LASSERT(ops != NULL);
@@ -1056,7 +1086,7 @@ cfs_hash_create(char *name, unsigned cur_bits, unsigned max_bits,
         hs->hs_ops         = ops;
         hs->hs_extra_bytes = extra_bytes;
         hs->hs_rehash_bits = 0;
-       cfs_wi_init(&hs->hs_rehash_wi, hs, cfs_hash_rehash_worker);
+       INIT_WORK(&hs->hs_rehash_work, cfs_hash_rehash_worker);
         cfs_hash_depth_wi_init(hs);
 
         if (cfs_hash_with_rehash(hs))
@@ -1377,16 +1407,17 @@ cfs_hash_for_each_enter(struct cfs_hash *hs)
          */
         hs->hs_iterating = 1;
 
-        cfs_hash_lock(hs, 1);
-        hs->hs_iterators++;
+       cfs_hash_lock(hs, 1);
+       hs->hs_iterators++;
+       cfs_hash_unlock(hs, 1);
 
-        /* NB: iteration is mostly called by service thread,
+       /* NB: iteration is mostly called by service thread,
         * we tend to cancel pending rehash-request, instead of
-         * blocking service thread, we will relaunch rehash request
-         * after iteration */
-        if (cfs_hash_is_rehashing(hs))
-                cfs_hash_rehash_cancel_locked(hs);
-        cfs_hash_unlock(hs, 1);
+        * blocking service thread, we will relaunch rehash request
+        * after iteration
+        */
+       if (cfs_hash_is_rehashing(hs))
+               cfs_hash_rehash_cancel(hs);
 }
 
 static void
@@ -1796,42 +1827,13 @@ EXPORT_SYMBOL(cfs_hash_for_each_key);
  * theta thresholds for @hs are tunable via cfs_hash_set_theta().
  */
 void
-cfs_hash_rehash_cancel_locked(struct cfs_hash *hs)
-{
-        int     i;
-
-        /* need hold cfs_hash_lock(hs, 1) */
-        LASSERT(cfs_hash_with_rehash(hs) &&
-                !cfs_hash_with_no_lock(hs));
-
-        if (!cfs_hash_is_rehashing(hs))
-                return;
-
-       if (cfs_wi_deschedule(cfs_sched_rehash, &hs->hs_rehash_wi)) {
-                hs->hs_rehash_bits = 0;
-                return;
-        }
-
-        for (i = 2; cfs_hash_is_rehashing(hs); i++) {
-               cfs_hash_unlock(hs, 1);
-               /* raise console warning while waiting too long */
-               CDEBUG(IS_PO2(i >> 3) ? D_WARNING : D_INFO,
-                      "hash %s is still rehashing, rescheded %d\n",
-                      hs->hs_name, i - 1);
-               cond_resched();
-               cfs_hash_lock(hs, 1);
-       }
-}
-
-void
 cfs_hash_rehash_cancel(struct cfs_hash *hs)
 {
-        cfs_hash_lock(hs, 1);
-        cfs_hash_rehash_cancel_locked(hs);
-        cfs_hash_unlock(hs, 1);
+       LASSERT(cfs_hash_with_rehash(hs));
+       cancel_work_sync(&hs->hs_rehash_work);
 }
 
-int
+void
 cfs_hash_rehash(struct cfs_hash *hs, int do_rehash)
 {
         int     rc;
@@ -1840,24 +1842,24 @@ cfs_hash_rehash(struct cfs_hash *hs, int do_rehash)
 
         cfs_hash_lock(hs, 1);
 
-        rc = cfs_hash_rehash_bits(hs);
-        if (rc <= 0) {
-                cfs_hash_unlock(hs, 1);
-                return rc;
-        }
+       rc = cfs_hash_rehash_bits(hs);
+       if (rc <= 0) {
+               cfs_hash_unlock(hs, 1);
+               return;
+       }
 
-        hs->hs_rehash_bits = rc;
-        if (!do_rehash) {
-                /* launch and return */
-               cfs_wi_schedule(cfs_sched_rehash, &hs->hs_rehash_wi);
-                cfs_hash_unlock(hs, 1);
-                return 0;
-        }
+       hs->hs_rehash_bits = rc;
+       if (!do_rehash) {
+               /* launch and return */
+               queue_work(cfs_rehash_wq, &hs->hs_rehash_work);
+               cfs_hash_unlock(hs, 1);
+               return;
+       }
 
-        /* rehash right now */
-        cfs_hash_unlock(hs, 1);
+       /* rehash right now */
+       cfs_hash_unlock(hs, 1);
 
-        return cfs_hash_rehash_worker(&hs->hs_rehash_wi);
+       cfs_hash_rehash_worker(&hs->hs_rehash_work);
 }
 
 static int
@@ -1890,11 +1892,11 @@ cfs_hash_rehash_bd(struct cfs_hash *hs, struct cfs_hash_bd *old)
        return c;
 }
 
-static int
-cfs_hash_rehash_worker(struct cfs_workitem *wi)
+static void
+cfs_hash_rehash_worker(struct work_struct *work)
 {
-       struct cfs_hash         *hs =
-               container_of(wi, struct cfs_hash, hs_rehash_wi);
+       struct cfs_hash *hs = container_of(work, struct cfs_hash,
+                                          hs_rehash_work);
        struct cfs_hash_bucket **bkts;
        struct cfs_hash_bd      bd;
        unsigned int            old_size;
@@ -1975,20 +1977,16 @@ cfs_hash_rehash_worker(struct cfs_workitem *wi)
         hs->hs_buckets = hs->hs_rehash_buckets;
         hs->hs_rehash_buckets = NULL;
 
-        hs->hs_cur_bits = hs->hs_rehash_bits;
- out:
-        hs->hs_rehash_bits = 0;
-       if (rc == -ESRCH) /* never be scheduled again */
-               cfs_wi_exit(cfs_sched_rehash, wi);
-        bsize = cfs_hash_bkt_size(hs);
-        cfs_hash_unlock(hs, 1);
-        /* can't refer to @hs anymore because it could be destroyed */
-        if (bkts != NULL)
-                cfs_hash_buckets_free(bkts, bsize, new_size, old_size);
-        if (rc != 0)
+       hs->hs_cur_bits = hs->hs_rehash_bits;
+out:
+       hs->hs_rehash_bits = 0;
+       bsize = cfs_hash_bkt_size(hs);
+       cfs_hash_unlock(hs, 1);
+       /* can't refer to @hs anymore because it could be destroyed */
+       if (bkts != NULL)
+               cfs_hash_buckets_free(bkts, bsize, new_size, old_size);
+       if (rc != 0)
                CDEBUG(D_INFO, "early quit of rehashing: %d\n", rc);
-       /* return 1 only if cfs_wi_exit is called */
-       return rc == -ESRCH;
 }
 
 /**
@@ -2039,13 +2037,10 @@ void cfs_hash_rehash_key(struct cfs_hash *hs, const void *old_key,
 }
 EXPORT_SYMBOL(cfs_hash_rehash_key);
 
-int cfs_hash_debug_header(struct seq_file *m)
+void cfs_hash_debug_header(struct seq_file *m)
 {
-       return seq_printf(m, "%-*s%6s%6s%6s%6s%6s%6s%6s%7s%8s%8s%8s%s\n",
-                       CFS_HASH_BIGNAME_LEN,
-                       "name", "cur", "min", "max", "theta", "t-min", "t-max",
-                       "flags", "rehash", "count", "maxdep", "maxdepb",
-                       " distribution");
+       seq_printf(m, "%-*s   cur   min   max theta t-min t-max flags rehash   count  maxdep maxdepb distribution\n",
+                  CFS_HASH_BIGNAME_LEN, "name");
 }
 EXPORT_SYMBOL(cfs_hash_debug_header);
 
@@ -2073,31 +2068,28 @@ cfs_hash_full_nbkt(struct cfs_hash *hs)
                CFS_HASH_RH_NBKT(hs) : CFS_HASH_NBKT(hs);
 }
 
-int cfs_hash_debug_str(struct cfs_hash *hs, struct seq_file *m)
+void cfs_hash_debug_str(struct cfs_hash *hs, struct seq_file *m)
 {
-       int     dist[8] = { 0, };
-       int     maxdep  = -1;
-       int     maxdepb = -1;
-       int     total   = 0;
-       int     c       = 0;
-       int     theta;
-       int     i;
+       int dist[8] = { 0, };
+       int maxdep = -1;
+       int maxdepb = -1;
+       int total = 0;
+       int theta;
+       int i;
 
        cfs_hash_lock(hs, 0);
        theta = __cfs_hash_theta(hs);
 
-       c += seq_printf(m, "%-*s ", CFS_HASH_BIGNAME_LEN, hs->hs_name);
-       c += seq_printf(m, "%5d ",  1 << hs->hs_cur_bits);
-       c += seq_printf(m, "%5d ",  1 << hs->hs_min_bits);
-       c += seq_printf(m, "%5d ",  1 << hs->hs_max_bits);
-       c += seq_printf(m, "%d.%03d ", __cfs_hash_theta_int(theta),
-                       __cfs_hash_theta_frac(theta));
-       c += seq_printf(m, "%d.%03d ", __cfs_hash_theta_int(hs->hs_min_theta),
-                       __cfs_hash_theta_frac(hs->hs_min_theta));
-       c += seq_printf(m, "%d.%03d ", __cfs_hash_theta_int(hs->hs_max_theta),
-                       __cfs_hash_theta_frac(hs->hs_max_theta));
-       c += seq_printf(m, " 0x%02x ", hs->hs_flags);
-       c += seq_printf(m, "%6d ", hs->hs_rehash_count);
+       seq_printf(m, "%-*s %5d %5d %5d %d.%03d %d.%03d %d.%03d  0x%02x %6d ",
+                  CFS_HASH_BIGNAME_LEN, hs->hs_name,
+                  1 << hs->hs_cur_bits, 1 << hs->hs_min_bits,
+                  1 << hs->hs_max_bits,
+                  __cfs_hash_theta_int(theta), __cfs_hash_theta_frac(theta),
+                  __cfs_hash_theta_int(hs->hs_min_theta),
+                  __cfs_hash_theta_frac(hs->hs_min_theta),
+                  __cfs_hash_theta_int(hs->hs_max_theta),
+                  __cfs_hash_theta_frac(hs->hs_max_theta),
+                  hs->hs_flags, hs->hs_rehash_count);
 
        /*
         * The distribution is a summary of the chained hash depth in
@@ -2122,17 +2114,14 @@ int cfs_hash_debug_str(struct cfs_hash *hs, struct seq_file *m)
                        maxdepb = ffz(~maxdep);
                }
                total += bd.bd_bucket->hsb_count;
-               dist[min(fls(bd.bd_bucket->hsb_count/max(theta,1)),7)]++;
+               dist[min(fls(bd.bd_bucket->hsb_count / max(theta, 1)), 7)]++;
                cfs_hash_bd_unlock(hs, &bd, 0);
        }
 
-       c += seq_printf(m, "%7d ", total);
-       c += seq_printf(m, "%7d ", maxdep);
-       c += seq_printf(m, "%7d ", maxdepb);
+       seq_printf(m, "%7d %7d %7d ", total, maxdep, maxdepb);
        for (i = 0; i < 8; i++)
-               c += seq_printf(m, "%d%c",  dist[i], (i == 7) ? '\n' : '/');
+               seq_printf(m, "%d%c",  dist[i], (i == 7) ? '\n' : '/');
 
        cfs_hash_unlock(hs, 0);
-       return c;
 }
 EXPORT_SYMBOL(cfs_hash_debug_str);