dm persistent metadata: add space map threshold callback
authorJoe Thornber <ejt@redhat.com>
Fri, 10 May 2013 13:37:20 +0000 (14:37 +0100)
committerAlasdair G Kergon <agk@redhat.com>
Fri, 10 May 2013 13:37:20 +0000 (14:37 +0100)
Add a threshold callback to dm persistent data space maps.

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

index 883b465794d4281f3dfe2f10c77c6fa3ccf0595f..1c959684caef7512fafd3c1a5505c29c798a9c11 100644 (file)
 
 /*----------------------------------------------------------------*/
 
+/*
+ * An edge triggered threshold.
+ */
+struct threshold {
+       bool threshold_set;
+       bool value_set;
+       dm_block_t threshold;
+       dm_block_t current_value;
+       dm_sm_threshold_fn fn;
+       void *context;
+};
+
+static void threshold_init(struct threshold *t)
+{
+       t->threshold_set = false;
+       t->value_set = false;
+}
+
+static void set_threshold(struct threshold *t, dm_block_t value,
+                         dm_sm_threshold_fn fn, void *context)
+{
+       t->threshold_set = true;
+       t->threshold = value;
+       t->fn = fn;
+       t->context = context;
+}
+
+static bool below_threshold(struct threshold *t, dm_block_t value)
+{
+       return t->threshold_set && value <= t->threshold;
+}
+
+static bool threshold_already_triggered(struct threshold *t)
+{
+       return t->value_set && below_threshold(t, t->current_value);
+}
+
+static void check_threshold(struct threshold *t, dm_block_t value)
+{
+       if (below_threshold(t, value) &&
+           !threshold_already_triggered(t))
+               t->fn(t->context);
+
+       t->value_set = true;
+       t->current_value = value;
+}
+
+/*----------------------------------------------------------------*/
+
 /*
  * Space map interface.
  *
@@ -54,6 +103,8 @@ struct sm_metadata {
        unsigned allocated_this_transaction;
        unsigned nr_uncommitted;
        struct block_op uncommitted[MAX_RECURSIVE_ALLOCATIONS];
+
+       struct threshold threshold;
 };
 
 static int add_bop(struct sm_metadata *smm, enum block_op_type type, dm_block_t b)
@@ -329,9 +380,19 @@ static int sm_metadata_new_block_(struct dm_space_map *sm, dm_block_t *b)
 
 static int sm_metadata_new_block(struct dm_space_map *sm, dm_block_t *b)
 {
+       dm_block_t count;
+       struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
+
        int r = sm_metadata_new_block_(sm, b);
        if (r)
                DMERR("unable to allocate new metadata block");
+
+       r = sm_metadata_get_nr_free(sm, &count);
+       if (r)
+               DMERR("couldn't get free block count");
+
+       check_threshold(&smm->threshold, count);
+
        return r;
 }
 
@@ -351,6 +412,18 @@ static int sm_metadata_commit(struct dm_space_map *sm)
        return 0;
 }
 
+static int sm_metadata_register_threshold_callback(struct dm_space_map *sm,
+                                                  dm_block_t threshold,
+                                                  dm_sm_threshold_fn fn,
+                                                  void *context)
+{
+       struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
+
+       set_threshold(&smm->threshold, threshold, fn, context);
+
+       return 0;
+}
+
 static int sm_metadata_root_size(struct dm_space_map *sm, size_t *result)
 {
        *result = sizeof(struct disk_sm_root);
@@ -392,7 +465,7 @@ static struct dm_space_map ops = {
        .commit = sm_metadata_commit,
        .root_size = sm_metadata_root_size,
        .copy_root = sm_metadata_copy_root,
-       .register_threshold_callback = NULL
+       .register_threshold_callback = sm_metadata_register_threshold_callback
 };
 
 /*----------------------------------------------------------------*/
@@ -577,6 +650,7 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
        smm->recursion_count = 0;
        smm->allocated_this_transaction = 0;
        smm->nr_uncommitted = 0;
+       threshold_init(&smm->threshold);
 
        memcpy(&smm->sm, &bootstrap_ops, sizeof(smm->sm));
 
@@ -618,6 +692,7 @@ int dm_sm_metadata_open(struct dm_space_map *sm,
        smm->recursion_count = 0;
        smm->allocated_this_transaction = 0;
        smm->nr_uncommitted = 0;
+       threshold_init(&smm->threshold);
 
        memcpy(&smm->old_ll, &smm->ll, sizeof(smm->old_ll));
        return 0;