diff options
Diffstat (limited to 'drivers/md/persistent-data')
| -rw-r--r-- | drivers/md/persistent-data/dm-space-map-metadata.c | 77 | 
1 files changed, 76 insertions, 1 deletions
| diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c index 883b465794d4..1c959684caef 100644 --- a/drivers/md/persistent-data/dm-space-map-metadata.c +++ b/drivers/md/persistent-data/dm-space-map-metadata.c @@ -17,6 +17,55 @@  /*----------------------------------------------------------------*/  /* + * 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.   *   * The low level disk format is written using the standard btree and @@ -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; | 
