dm thin: generate event when metadata threshold passed
authorJoe Thornber <ejt@redhat.com>
Fri, 10 May 2013 13:37:21 +0000 (14:37 +0100)
committerAlasdair G Kergon <agk@redhat.com>
Fri, 10 May 2013 13:37:21 +0000 (14:37 +0100)
Generate a dm event when the amount of remaining thin pool metadata
space falls below a certain level.

The threshold is taken to be a quarter of the size of the metadata
device with a minimum threshold of 4MB.

Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
drivers/md/dm-thin-metadata.c
drivers/md/dm-thin-metadata.h
drivers/md/dm-thin.c

index f553ed66603c57efc1135c658ace9e149804ff1a..60bce435f4fa1443c2994bd483e70ea096c7aa92 100644 (file)
@@ -1696,3 +1696,17 @@ void dm_pool_metadata_read_only(struct dm_pool_metadata *pmd)
        dm_bm_set_read_only(pmd->bm);
        up_write(&pmd->root_lock);
 }
+
+int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
+                                       dm_block_t threshold,
+                                       dm_sm_threshold_fn fn,
+                                       void *context)
+{
+       int r;
+
+       down_write(&pmd->root_lock);
+       r = dm_sm_register_threshold_callback(pmd->metadata_sm, threshold, fn, context);
+       up_write(&pmd->root_lock);
+
+       return r;
+}
index ef8dd709e34e2371c721be5c6a9b497f28a342b4..845ebbe589a9e0a00505bab0150df48331233928 100644 (file)
@@ -8,6 +8,7 @@
 #define DM_THIN_METADATA_H
 
 #include "persistent-data/dm-block-manager.h"
+#include "persistent-data/dm-space-map.h"
 
 #define THIN_METADATA_BLOCK_SIZE 4096
 
@@ -193,6 +194,11 @@ int dm_pool_resize_metadata_dev(struct dm_pool_metadata *pmd, dm_block_t new_siz
  */
 void dm_pool_metadata_read_only(struct dm_pool_metadata *pmd);
 
+int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
+                                       dm_block_t threshold,
+                                       dm_sm_threshold_fn fn,
+                                       void *context);
+
 /*----------------------------------------------------------------*/
 
 #endif
index f4632f97bd7b5b6ca988937b11dbd62694eaab34..759cffc45cabce8414c883f329b52fd56513bccf 100644 (file)
@@ -1281,6 +1281,10 @@ static void process_bio_fail(struct thin_c *tc, struct bio *bio)
        bio_io_error(bio);
 }
 
+/*
+ * FIXME: should we also commit due to size of transaction, measured in
+ * metadata blocks?
+ */
 static int need_commit_due_to_time(struct pool *pool)
 {
        return jiffies < pool->last_commit_jiffies ||
@@ -1909,6 +1913,16 @@ static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
        return r;
 }
 
+static void metadata_low_callback(void *context)
+{
+       struct pool *pool = context;
+
+       DMWARN("%s: reached low water mark for metadata device: sending event.",
+              dm_device_name(pool->pool_md));
+
+       dm_table_event(pool->ti->table);
+}
+
 static sector_t get_metadata_dev_size(struct block_device *bdev)
 {
        sector_t metadata_dev_size = i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
@@ -1932,6 +1946,23 @@ static dm_block_t get_metadata_dev_size_in_blocks(struct block_device *bdev)
        return metadata_dev_size;
 }
 
+/*
+ * When a metadata threshold is crossed a dm event is triggered, and
+ * userland should respond by growing the metadata device.  We could let
+ * userland set the threshold, like we do with the data threshold, but I'm
+ * not sure they know enough to do this well.
+ */
+static dm_block_t calc_metadata_threshold(struct pool_c *pt)
+{
+       /*
+        * 4M is ample for all ops with the possible exception of thin
+        * device deletion which is harmless if it fails (just retry the
+        * delete after you've grown the device).
+        */
+       dm_block_t quarter = get_metadata_dev_size_in_blocks(pt->metadata_dev->bdev) / 4;
+       return min((dm_block_t)1024ULL /* 4M */, quarter);
+}
+
 /*
  * thin-pool <metadata dev> <data dev>
  *          <data block size (sectors)>
@@ -2065,6 +2096,13 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
        }
        ti->private = pt;
 
+       r = dm_pool_register_metadata_threshold(pt->pool->pmd,
+                                               calc_metadata_threshold(pt),
+                                               metadata_low_callback,
+                                               pool);
+       if (r)
+               goto out_free_pt;
+
        pt->callbacks.congested_fn = pool_is_congested;
        dm_table_add_target_callbacks(ti->table, &pt->callbacks);