dm cache: speed up writing of the hint array
authorJoe Thornber <ejt@redhat.com>
Thu, 15 Sep 2016 13:23:46 +0000 (09:23 -0400)
committerMike Snitzer <snitzer@redhat.com>
Thu, 22 Sep 2016 15:15:02 +0000 (11:15 -0400)
It's far quicker to always delete the hint array and recreate with
dm_array_new() because we avoid the copying caused by mutation.

Also simplifies the policy interface, replacing the walk_hints() with
the simpler get_hint().

Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
drivers/md/dm-cache-metadata.c
drivers/md/dm-cache-policy-cleaner.c
drivers/md/dm-cache-policy-internal.h
drivers/md/dm-cache-policy-smq.c
drivers/md/dm-cache-policy.h

index 3970cda10080988887bfa07329241d94afd1b883..a60f10a0ee0ad8eee7f111ef22878edd42480bb7 100644 (file)
@@ -1368,10 +1368,24 @@ int dm_cache_get_metadata_dev_size(struct dm_cache_metadata *cmd,
 
 /*----------------------------------------------------------------*/
 
-static int begin_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *policy)
+static int get_hint(uint32_t index, void *value_le, void *context)
+{
+       uint32_t value;
+       struct dm_cache_policy *policy = context;
+
+       value = policy_get_hint(policy, to_cblock(index));
+       *((__le32 *) value_le) = cpu_to_le32(value);
+
+       return 0;
+}
+
+/*
+ * It's quicker to always delete the hint array, and recreate with
+ * dm_array_new().
+ */
+static int write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *policy)
 {
        int r;
-       __le32 value;
        size_t hint_size;
        const char *policy_name = dm_cache_policy_get_name(policy);
        const unsigned *policy_version = dm_cache_policy_get_version(policy);
@@ -1380,63 +1394,23 @@ static int begin_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *po
            (strlen(policy_name) > sizeof(cmd->policy_name) - 1))
                return -EINVAL;
 
-       if (!policy_unchanged(cmd, policy)) {
-               strncpy(cmd->policy_name, policy_name, sizeof(cmd->policy_name));
-               memcpy(cmd->policy_version, policy_version, sizeof(cmd->policy_version));
+       strncpy(cmd->policy_name, policy_name, sizeof(cmd->policy_name));
+       memcpy(cmd->policy_version, policy_version, sizeof(cmd->policy_version));
 
-               hint_size = dm_cache_policy_get_hint_size(policy);
-               if (!hint_size)
-                       return 0; /* short-circuit hints initialization */
-               cmd->policy_hint_size = hint_size;
+       hint_size = dm_cache_policy_get_hint_size(policy);
+       if (!hint_size)
+               return 0; /* short-circuit hints initialization */
+       cmd->policy_hint_size = hint_size;
 
-               if (cmd->hint_root) {
-                       r = dm_array_del(&cmd->hint_info, cmd->hint_root);
-                       if (r)
-                               return r;
-               }
-
-               r = dm_array_empty(&cmd->hint_info, &cmd->hint_root);
+       if (cmd->hint_root) {
+               r = dm_array_del(&cmd->hint_info, cmd->hint_root);
                if (r)
                        return r;
-
-               value = cpu_to_le32(0);
-               __dm_bless_for_disk(&value);
-               r = dm_array_resize(&cmd->hint_info, cmd->hint_root, 0,
-                                   from_cblock(cmd->cache_blocks),
-                                   &value, &cmd->hint_root);
-               if (r)
-                       return r;
-       }
-
-       return 0;
-}
-
-static int save_hint(void *context, dm_cblock_t cblock, dm_oblock_t oblock, uint32_t hint)
-{
-       struct dm_cache_metadata *cmd = context;
-       __le32 value = cpu_to_le32(hint);
-       int r;
-
-       __dm_bless_for_disk(&value);
-
-       r = dm_array_set_value(&cmd->hint_info, cmd->hint_root,
-                              from_cblock(cblock), &value, &cmd->hint_root);
-       cmd->changed = true;
-
-       return r;
-}
-
-static int write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *policy)
-{
-       int r;
-
-       r = begin_hints(cmd, policy);
-       if (r) {
-               DMERR("begin_hints failed");
-               return r;
        }
 
-       return policy_walk_mappings(policy, save_hint, cmd);
+       return dm_array_new(&cmd->hint_info, &cmd->hint_root,
+                           from_cblock(cmd->cache_blocks),
+                           get_hint, policy);
 }
 
 int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *policy)
index 14aaaf059f06a6a8197a8d3eb875abaf671b6305..2e8a8f1d835890d6b9f6f2892eef3103b42e7ad2 100644 (file)
@@ -395,7 +395,7 @@ static void init_policy_functions(struct policy *p)
        p->policy.set_dirty = wb_set_dirty;
        p->policy.clear_dirty = wb_clear_dirty;
        p->policy.load_mapping = wb_load_mapping;
