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

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

dm array: introduce cursor api



More efficient way to iterate an array due to prefetching (makes use of
the new dm_btree_cursor_* api).

Signed-off-by: default avatarJoe Thornber <ejt@redhat.com>
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
parent 7d111c81
Loading
Loading
Loading
Loading
+86 −0
Original line number Diff line number Diff line
@@ -899,3 +899,89 @@ int dm_array_walk(struct dm_array_info *info, dm_block_t root,
EXPORT_SYMBOL_GPL(dm_array_walk);

/*----------------------------------------------------------------*/

static int load_ablock(struct dm_array_cursor *c)
{
	int r;
	__le64 value_le;
	uint64_t key;

	if (c->block)
		unlock_ablock(c->info, c->block);

	c->block = NULL;
	c->ab = NULL;
	c->index = 0;

	r = dm_btree_cursor_get_value(&c->cursor, &key, &value_le);
	if (r) {
		DMERR("dm_btree_cursor_get_value failed");
		dm_btree_cursor_end(&c->cursor);

	} else {
		r = get_ablock(c->info, le64_to_cpu(value_le), &c->block, &c->ab);
		if (r) {
			DMERR("get_ablock failed");
			dm_btree_cursor_end(&c->cursor);
		}
	}

	return r;
}

int dm_array_cursor_begin(struct dm_array_info *info, dm_block_t root,
			  struct dm_array_cursor *c)
{
	int r;

	memset(c, 0, sizeof(*c));
	c->info = info;
	r = dm_btree_cursor_begin(&info->btree_info, root, true, &c->cursor);
	if (r) {
		DMERR("couldn't create btree cursor");
		return r;
	}

	return load_ablock(c);
}
EXPORT_SYMBOL_GPL(dm_array_cursor_begin);

void dm_array_cursor_end(struct dm_array_cursor *c)
{
	if (c->block) {
		unlock_ablock(c->info, c->block);
		dm_btree_cursor_end(&c->cursor);
	}
}
EXPORT_SYMBOL_GPL(dm_array_cursor_end);

int dm_array_cursor_next(struct dm_array_cursor *c)
{
	int r;

	if (!c->block)
		return -ENODATA;

	c->index++;

	if (c->index >= le32_to_cpu(c->ab->nr_entries)) {
		r = dm_btree_cursor_next(&c->cursor);
		if (r)
			return r;

		r = load_ablock(c);
		if (r)
			return r;
	}

	return 0;
}
EXPORT_SYMBOL_GPL(dm_array_cursor_next);

void dm_array_cursor_get_value(struct dm_array_cursor *c, void **value_le)
{
	*value_le = element_at(c->info, c->ab, c->index);
}
EXPORT_SYMBOL_GPL(dm_array_cursor_get_value);

/*----------------------------------------------------------------*/
+33 −0
Original line number Diff line number Diff line
@@ -182,4 +182,37 @@ int dm_array_walk(struct dm_array_info *info, dm_block_t root,

/*----------------------------------------------------------------*/

/*
 * Cursor api.
 *
 * This lets you iterate through all the entries in an array efficiently
 * (it will preload metadata).
 *
 * I'm using a cursor, rather than a walk function with a callback because
 * the cache target needs to iterate both the mapping and hint arrays in
 * unison.
 */
struct dm_array_cursor {
	struct dm_array_info *info;
	struct dm_btree_cursor cursor;

	struct dm_block *block;
	struct array_block *ab;
	unsigned index;
};

int dm_array_cursor_begin(struct dm_array_info *info,
			  dm_block_t root, struct dm_array_cursor *c);
void dm_array_cursor_end(struct dm_array_cursor *c);

uint32_t dm_array_cursor_index(struct dm_array_cursor *c);
int dm_array_cursor_next(struct dm_array_cursor *c);

/*
 * value_le is only valid while the cursor points at the current value.
 */
void dm_array_cursor_get_value(struct dm_array_cursor *c, void **value_le);

/*----------------------------------------------------------------*/

#endif	/* _LINUX_DM_ARRAY_H */