diff options
| author | Joe Thornber <ejt@redhat.com> | 2016-09-15 11:11:42 -0400 |
|---|---|---|
| committer | Mike Snitzer <snitzer@redhat.com> | 2016-09-22 11:15:04 -0400 |
| commit | fdd1315aa5f022fe6574efdc2d9535f75a0ee255 (patch) | |
| tree | 769113eca5f6a1594247d62410dbd829e74d8fd3 /drivers/md/persistent-data | |
| parent | 7d111c81fa29041c730010450618917fb05cab62 (diff) | |
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>
Diffstat (limited to 'drivers/md/persistent-data')
| -rw-r--r-- | drivers/md/persistent-data/dm-array.c | 86 | ||||
| -rw-r--r-- | drivers/md/persistent-data/dm-array.h | 33 |
2 files changed, 119 insertions, 0 deletions
diff --git a/drivers/md/persistent-data/dm-array.c b/drivers/md/persistent-data/dm-array.c index 155180954cdf..e83047cbb2da 100644 --- a/drivers/md/persistent-data/dm-array.c +++ b/drivers/md/persistent-data/dm-array.c | |||
| @@ -899,3 +899,89 @@ int dm_array_walk(struct dm_array_info *info, dm_block_t root, | |||
| 899 | EXPORT_SYMBOL_GPL(dm_array_walk); | 899 | EXPORT_SYMBOL_GPL(dm_array_walk); |
| 900 | 900 | ||
| 901 | /*----------------------------------------------------------------*/ | 901 | /*----------------------------------------------------------------*/ |
| 902 | |||
| 903 | static int load_ablock(struct dm_array_cursor *c) | ||
| 904 | { | ||
| 905 | int r; | ||
| 906 | __le64 value_le; | ||
| 907 | uint64_t key; | ||
| 908 | |||
| 909 | if (c->block) | ||
| 910 | unlock_ablock(c->info, c->block); | ||
| 911 | |||
| 912 | c->block = NULL; | ||
| 913 | c->ab = NULL; | ||
| 914 | c->index = 0; | ||
| 915 | |||
| 916 | r = dm_btree_cursor_get_value(&c->cursor, &key, &value_le); | ||
| 917 | if (r) { | ||
| 918 | DMERR("dm_btree_cursor_get_value failed"); | ||
| 919 | dm_btree_cursor_end(&c->cursor); | ||
| 920 | |||
| 921 | } else { | ||
| 922 | r = get_ablock(c->info, le64_to_cpu(value_le), &c->block, &c->ab); | ||
| 923 | if (r) { | ||
| 924 | DMERR("get_ablock failed"); | ||
| 925 | dm_btree_cursor_end(&c->cursor); | ||
| 926 | } | ||
| 927 | } | ||
| 928 | |||
| 929 | return r; | ||
| 930 | } | ||
| 931 | |||
| 932 | int dm_array_cursor_begin(struct dm_array_info *info, dm_block_t root, | ||
| 933 | struct dm_array_cursor *c) | ||
| 934 | { | ||
| 935 | int r; | ||
| 936 | |||
| 937 | memset(c, 0, sizeof(*c)); | ||
| 938 | c->info = info; | ||
| 939 | r = dm_btree_cursor_begin(&info->btree_info, root, true, &c->cursor); | ||
| 940 | if (r) { | ||
| 941 | DMERR("couldn't create btree cursor"); | ||
| 942 | return r; | ||
| 943 | } | ||
| 944 | |||
| 945 | return load_ablock(c); | ||
| 946 | } | ||
| 947 | EXPORT_SYMBOL_GPL(dm_array_cursor_begin); | ||
| 948 | |||
| 949 | void dm_array_cursor_end(struct dm_array_cursor *c) | ||
| 950 | { | ||
| 951 | if (c->block) { | ||
| 952 | unlock_ablock(c->info, c->block); | ||
| 953 | dm_btree_cursor_end(&c->cursor); | ||
| 954 | } | ||
| 955 | } | ||
| 956 | EXPORT_SYMBOL_GPL(dm_array_cursor_end); | ||
| 957 | |||
| 958 | int dm_array_cursor_next(struct dm_array_cursor *c) | ||
| 959 | { | ||
| 960 | int r; | ||
| 961 | |||
| 962 | if (!c->block) | ||
| 963 | return -ENODATA; | ||
| 964 | |||
| 965 | c->index++; | ||
| 966 | |||
| 967 | if (c->index >= le32_to_cpu(c->ab->nr_entries)) { | ||
| 968 | r = dm_btree_cursor_next(&c->cursor); | ||
| 969 | if (r) | ||
| 970 | return r; | ||
| 971 | |||
| 972 | r = load_ablock(c); | ||
| 973 | if (r) | ||
| 974 | return r; | ||
| 975 | } | ||
| 976 | |||
| 977 | return 0; | ||
| 978 | } | ||
| 979 | EXPORT_SYMBOL_GPL(dm_array_cursor_next); | ||
| 980 | |||
| 981 | void dm_array_cursor_get_value(struct dm_array_cursor *c, void **value_le) | ||
| 982 | { | ||
| 983 | *value_le = element_at(c->info, c->ab, c->index); | ||
| 984 | } | ||
| 985 | EXPORT_SYMBOL_GPL(dm_array_cursor_get_value); | ||
| 986 | |||
| 987 | /*----------------------------------------------------------------*/ | ||
diff --git a/drivers/md/persistent-data/dm-array.h b/drivers/md/persistent-data/dm-array.h index 45ea3f6e1ded..27ee49a55473 100644 --- a/drivers/md/persistent-data/dm-array.h +++ b/drivers/md/persistent-data/dm-array.h | |||
| @@ -182,4 +182,37 @@ int dm_array_walk(struct dm_array_info *info, dm_block_t root, | |||
| 182 | 182 | ||
| 183 | /*----------------------------------------------------------------*/ | 183 | /*----------------------------------------------------------------*/ |
| 184 | 184 | ||
| 185 | /* | ||
| 186 | * Cursor api. | ||
| 187 | * | ||
| 188 | * This lets you iterate through all the entries in an array efficiently | ||
| 189 | * (it will preload metadata). | ||
| 190 | * | ||
| 191 | * I'm using a cursor, rather than a walk function with a callback because | ||
| 192 | * the cache target needs to iterate both the mapping and hint arrays in | ||
| 193 | * unison. | ||
| 194 | */ | ||
| 195 | struct dm_array_cursor { | ||
| 196 | struct dm_array_info *info; | ||
| 197 | struct dm_btree_cursor cursor; | ||
| 198 | |||
| 199 | struct dm_block *block; | ||
| 200 | struct array_block *ab; | ||
| 201 | unsigned index; | ||
| 202 | }; | ||
| 203 | |||
| 204 | int dm_array_cursor_begin(struct dm_array_info *info, | ||
| 205 | dm_block_t root, struct dm_array_cursor *c); | ||
| 206 | void dm_array_cursor_end(struct dm_array_cursor *c); | ||
| 207 | |||
| 208 | uint32_t dm_array_cursor_index(struct dm_array_cursor *c); | ||
| 209 | int dm_array_cursor_next(struct dm_array_cursor *c); | ||
| 210 | |||
| 211 | /* | ||
| 212 | * value_le is only valid while the cursor points at the current value. | ||
| 213 | */ | ||
| 214 | void dm_array_cursor_get_value(struct dm_array_cursor *c, void **value_le); | ||
| 215 | |||
| 216 | /*----------------------------------------------------------------*/ | ||
| 217 | |||
| 185 | #endif /* _LINUX_DM_ARRAY_H */ | 218 | #endif /* _LINUX_DM_ARRAY_H */ |