-       p->policy.walk_mappings = NULL;
+       p->policy.get_hint = NULL;
        p->policy.remove_mapping = wb_remove_mapping;
        p->policy.writeback_work = wb_writeback_work;
        p->policy.force_mapping = wb_force_mapping;
index 2816018faa7ffc96e27649742410b41f05b3153d..808ee0e2b2c4703d4dd837efde064f479966a5c1 100644 (file)
@@ -48,10 +48,10 @@ static inline int policy_load_mapping(struct dm_cache_policy *p,
        return p->load_mapping(p, oblock, cblock, hint, hint_valid);
 }
 
-static inline int policy_walk_mappings(struct dm_cache_policy *p,
-                                     policy_walk_fn fn, void *context)
+static inline uint32_t policy_get_hint(struct dm_cache_policy *p,
+                                      dm_cblock_t cblock)
 {
-       return p->walk_mappings ? p->walk_mappings(p, fn, context) : 0;
+       return p->get_hint ? p->get_hint(p, cblock) : 0;
 }
 
 static inline int policy_writeback_work(struct dm_cache_policy *p,
index cf48a617a3a4f4ff53c2e2805e5a458e6b5a7adc..f3cec4e6333ccf8f6ddf2542a5cdfd272e50a0a9 100644 (file)
@@ -1375,41 +1375,15 @@ static int smq_load_mapping(struct dm_cache_policy *p,
        return 0;
 }
 
-static int smq_save_hints(struct smq_policy *mq, struct queue *q,
-                         policy_walk_fn fn, void *context)
-{
-       int r;
-       unsigned level;
-       struct entry *e;
-
-       for (level = 0; level < q->nr_levels; level++)
-               for (e = l_head(q->es, q->qs + level); e; e = l_next(q->es, e)) {
-                       if (!e->sentinel) {
-                               r = fn(context, infer_cblock(mq, e),
-                                      e->oblock, e->level);
-                               if (r)
-                                       return r;
-                       }
-               }
-
-       return 0;
-}
-
-static int smq_walk_mappings(struct dm_cache_policy *p, policy_walk_fn fn,
-                            void *context)
+static uint32_t smq_get_hint(struct dm_cache_policy *p, dm_cblock_t cblock)
 {
        struct smq_policy *mq = to_smq_policy(p);
-       int r = 0;
+       struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock));
 
-       /*
-        * We don't need to lock here since this method is only called once
-        * the IO has stopped.
-        */
-       r = smq_save_hints(mq, &mq->clean, fn, context);
-       if (!r)
-               r = smq_save_hints(mq, &mq->dirty, fn, context);
+       if (!e->allocated)
+               return 0;
 
-       return r;
+       return e->level;
 }
 
 static void __remove_mapping(struct smq_policy *mq, dm_oblock_t oblock)
@@ -1616,7 +1590,7 @@ static void init_policy_functions(struct smq_policy *mq, bool mimic_mq)
        mq->policy.set_dirty = smq_set_dirty;
        mq->policy.clear_dirty = smq_clear_dirty;
        mq->policy.load_mapping = smq_load_mapping;
-       mq->policy.walk_mappings = smq_walk_mappings;
+       mq->policy.get_hint = smq_get_hint;
        mq->policy.remove_mapping = smq_remove_mapping;
        mq->policy.remove_cblock = smq_remove_cblock;
        mq->policy.writeback_work = smq_writeback_work;
index 05db56eedb6a761ae42d3f1c09cdd803c540d8c0..aa10b1493f349ed1a43cf5f3e76de1ea083466b9 100644 (file)
@@ -90,9 +90,6 @@ struct policy_result {
        dm_cblock_t cblock;     /* POLICY_HIT, POLICY_NEW, POLICY_REPLACE */
 };
 
-typedef int (*policy_walk_fn)(void *context, dm_cblock_t cblock,
-                             dm_oblock_t oblock, uint32_t hint);
-
 /*
  * The cache policy object.  Just a bunch of methods.  It is envisaged that
  * this structure will be embedded in a bigger, policy specific structure
@@ -158,8 +155,11 @@ struct dm_cache_policy {
        int (*load_mapping)(struct dm_cache_policy *p, dm_oblock_t oblock,
                            dm_cblock_t cblock, uint32_t hint, bool hint_valid);
 
-       int (*walk_mappings)(struct dm_cache_policy *p, policy_walk_fn fn,
-                            void *context);
+       /*
+        * Gets the hint for a given cblock.  Called in a single threaded
+        * context.  So no locking required.
+        */
+       uint32_t (*get_hint)(struct dm_cache_policy *p, dm_cblock_t cblock);
 
        /*
         * Override functions used on the error paths of the core target.