forked from mirrors/linux
		
	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:
		
							parent
							
								
									7d111c81fa
								
							
						
					
					
						commit
						fdd1315aa5
					
				
					 2 changed files with 119 additions and 0 deletions
				
			
		| 
						 | 
					@ -899,3 +899,89 @@ int dm_array_walk(struct dm_array_info *info, dm_block_t root,
 | 
				
			||||||
EXPORT_SYMBOL_GPL(dm_array_walk);
 | 
					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 */
 | 
					#endif	/* _LINUX_DM_ARRAY_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue