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: Joe Thornber <ejt@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
This commit is contained in:
Родитель
7d111c81fa
Коммит
fdd1315aa5
|
@ -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);
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
|
|
@ -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 */
|
||||
|
|
Загрузка…
Ссылка в новой задаче