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 | |
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')
-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 */ |