Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dd6a77d9 authored by Joe Thornber's avatar Joe Thornber Committed by Mike Snitzer
Browse files

dm array: add dm_array_new()



dm_array_new() creates a new, populated array more efficiently than
starting with an empty one and resizing.

Signed-off-by: default avatarJoe Thornber <ejt@redhat.com>
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
parent b88efd43
Loading
Loading
Loading
Loading
+111 −31
Original line number Diff line number Diff line
@@ -277,32 +277,13 @@ static int insert_ablock(struct dm_array_info *info, uint64_t index,
	return dm_btree_insert(&info->btree_info, *root, &index, &block_le, root);
}

/*
 * Looks up an array block in the btree.  Then shadows it, and updates the
 * btree to point to this new shadow.  'root' is an input/output parameter
 * for both the current root block, and the new one.
 */
static int shadow_ablock(struct dm_array_info *info, dm_block_t *root,
			 unsigned index, struct dm_block **block,
			 struct array_block **ab)
{
	int r, inc;
	uint64_t key = index;
	dm_block_t b;
	__le64 block_le;

	/*
	 * lookup
	 */
	r = dm_btree_lookup(&info->btree_info, *root, &key, &block_le);
	if (r)
		return r;
	b = le64_to_cpu(block_le);
/*----------------------------------------------------------------*/

	/*
	 * shadow
	 */
	r = dm_tm_shadow_block(info->btree_info.tm, b,
static int __shadow_ablock(struct dm_array_info *info, dm_block_t b,
			   struct dm_block **block, struct array_block **ab)
{
	int inc;
	int r = dm_tm_shadow_block(info->btree_info.tm, b,
				   &array_validator, block, &inc);
	if (r)
		return r;
@@ -311,13 +292,20 @@ static int shadow_ablock(struct dm_array_info *info, dm_block_t *root,
	if (inc)
		inc_ablock_entries(info, *ab);

	return 0;
}

/*
	 * Reinsert.
	 *
 * The shadow op will often be a noop.  Only insert if it really
 * copied data.
 */
	if (dm_block_location(*block) != b) {
static int __reinsert_ablock(struct dm_array_info *info, unsigned index,
			     struct dm_block *block, dm_block_t b,
			     dm_block_t *root)
{
	int r = 0;

	if (dm_block_location(block) != b) {
		/*
		 * dm_tm_shadow_block will have already decremented the old
		 * block, but it is still referenced by the btree.  We
@@ -325,12 +313,38 @@ static int shadow_ablock(struct dm_array_info *info, dm_block_t *root,
		 * when overwriting the old value.
		 */
		dm_tm_inc(info->btree_info.tm, b);
		r = insert_ablock(info, index, *block, root);
		r = insert_ablock(info, index, block, root);
	}

	return r;
}

/*
 * Looks up an array block in the btree.  Then shadows it, and updates the
 * btree to point to this new shadow.  'root' is an input/output parameter
 * for both the current root block, and the new one.
 */
static int shadow_ablock(struct dm_array_info *info, dm_block_t *root,
			 unsigned index, struct dm_block **block,
			 struct array_block **ab)
{
	int r;
	uint64_t key = index;
	dm_block_t b;
	__le64 block_le;

	r = dm_btree_lookup(&info->btree_info, *root, &key, &block_le);
	if (r)
		return r;
	b = le64_to_cpu(block_le);

	r = __shadow_ablock(info, b, block, ab);
	if (r)
		return r;

	return __reinsert_ablock(info, index, *block, b, root);
}

/*
 * Allocate an new array block, and fill it with some values.
 */
@@ -681,6 +695,72 @@ int dm_array_resize(struct dm_array_info *info, dm_block_t root,
}
EXPORT_SYMBOL_GPL(dm_array_resize);

static int populate_ablock_with_values(struct dm_array_info *info, struct array_block *ab,
				       value_fn fn, void *context, unsigned base, unsigned new_nr)
{
	int r;
	unsigned i;
	uint32_t nr_entries;
	struct dm_btree_value_type *vt = &info->value_type;

	BUG_ON(le32_to_cpu(ab->nr_entries));
	BUG_ON(new_nr > le32_to_cpu(ab->max_entries));

	nr_entries = le32_to_cpu(ab->nr_entries);
	for (i = 0; i < new_nr; i++) {
		r = fn(base + i, element_at(info, ab, i), context);
		if (r)
			return r;

		if (vt->inc)
			vt->inc(vt->context, element_at(info, ab, i));
	}

	ab->nr_entries = cpu_to_le32(new_nr);
	return 0;
}

int dm_array_new(struct dm_array_info *info, dm_block_t *root,
		 uint32_t size, value_fn fn, void *context)
{
	int r;
	struct dm_block *block;
	struct array_block *ab;
	unsigned block_index, end_block, size_of_block, max_entries;

	r = dm_array_empty(info, root);
	if (r)
		return r;

	size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm));
	max_entries = calc_max_entries(info->value_type.size, size_of_block);
	end_block = dm_div_up(size, max_entries);

	for (block_index = 0; block_index != end_block; block_index++) {
		r = alloc_ablock(info, size_of_block, max_entries, &block, &ab);
		if (r)
			break;

		r = populate_ablock_with_values(info, ab, fn, context,
						block_index * max_entries,
						min(max_entries, size));
		if (r) {
			unlock_ablock(info, block);
			break;
		}

		r = insert_ablock(info, block_index, block, root);
		unlock_ablock(info, block);
		if (r)
			break;

		size -= max_entries;
	}

	return r;
}
EXPORT_SYMBOL_GPL(dm_array_new);

int dm_array_del(struct dm_array_info *info, dm_block_t root)
{
	return dm_btree_del(&info->btree_info, root);
+19 −0
Original line number Diff line number Diff line
@@ -111,6 +111,25 @@ int dm_array_resize(struct dm_array_info *info, dm_block_t root,
		    const void *value, dm_block_t *new_root)
	__dm_written_to_disk(value);

/*
 * Creates a new array populated with values provided by a callback
 * function.  This is more efficient than creating an empty array,
 * resizing, and then setting values since that process incurs a lot of
 * copying.
 *
 * Assumes 32bit values for now since it's only used by the cache hint
 * array.
 *
 * info - describes the array
 * root - the root block of the array on disk
 * size - the number of entries in the array
 * fn - the callback
 * context - passed to the callback
 */
typedef int (*value_fn)(uint32_t index, void *value_le, void *context);
int dm_array_new(struct dm_array_info *info, dm_block_t *root,
		 uint32_t size, value_fn fn, void *context);

/*
 * Frees a whole array.  The value_type's decrement operation will be called
 * for all values in the array