xref: /openbmc/linux/drivers/md/persistent-data/dm-array.c (revision 6513c29f44f2cc970c0e9fecfe5a6526c3e73025)
1*6513c29fSJoe Thornber /*
2*6513c29fSJoe Thornber  * Copyright (C) 2012 Red Hat, Inc.
3*6513c29fSJoe Thornber  *
4*6513c29fSJoe Thornber  * This file is released under the GPL.
5*6513c29fSJoe Thornber  */
6*6513c29fSJoe Thornber 
7*6513c29fSJoe Thornber #include "dm-array.h"
8*6513c29fSJoe Thornber #include "dm-space-map.h"
9*6513c29fSJoe Thornber #include "dm-transaction-manager.h"
10*6513c29fSJoe Thornber 
11*6513c29fSJoe Thornber #include <linux/export.h>
12*6513c29fSJoe Thornber #include <linux/device-mapper.h>
13*6513c29fSJoe Thornber 
14*6513c29fSJoe Thornber #define DM_MSG_PREFIX "array"
15*6513c29fSJoe Thornber 
16*6513c29fSJoe Thornber /*----------------------------------------------------------------*/
17*6513c29fSJoe Thornber 
18*6513c29fSJoe Thornber /*
19*6513c29fSJoe Thornber  * The array is implemented as a fully populated btree, which points to
20*6513c29fSJoe Thornber  * blocks that contain the packed values.  This is more space efficient
21*6513c29fSJoe Thornber  * than just using a btree since we don't store 1 key per value.
22*6513c29fSJoe Thornber  */
23*6513c29fSJoe Thornber struct array_block {
24*6513c29fSJoe Thornber 	__le32 csum;
25*6513c29fSJoe Thornber 	__le32 max_entries;
26*6513c29fSJoe Thornber 	__le32 nr_entries;
27*6513c29fSJoe Thornber 	__le32 value_size;
28*6513c29fSJoe Thornber 	__le64 blocknr; /* Block this node is supposed to live in. */
29*6513c29fSJoe Thornber } __packed;
30*6513c29fSJoe Thornber 
31*6513c29fSJoe Thornber /*----------------------------------------------------------------*/
32*6513c29fSJoe Thornber 
33*6513c29fSJoe Thornber /*
34*6513c29fSJoe Thornber  * Validator methods.  As usual we calculate a checksum, and also write the
35*6513c29fSJoe Thornber  * block location into the header (paranoia about ssds remapping areas by
36*6513c29fSJoe Thornber  * mistake).
37*6513c29fSJoe Thornber  */
38*6513c29fSJoe Thornber #define CSUM_XOR 595846735
39*6513c29fSJoe Thornber 
40*6513c29fSJoe Thornber static void array_block_prepare_for_write(struct dm_block_validator *v,
41*6513c29fSJoe Thornber 					  struct dm_block *b,
42*6513c29fSJoe Thornber 					  size_t size_of_block)
43*6513c29fSJoe Thornber {
44*6513c29fSJoe Thornber 	struct array_block *bh_le = dm_block_data(b);
45*6513c29fSJoe Thornber 
46*6513c29fSJoe Thornber 	bh_le->blocknr = cpu_to_le64(dm_block_location(b));
47*6513c29fSJoe Thornber 	bh_le->csum = cpu_to_le32(dm_bm_checksum(&bh_le->max_entries,
48*6513c29fSJoe Thornber 						 size_of_block - sizeof(__le32),
49*6513c29fSJoe Thornber 						 CSUM_XOR));
50*6513c29fSJoe Thornber }
51*6513c29fSJoe Thornber 
52*6513c29fSJoe Thornber static int array_block_check(struct dm_block_validator *v,
53*6513c29fSJoe Thornber 			     struct dm_block *b,
54*6513c29fSJoe Thornber 			     size_t size_of_block)
55*6513c29fSJoe Thornber {
56*6513c29fSJoe Thornber 	struct array_block *bh_le = dm_block_data(b);
57*6513c29fSJoe Thornber 	__le32 csum_disk;
58*6513c29fSJoe Thornber 
59*6513c29fSJoe Thornber 	if (dm_block_location(b) != le64_to_cpu(bh_le->blocknr)) {
60*6513c29fSJoe Thornber 		DMERR_LIMIT("array_block_check failed: blocknr %llu != wanted %llu",
61*6513c29fSJoe Thornber 			    (unsigned long long) le64_to_cpu(bh_le->blocknr),
62*6513c29fSJoe Thornber 			    (unsigned long long) dm_block_location(b));
63*6513c29fSJoe Thornber 		return -ENOTBLK;
64*6513c29fSJoe Thornber 	}
65*6513c29fSJoe Thornber 
66*6513c29fSJoe Thornber 	csum_disk = cpu_to_le32(dm_bm_checksum(&bh_le->max_entries,
67*6513c29fSJoe Thornber 					       size_of_block - sizeof(__le32),
68*6513c29fSJoe Thornber 					       CSUM_XOR));
69*6513c29fSJoe Thornber 	if (csum_disk != bh_le->csum) {
70*6513c29fSJoe Thornber 		DMERR_LIMIT("array_block_check failed: csum %u != wanted %u",
71*6513c29fSJoe Thornber 			    (unsigned) le32_to_cpu(csum_disk),
72*6513c29fSJoe Thornber 			    (unsigned) le32_to_cpu(bh_le->csum));
73*6513c29fSJoe Thornber 		return -EILSEQ;
74*6513c29fSJoe Thornber 	}
75*6513c29fSJoe Thornber 
76*6513c29fSJoe Thornber 	return 0;
77*6513c29fSJoe Thornber }
78*6513c29fSJoe Thornber 
79*6513c29fSJoe Thornber static struct dm_block_validator array_validator = {
80*6513c29fSJoe Thornber 	.name = "array",
81*6513c29fSJoe Thornber 	.prepare_for_write = array_block_prepare_for_write,
82*6513c29fSJoe Thornber 	.check = array_block_check
83*6513c29fSJoe Thornber };
84*6513c29fSJoe Thornber 
85*6513c29fSJoe Thornber /*----------------------------------------------------------------*/
86*6513c29fSJoe Thornber 
87*6513c29fSJoe Thornber /*
88*6513c29fSJoe Thornber  * Functions for manipulating the array blocks.
89*6513c29fSJoe Thornber  */
90*6513c29fSJoe Thornber 
91*6513c29fSJoe Thornber /*
92*6513c29fSJoe Thornber  * Returns a pointer to a value within an array block.
93*6513c29fSJoe Thornber  *
94*6513c29fSJoe Thornber  * index - The index into _this_ specific block.
95*6513c29fSJoe Thornber  */
96*6513c29fSJoe Thornber static void *element_at(struct dm_array_info *info, struct array_block *ab,
97*6513c29fSJoe Thornber 			unsigned index)
98*6513c29fSJoe Thornber {
99*6513c29fSJoe Thornber 	unsigned char *entry = (unsigned char *) (ab + 1);
100*6513c29fSJoe Thornber 
101*6513c29fSJoe Thornber 	entry += index * info->value_type.size;
102*6513c29fSJoe Thornber 
103*6513c29fSJoe Thornber 	return entry;
104*6513c29fSJoe Thornber }
105*6513c29fSJoe Thornber 
106*6513c29fSJoe Thornber /*
107*6513c29fSJoe Thornber  * Utility function that calls one of the value_type methods on every value
108*6513c29fSJoe Thornber  * in an array block.
109*6513c29fSJoe Thornber  */
110*6513c29fSJoe Thornber static void on_entries(struct dm_array_info *info, struct array_block *ab,
111*6513c29fSJoe Thornber 		       void (*fn)(void *, const void *))
112*6513c29fSJoe Thornber {
113*6513c29fSJoe Thornber 	unsigned i, nr_entries = le32_to_cpu(ab->nr_entries);
114*6513c29fSJoe Thornber 
115*6513c29fSJoe Thornber 	for (i = 0; i < nr_entries; i++)
116*6513c29fSJoe Thornber 		fn(info->value_type.context, element_at(info, ab, i));
117*6513c29fSJoe Thornber }
118*6513c29fSJoe Thornber 
119*6513c29fSJoe Thornber /*
120*6513c29fSJoe Thornber  * Increment every value in an array block.
121*6513c29fSJoe Thornber  */
122*6513c29fSJoe Thornber static void inc_ablock_entries(struct dm_array_info *info, struct array_block *ab)
123*6513c29fSJoe Thornber {
124*6513c29fSJoe Thornber 	struct dm_btree_value_type *vt = &info->value_type;
125*6513c29fSJoe Thornber 
126*6513c29fSJoe Thornber 	if (vt->inc)
127*6513c29fSJoe Thornber 		on_entries(info, ab, vt->inc);
128*6513c29fSJoe Thornber }
129*6513c29fSJoe Thornber 
130*6513c29fSJoe Thornber /*
131*6513c29fSJoe Thornber  * Decrement every value in an array block.
132*6513c29fSJoe Thornber  */
133*6513c29fSJoe Thornber static void dec_ablock_entries(struct dm_array_info *info, struct array_block *ab)
134*6513c29fSJoe Thornber {
135*6513c29fSJoe Thornber 	struct dm_btree_value_type *vt = &info->value_type;
136*6513c29fSJoe Thornber 
137*6513c29fSJoe Thornber 	if (vt->dec)
138*6513c29fSJoe Thornber 		on_entries(info, ab, vt->dec);
139*6513c29fSJoe Thornber }
140*6513c29fSJoe Thornber 
141*6513c29fSJoe Thornber /*
142*6513c29fSJoe Thornber  * Each array block can hold this many values.
143*6513c29fSJoe Thornber  */
144*6513c29fSJoe Thornber static uint32_t calc_max_entries(size_t value_size, size_t size_of_block)
145*6513c29fSJoe Thornber {
146*6513c29fSJoe Thornber 	return (size_of_block - sizeof(struct array_block)) / value_size;
147*6513c29fSJoe Thornber }
148*6513c29fSJoe Thornber 
149*6513c29fSJoe Thornber /*
150*6513c29fSJoe Thornber  * Allocate a new array block.  The caller will need to unlock block.
151*6513c29fSJoe Thornber  */
152*6513c29fSJoe Thornber static int alloc_ablock(struct dm_array_info *info, size_t size_of_block,
153*6513c29fSJoe Thornber 			uint32_t max_entries,
154*6513c29fSJoe Thornber 			struct dm_block **block, struct array_block **ab)
155*6513c29fSJoe Thornber {
156*6513c29fSJoe Thornber 	int r;
157*6513c29fSJoe Thornber 
158*6513c29fSJoe Thornber 	r = dm_tm_new_block(info->btree_info.tm, &array_validator, block);
159*6513c29fSJoe Thornber 	if (r)
160*6513c29fSJoe Thornber 		return r;
161*6513c29fSJoe Thornber 
162*6513c29fSJoe Thornber 	(*ab) = dm_block_data(*block);
163*6513c29fSJoe Thornber 	(*ab)->max_entries = cpu_to_le32(max_entries);
164*6513c29fSJoe Thornber 	(*ab)->nr_entries = cpu_to_le32(0);
165*6513c29fSJoe Thornber 	(*ab)->value_size = cpu_to_le32(info->value_type.size);
166*6513c29fSJoe Thornber 
167*6513c29fSJoe Thornber 	return 0;
168*6513c29fSJoe Thornber }
169*6513c29fSJoe Thornber 
170*6513c29fSJoe Thornber /*
171*6513c29fSJoe Thornber  * Pad an array block out with a particular value.  Every instance will
172*6513c29fSJoe Thornber  * cause an increment of the value_type.  new_nr must always be more than
173*6513c29fSJoe Thornber  * the current number of entries.
174*6513c29fSJoe Thornber  */
175*6513c29fSJoe Thornber static void fill_ablock(struct dm_array_info *info, struct array_block *ab,
176*6513c29fSJoe Thornber 			const void *value, unsigned new_nr)
177*6513c29fSJoe Thornber {
178*6513c29fSJoe Thornber 	unsigned i;
179*6513c29fSJoe Thornber 	uint32_t nr_entries;
180*6513c29fSJoe Thornber 	struct dm_btree_value_type *vt = &info->value_type;
181*6513c29fSJoe Thornber 
182*6513c29fSJoe Thornber 	BUG_ON(new_nr > le32_to_cpu(ab->max_entries));
183*6513c29fSJoe Thornber 	BUG_ON(new_nr < le32_to_cpu(ab->nr_entries));
184*6513c29fSJoe Thornber 
185*6513c29fSJoe Thornber 	nr_entries = le32_to_cpu(ab->nr_entries);
186*6513c29fSJoe Thornber 	for (i = nr_entries; i < new_nr; i++) {
187*6513c29fSJoe Thornber 		if (vt->inc)
188*6513c29fSJoe Thornber 			vt->inc(vt->context, value);
189*6513c29fSJoe Thornber 		memcpy(element_at(info, ab, i), value, vt->size);
190*6513c29fSJoe Thornber 	}
191*6513c29fSJoe Thornber 	ab->nr_entries = cpu_to_le32(new_nr);
192*6513c29fSJoe Thornber }
193*6513c29fSJoe Thornber 
194*6513c29fSJoe Thornber /*
195*6513c29fSJoe Thornber  * Remove some entries from the back of an array block.  Every value
196*6513c29fSJoe Thornber  * removed will be decremented.  new_nr must be <= the current number of
197*6513c29fSJoe Thornber  * entries.
198*6513c29fSJoe Thornber  */
199*6513c29fSJoe Thornber static void trim_ablock(struct dm_array_info *info, struct array_block *ab,
200*6513c29fSJoe Thornber 			unsigned new_nr)
201*6513c29fSJoe Thornber {
202*6513c29fSJoe Thornber 	unsigned i;
203*6513c29fSJoe Thornber 	uint32_t nr_entries;
204*6513c29fSJoe Thornber 	struct dm_btree_value_type *vt = &info->value_type;
205*6513c29fSJoe Thornber 
206*6513c29fSJoe Thornber 	BUG_ON(new_nr > le32_to_cpu(ab->max_entries));
207*6513c29fSJoe Thornber 	BUG_ON(new_nr > le32_to_cpu(ab->nr_entries));
208*6513c29fSJoe Thornber 
209*6513c29fSJoe Thornber 	nr_entries = le32_to_cpu(ab->nr_entries);
210*6513c29fSJoe Thornber 	for (i = nr_entries; i > new_nr; i--)
211*6513c29fSJoe Thornber 		if (vt->dec)
212*6513c29fSJoe Thornber 			vt->dec(vt->context, element_at(info, ab, i - 1));
213*6513c29fSJoe Thornber 	ab->nr_entries = cpu_to_le32(new_nr);
214*6513c29fSJoe Thornber }
215*6513c29fSJoe Thornber 
216*6513c29fSJoe Thornber /*
217*6513c29fSJoe Thornber  * Read locks a block, and coerces it to an array block.  The caller must
218*6513c29fSJoe Thornber  * unlock 'block' when finished.
219*6513c29fSJoe Thornber  */
220*6513c29fSJoe Thornber static int get_ablock(struct dm_array_info *info, dm_block_t b,
221*6513c29fSJoe Thornber 		      struct dm_block **block, struct array_block **ab)
222*6513c29fSJoe Thornber {
223*6513c29fSJoe Thornber 	int r;
224*6513c29fSJoe Thornber 
225*6513c29fSJoe Thornber 	r = dm_tm_read_lock(info->btree_info.tm, b, &array_validator, block);
226*6513c29fSJoe Thornber 	if (r)
227*6513c29fSJoe Thornber 		return r;
228*6513c29fSJoe Thornber 
229*6513c29fSJoe Thornber 	*ab = dm_block_data(*block);
230*6513c29fSJoe Thornber 	return 0;
231*6513c29fSJoe Thornber }
232*6513c29fSJoe Thornber 
233*6513c29fSJoe Thornber /*
234*6513c29fSJoe Thornber  * Unlocks an array block.
235*6513c29fSJoe Thornber  */
236*6513c29fSJoe Thornber static int unlock_ablock(struct dm_array_info *info, struct dm_block *block)
237*6513c29fSJoe Thornber {
238*6513c29fSJoe Thornber 	return dm_tm_unlock(info->btree_info.tm, block);
239*6513c29fSJoe Thornber }
240*6513c29fSJoe Thornber 
241*6513c29fSJoe Thornber /*----------------------------------------------------------------*/
242*6513c29fSJoe Thornber 
243*6513c29fSJoe Thornber /*
244*6513c29fSJoe Thornber  * Btree manipulation.
245*6513c29fSJoe Thornber  */
246*6513c29fSJoe Thornber 
247*6513c29fSJoe Thornber /*
248*6513c29fSJoe Thornber  * Looks up an array block in the btree, and then read locks it.
249*6513c29fSJoe Thornber  *
250*6513c29fSJoe Thornber  * index is the index of the index of the array_block, (ie. the array index
251*6513c29fSJoe Thornber  * / max_entries).
252*6513c29fSJoe Thornber  */
253*6513c29fSJoe Thornber static int lookup_ablock(struct dm_array_info *info, dm_block_t root,
254*6513c29fSJoe Thornber 			 unsigned index, struct dm_block **block,
255*6513c29fSJoe Thornber 			 struct array_block **ab)
256*6513c29fSJoe Thornber {
257*6513c29fSJoe Thornber 	int r;
258*6513c29fSJoe Thornber 	uint64_t key = index;
259*6513c29fSJoe Thornber 	__le64 block_le;
260*6513c29fSJoe Thornber 
261*6513c29fSJoe Thornber 	r = dm_btree_lookup(&info->btree_info, root, &key, &block_le);
262*6513c29fSJoe Thornber 	if (r)
263*6513c29fSJoe Thornber 		return r;
264*6513c29fSJoe Thornber 
265*6513c29fSJoe Thornber 	return get_ablock(info, le64_to_cpu(block_le), block, ab);
266*6513c29fSJoe Thornber }
267*6513c29fSJoe Thornber 
268*6513c29fSJoe Thornber /*
269*6513c29fSJoe Thornber  * Insert an array block into the btree.  The block is _not_ unlocked.
270*6513c29fSJoe Thornber  */
271*6513c29fSJoe Thornber static int insert_ablock(struct dm_array_info *info, uint64_t index,
272*6513c29fSJoe Thornber 			 struct dm_block *block, dm_block_t *root)
273*6513c29fSJoe Thornber {
274*6513c29fSJoe Thornber 	__le64 block_le = cpu_to_le64(dm_block_location(block));
275*6513c29fSJoe Thornber 
276*6513c29fSJoe Thornber 	__dm_bless_for_disk(block_le);
277*6513c29fSJoe Thornber 	return dm_btree_insert(&info->btree_info, *root, &index, &block_le, root);
278*6513c29fSJoe Thornber }
279*6513c29fSJoe Thornber 
280*6513c29fSJoe Thornber /*
281*6513c29fSJoe Thornber  * Looks up an array block in the btree.  Then shadows it, and updates the
282*6513c29fSJoe Thornber  * btree to point to this new shadow.  'root' is an input/output parameter
283*6513c29fSJoe Thornber  * for both the current root block, and the new one.
284*6513c29fSJoe Thornber  */
285*6513c29fSJoe Thornber static int shadow_ablock(struct dm_array_info *info, dm_block_t *root,
286*6513c29fSJoe Thornber 			 unsigned index, struct dm_block **block,
287*6513c29fSJoe Thornber 			 struct array_block **ab)
288*6513c29fSJoe Thornber {
289*6513c29fSJoe Thornber 	int r, inc;
290*6513c29fSJoe Thornber 	uint64_t key = index;
291*6513c29fSJoe Thornber 	dm_block_t b;
292*6513c29fSJoe Thornber 	__le64 block_le;
293*6513c29fSJoe Thornber 
294*6513c29fSJoe Thornber 	/*
295*6513c29fSJoe Thornber 	 * lookup
296*6513c29fSJoe Thornber 	 */
297*6513c29fSJoe Thornber 	r = dm_btree_lookup(&info->btree_info, *root, &key, &block_le);
298*6513c29fSJoe Thornber 	if (r)
299*6513c29fSJoe Thornber 		return r;
300*6513c29fSJoe Thornber 	b = le64_to_cpu(block_le);
301*6513c29fSJoe Thornber 
302*6513c29fSJoe Thornber 	/*
303*6513c29fSJoe Thornber 	 * shadow
304*6513c29fSJoe Thornber 	 */
305*6513c29fSJoe Thornber 	r = dm_tm_shadow_block(info->btree_info.tm, b,
306*6513c29fSJoe Thornber 			       &array_validator, block, &inc);
307*6513c29fSJoe Thornber 	if (r)
308*6513c29fSJoe Thornber 		return r;
309*6513c29fSJoe Thornber 
310*6513c29fSJoe Thornber 	*ab = dm_block_data(*block);
311*6513c29fSJoe Thornber 	if (inc)
312*6513c29fSJoe Thornber 		inc_ablock_entries(info, *ab);
313*6513c29fSJoe Thornber 
314*6513c29fSJoe Thornber 	/*
315*6513c29fSJoe Thornber 	 * Reinsert.
316*6513c29fSJoe Thornber 	 *
317*6513c29fSJoe Thornber 	 * The shadow op will often be a noop.  Only insert if it really
318*6513c29fSJoe Thornber 	 * copied data.
319*6513c29fSJoe Thornber 	 */
320*6513c29fSJoe Thornber 	if (dm_block_location(*block) != b)
321*6513c29fSJoe Thornber 		r = insert_ablock(info, index, *block, root);
322*6513c29fSJoe Thornber 
323*6513c29fSJoe Thornber 	return r;
324*6513c29fSJoe Thornber }
325*6513c29fSJoe Thornber 
326*6513c29fSJoe Thornber /*
327*6513c29fSJoe Thornber  * Allocate an new array block, and fill it with some values.
328*6513c29fSJoe Thornber  */
329*6513c29fSJoe Thornber static int insert_new_ablock(struct dm_array_info *info, size_t size_of_block,
330*6513c29fSJoe Thornber 			     uint32_t max_entries,
331*6513c29fSJoe Thornber 			     unsigned block_index, uint32_t nr,
332*6513c29fSJoe Thornber 			     const void *value, dm_block_t *root)
333*6513c29fSJoe Thornber {
334*6513c29fSJoe Thornber 	int r;
335*6513c29fSJoe Thornber 	struct dm_block *block;
336*6513c29fSJoe Thornber 	struct array_block *ab;
337*6513c29fSJoe Thornber 
338*6513c29fSJoe Thornber 	r = alloc_ablock(info, size_of_block, max_entries, &block, &ab);
339*6513c29fSJoe Thornber 	if (r)
340*6513c29fSJoe Thornber 		return r;
341*6513c29fSJoe Thornber 
342*6513c29fSJoe Thornber 	fill_ablock(info, ab, value, nr);
343*6513c29fSJoe Thornber 	r = insert_ablock(info, block_index, block, root);
344*6513c29fSJoe Thornber 	unlock_ablock(info, block);
345*6513c29fSJoe Thornber 
346*6513c29fSJoe Thornber 	return r;
347*6513c29fSJoe Thornber }
348*6513c29fSJoe Thornber 
349*6513c29fSJoe Thornber static int insert_full_ablocks(struct dm_array_info *info, size_t size_of_block,
350*6513c29fSJoe Thornber 			       unsigned begin_block, unsigned end_block,
351*6513c29fSJoe Thornber 			       unsigned max_entries, const void *value,
352*6513c29fSJoe Thornber 			       dm_block_t *root)
353*6513c29fSJoe Thornber {
354*6513c29fSJoe Thornber 	int r = 0;
355*6513c29fSJoe Thornber 
356*6513c29fSJoe Thornber 	for (; !r && begin_block != end_block; begin_block++)
357*6513c29fSJoe Thornber 		r = insert_new_ablock(info, size_of_block, max_entries, begin_block, max_entries, value, root);
358*6513c29fSJoe Thornber 
359*6513c29fSJoe Thornber 	return r;
360*6513c29fSJoe Thornber }
361*6513c29fSJoe Thornber 
362*6513c29fSJoe Thornber /*
363*6513c29fSJoe Thornber  * There are a bunch of functions involved with resizing an array.  This
364*6513c29fSJoe Thornber  * structure holds information that commonly needed by them.  Purely here
365*6513c29fSJoe Thornber  * to reduce parameter count.
366*6513c29fSJoe Thornber  */
367*6513c29fSJoe Thornber struct resize {
368*6513c29fSJoe Thornber 	/*
369*6513c29fSJoe Thornber 	 * Describes the array.
370*6513c29fSJoe Thornber 	 */
371*6513c29fSJoe Thornber 	struct dm_array_info *info;
372*6513c29fSJoe Thornber 
373*6513c29fSJoe Thornber 	/*
374*6513c29fSJoe Thornber 	 * The current root of the array.  This gets updated.
375*6513c29fSJoe Thornber 	 */
376*6513c29fSJoe Thornber 	dm_block_t root;
377*6513c29fSJoe Thornber 
378*6513c29fSJoe Thornber 	/*
379*6513c29fSJoe Thornber 	 * Metadata block size.  Used to calculate the nr entries in an
380*6513c29fSJoe Thornber 	 * array block.
381*6513c29fSJoe Thornber 	 */
382*6513c29fSJoe Thornber 	size_t size_of_block;
383*6513c29fSJoe Thornber 
384*6513c29fSJoe Thornber 	/*
385*6513c29fSJoe Thornber 	 * Maximum nr entries in an array block.
386*6513c29fSJoe Thornber 	 */
387*6513c29fSJoe Thornber 	unsigned max_entries;
388*6513c29fSJoe Thornber 
389*6513c29fSJoe Thornber 	/*
390*6513c29fSJoe Thornber 	 * nr of completely full blocks in the array.
391*6513c29fSJoe Thornber 	 *
392*6513c29fSJoe Thornber 	 * 'old' refers to before the resize, 'new' after.
393*6513c29fSJoe Thornber 	 */
394*6513c29fSJoe Thornber 	unsigned old_nr_full_blocks, new_nr_full_blocks;
395*6513c29fSJoe Thornber 
396*6513c29fSJoe Thornber 	/*
397*6513c29fSJoe Thornber 	 * Number of entries in the final block.  0 iff only full blocks in
398*6513c29fSJoe Thornber 	 * the array.
399*6513c29fSJoe Thornber 	 */
400*6513c29fSJoe Thornber 	unsigned old_nr_entries_in_last_block, new_nr_entries_in_last_block;
401*6513c29fSJoe Thornber 
402*6513c29fSJoe Thornber 	/*
403*6513c29fSJoe Thornber 	 * The default value used when growing the array.
404*6513c29fSJoe Thornber 	 */
405*6513c29fSJoe Thornber 	const void *value;
406*6513c29fSJoe Thornber };
407*6513c29fSJoe Thornber 
408*6513c29fSJoe Thornber /*
409*6513c29fSJoe Thornber  * Removes a consecutive set of array blocks from the btree.  The values
410*6513c29fSJoe Thornber  * in block are decremented as a side effect of the btree remove.
411*6513c29fSJoe Thornber  *
412*6513c29fSJoe Thornber  * begin_index - the index of the first array block to remove.
413*6513c29fSJoe Thornber  * end_index - the one-past-the-end value.  ie. this block is not removed.
414*6513c29fSJoe Thornber  */
415*6513c29fSJoe Thornber static int drop_blocks(struct resize *resize, unsigned begin_index,
416*6513c29fSJoe Thornber 		       unsigned end_index)
417*6513c29fSJoe Thornber {
418*6513c29fSJoe Thornber 	int r;
419*6513c29fSJoe Thornber 
420*6513c29fSJoe Thornber 	while (begin_index != end_index) {
421*6513c29fSJoe Thornber 		uint64_t key = begin_index++;
422*6513c29fSJoe Thornber 		r = dm_btree_remove(&resize->info->btree_info, resize->root,
423*6513c29fSJoe Thornber 				    &key, &resize->root);
424*6513c29fSJoe Thornber 		if (r)
425*6513c29fSJoe Thornber 			return r;
426*6513c29fSJoe Thornber 	}
427*6513c29fSJoe Thornber 
428*6513c29fSJoe Thornber 	return 0;
429*6513c29fSJoe Thornber }
430*6513c29fSJoe Thornber 
431*6513c29fSJoe Thornber /*
432*6513c29fSJoe Thornber  * Calculates how many blocks are needed for the array.
433*6513c29fSJoe Thornber  */
434*6513c29fSJoe Thornber static unsigned total_nr_blocks_needed(unsigned nr_full_blocks,
435*6513c29fSJoe Thornber 				       unsigned nr_entries_in_last_block)
436*6513c29fSJoe Thornber {
437*6513c29fSJoe Thornber 	return nr_full_blocks + (nr_entries_in_last_block ? 1 : 0);
438*6513c29fSJoe Thornber }
439*6513c29fSJoe Thornber 
440*6513c29fSJoe Thornber /*
441*6513c29fSJoe Thornber  * Shrink an array.
442*6513c29fSJoe Thornber  */
443*6513c29fSJoe Thornber static int shrink(struct resize *resize)
444*6513c29fSJoe Thornber {
445*6513c29fSJoe Thornber 	int r;
446*6513c29fSJoe Thornber 	unsigned begin, end;
447*6513c29fSJoe Thornber 	struct dm_block *block;
448*6513c29fSJoe Thornber 	struct array_block *ab;
449*6513c29fSJoe Thornber 
450*6513c29fSJoe Thornber 	/*
451*6513c29fSJoe Thornber 	 * Lose some blocks from the back?
452*6513c29fSJoe Thornber 	 */
453*6513c29fSJoe Thornber 	if (resize->new_nr_full_blocks < resize->old_nr_full_blocks) {
454*6513c29fSJoe Thornber 		begin = total_nr_blocks_needed(resize->new_nr_full_blocks,
455*6513c29fSJoe Thornber 					       resize->new_nr_entries_in_last_block);
456*6513c29fSJoe Thornber 		end = total_nr_blocks_needed(resize->old_nr_full_blocks,
457*6513c29fSJoe Thornber 					     resize->old_nr_entries_in_last_block);
458*6513c29fSJoe Thornber 
459*6513c29fSJoe Thornber 		r = drop_blocks(resize, begin, end);
460*6513c29fSJoe Thornber 		if (r)
461*6513c29fSJoe Thornber 			return r;
462*6513c29fSJoe Thornber 	}
463*6513c29fSJoe Thornber 
464*6513c29fSJoe Thornber 	/*
465*6513c29fSJoe Thornber 	 * Trim the new tail block
466*6513c29fSJoe Thornber 	 */
467*6513c29fSJoe Thornber 	if (resize->new_nr_entries_in_last_block) {
468*6513c29fSJoe Thornber 		r = shadow_ablock(resize->info, &resize->root,
469*6513c29fSJoe Thornber 				  resize->new_nr_full_blocks, &block, &ab);
470*6513c29fSJoe Thornber 		if (r)
471*6513c29fSJoe Thornber 			return r;
472*6513c29fSJoe Thornber 
473*6513c29fSJoe Thornber 		trim_ablock(resize->info, ab, resize->new_nr_entries_in_last_block);
474*6513c29fSJoe Thornber 		unlock_ablock(resize->info, block);
475*6513c29fSJoe Thornber 	}
476*6513c29fSJoe Thornber 
477*6513c29fSJoe Thornber 	return 0;
478*6513c29fSJoe Thornber }
479*6513c29fSJoe Thornber 
480*6513c29fSJoe Thornber /*
481*6513c29fSJoe Thornber  * Grow an array.
482*6513c29fSJoe Thornber  */
483*6513c29fSJoe Thornber static int grow_extend_tail_block(struct resize *resize, uint32_t new_nr_entries)
484*6513c29fSJoe Thornber {
485*6513c29fSJoe Thornber 	int r;
486*6513c29fSJoe Thornber 	struct dm_block *block;
487*6513c29fSJoe Thornber 	struct array_block *ab;
488*6513c29fSJoe Thornber 
489*6513c29fSJoe Thornber 	r = shadow_ablock(resize->info, &resize->root,
490*6513c29fSJoe Thornber 			  resize->old_nr_full_blocks, &block, &ab);
491*6513c29fSJoe Thornber 	if (r)
492*6513c29fSJoe Thornber 		return r;
493*6513c29fSJoe Thornber 
494*6513c29fSJoe Thornber 	fill_ablock(resize->info, ab, resize->value, new_nr_entries);
495*6513c29fSJoe Thornber 	unlock_ablock(resize->info, block);
496*6513c29fSJoe Thornber 
497*6513c29fSJoe Thornber 	return r;
498*6513c29fSJoe Thornber }
499*6513c29fSJoe Thornber 
500*6513c29fSJoe Thornber static int grow_add_tail_block(struct resize *resize)
501*6513c29fSJoe Thornber {
502*6513c29fSJoe Thornber 	return insert_new_ablock(resize->info, resize->size_of_block,
503*6513c29fSJoe Thornber 				 resize->max_entries,
504*6513c29fSJoe Thornber 				 resize->new_nr_full_blocks,
505*6513c29fSJoe Thornber 				 resize->new_nr_entries_in_last_block,
506*6513c29fSJoe Thornber 				 resize->value, &resize->root);
507*6513c29fSJoe Thornber }
508*6513c29fSJoe Thornber 
509*6513c29fSJoe Thornber static int grow_needs_more_blocks(struct resize *resize)
510*6513c29fSJoe Thornber {
511*6513c29fSJoe Thornber 	int r;
512*6513c29fSJoe Thornber 
513*6513c29fSJoe Thornber 	if (resize->old_nr_entries_in_last_block > 0) {
514*6513c29fSJoe Thornber 		r = grow_extend_tail_block(resize, resize->max_entries);
515*6513c29fSJoe Thornber 		if (r)
516*6513c29fSJoe Thornber 			return r;
517*6513c29fSJoe Thornber 	}
518*6513c29fSJoe Thornber 
519*6513c29fSJoe Thornber 	r = insert_full_ablocks(resize->info, resize->size_of_block,
520*6513c29fSJoe Thornber 				resize->old_nr_full_blocks,
521*6513c29fSJoe Thornber 				resize->new_nr_full_blocks,
522*6513c29fSJoe Thornber 				resize->max_entries, resize->value,
523*6513c29fSJoe Thornber 				&resize->root);
524*6513c29fSJoe Thornber 	if (r)
525*6513c29fSJoe Thornber 		return r;
526*6513c29fSJoe Thornber 
527*6513c29fSJoe Thornber 	if (resize->new_nr_entries_in_last_block)
528*6513c29fSJoe Thornber 		r = grow_add_tail_block(resize);
529*6513c29fSJoe Thornber 
530*6513c29fSJoe Thornber 	return r;
531*6513c29fSJoe Thornber }
532*6513c29fSJoe Thornber 
533*6513c29fSJoe Thornber static int grow(struct resize *resize)
534*6513c29fSJoe Thornber {
535*6513c29fSJoe Thornber 	if (resize->new_nr_full_blocks > resize->old_nr_full_blocks)
536*6513c29fSJoe Thornber 		return grow_needs_more_blocks(resize);
537*6513c29fSJoe Thornber 
538*6513c29fSJoe Thornber 	else if (resize->old_nr_entries_in_last_block)
539*6513c29fSJoe Thornber 		return grow_extend_tail_block(resize, resize->new_nr_entries_in_last_block);
540*6513c29fSJoe Thornber 
541*6513c29fSJoe Thornber 	else
542*6513c29fSJoe Thornber 		return grow_add_tail_block(resize);
543*6513c29fSJoe Thornber }
544*6513c29fSJoe Thornber 
545*6513c29fSJoe Thornber /*----------------------------------------------------------------*/
546*6513c29fSJoe Thornber 
547*6513c29fSJoe Thornber /*
548*6513c29fSJoe Thornber  * These are the value_type functions for the btree elements, which point
549*6513c29fSJoe Thornber  * to array blocks.
550*6513c29fSJoe Thornber  */
551*6513c29fSJoe Thornber static void block_inc(void *context, const void *value)
552*6513c29fSJoe Thornber {
553*6513c29fSJoe Thornber 	__le64 block_le;
554*6513c29fSJoe Thornber 	struct dm_array_info *info = context;
555*6513c29fSJoe Thornber 
556*6513c29fSJoe Thornber 	memcpy(&block_le, value, sizeof(block_le));
557*6513c29fSJoe Thornber 	dm_tm_inc(info->btree_info.tm, le64_to_cpu(block_le));
558*6513c29fSJoe Thornber }
559*6513c29fSJoe Thornber 
560*6513c29fSJoe Thornber static void block_dec(void *context, const void *value)
561*6513c29fSJoe Thornber {
562*6513c29fSJoe Thornber 	int r;
563*6513c29fSJoe Thornber 	uint64_t b;
564*6513c29fSJoe Thornber 	__le64 block_le;
565*6513c29fSJoe Thornber 	uint32_t ref_count;
566*6513c29fSJoe Thornber 	struct dm_block *block;
567*6513c29fSJoe Thornber 	struct array_block *ab;
568*6513c29fSJoe Thornber 	struct dm_array_info *info = context;
569*6513c29fSJoe Thornber 
570*6513c29fSJoe Thornber 	memcpy(&block_le, value, sizeof(block_le));
571*6513c29fSJoe Thornber 	b = le64_to_cpu(block_le);
572*6513c29fSJoe Thornber 
573*6513c29fSJoe Thornber 	r = dm_tm_ref(info->btree_info.tm, b, &ref_count);
574*6513c29fSJoe Thornber 	if (r) {
575*6513c29fSJoe Thornber 		DMERR_LIMIT("couldn't get reference count for block %llu",
576*6513c29fSJoe Thornber 			    (unsigned long long) b);
577*6513c29fSJoe Thornber 		return;
578*6513c29fSJoe Thornber 	}
579*6513c29fSJoe Thornber 
580*6513c29fSJoe Thornber 	if (ref_count == 1) {
581*6513c29fSJoe Thornber 		/*
582*6513c29fSJoe Thornber 		 * We're about to drop the last reference to this ablock.
583*6513c29fSJoe Thornber 		 * So we need to decrement the ref count of the contents.
584*6513c29fSJoe Thornber 		 */
585*6513c29fSJoe Thornber 		r = get_ablock(info, b, &block, &ab);
586*6513c29fSJoe Thornber 		if (r) {
587*6513c29fSJoe Thornber 			DMERR_LIMIT("couldn't get array block %llu",
588*6513c29fSJoe Thornber 				    (unsigned long long) b);
589*6513c29fSJoe Thornber 			return;
590*6513c29fSJoe Thornber 		}
591*6513c29fSJoe Thornber 
592*6513c29fSJoe Thornber 		dec_ablock_entries(info, ab);
593*6513c29fSJoe Thornber 		unlock_ablock(info, block);
594*6513c29fSJoe Thornber 	}
595*6513c29fSJoe Thornber 
596*6513c29fSJoe Thornber 	dm_tm_dec(info->btree_info.tm, b);
597*6513c29fSJoe Thornber }
598*6513c29fSJoe Thornber 
599*6513c29fSJoe Thornber static int block_equal(void *context, const void *value1, const void *value2)
600*6513c29fSJoe Thornber {
601*6513c29fSJoe Thornber 	return !memcmp(value1, value2, sizeof(__le64));
602*6513c29fSJoe Thornber }
603*6513c29fSJoe Thornber 
604*6513c29fSJoe Thornber /*----------------------------------------------------------------*/
605*6513c29fSJoe Thornber 
606*6513c29fSJoe Thornber void dm_array_info_init(struct dm_array_info *info,
607*6513c29fSJoe Thornber 			struct dm_transaction_manager *tm,
608*6513c29fSJoe Thornber 			struct dm_btree_value_type *vt)
609*6513c29fSJoe Thornber {
610*6513c29fSJoe Thornber 	struct dm_btree_value_type *bvt = &info->btree_info.value_type;
611*6513c29fSJoe Thornber 
612*6513c29fSJoe Thornber 	memcpy(&info->value_type, vt, sizeof(info->value_type));
613*6513c29fSJoe Thornber 	info->btree_info.tm = tm;
614*6513c29fSJoe Thornber 	info->btree_info.levels = 1;
615*6513c29fSJoe Thornber 
616*6513c29fSJoe Thornber 	bvt->context = info;
617*6513c29fSJoe Thornber 	bvt->size = sizeof(__le64);
618*6513c29fSJoe Thornber 	bvt->inc = block_inc;
619*6513c29fSJoe Thornber 	bvt->dec = block_dec;
620*6513c29fSJoe Thornber 	bvt->equal = block_equal;
621*6513c29fSJoe Thornber }
622*6513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_info_init);
623*6513c29fSJoe Thornber 
624*6513c29fSJoe Thornber int dm_array_empty(struct dm_array_info *info, dm_block_t *root)
625*6513c29fSJoe Thornber {
626*6513c29fSJoe Thornber 	return dm_btree_empty(&info->btree_info, root);
627*6513c29fSJoe Thornber }
628*6513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_empty);
629*6513c29fSJoe Thornber 
630*6513c29fSJoe Thornber static int array_resize(struct dm_array_info *info, dm_block_t root,
631*6513c29fSJoe Thornber 			uint32_t old_size, uint32_t new_size,
632*6513c29fSJoe Thornber 			const void *value, dm_block_t *new_root)
633*6513c29fSJoe Thornber {
634*6513c29fSJoe Thornber 	int r;
635*6513c29fSJoe Thornber 	struct resize resize;
636*6513c29fSJoe Thornber 
637*6513c29fSJoe Thornber 	if (old_size == new_size)
638*6513c29fSJoe Thornber 		return 0;
639*6513c29fSJoe Thornber 
640*6513c29fSJoe Thornber 	resize.info = info;
641*6513c29fSJoe Thornber 	resize.root = root;
642*6513c29fSJoe Thornber 	resize.size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm));
643*6513c29fSJoe Thornber 	resize.max_entries = calc_max_entries(info->value_type.size,
644*6513c29fSJoe Thornber 					      resize.size_of_block);
645*6513c29fSJoe Thornber 
646*6513c29fSJoe Thornber 	resize.old_nr_full_blocks = old_size / resize.max_entries;
647*6513c29fSJoe Thornber 	resize.old_nr_entries_in_last_block = old_size % resize.max_entries;
648*6513c29fSJoe Thornber 	resize.new_nr_full_blocks = new_size / resize.max_entries;
649*6513c29fSJoe Thornber 	resize.new_nr_entries_in_last_block = new_size % resize.max_entries;
650*6513c29fSJoe Thornber 	resize.value = value;
651*6513c29fSJoe Thornber 
652*6513c29fSJoe Thornber 	r = ((new_size > old_size) ? grow : shrink)(&resize);
653*6513c29fSJoe Thornber 	if (r)
654*6513c29fSJoe Thornber 		return r;
655*6513c29fSJoe Thornber 
656*6513c29fSJoe Thornber 	*new_root = resize.root;
657*6513c29fSJoe Thornber 	return 0;
658*6513c29fSJoe Thornber }
659*6513c29fSJoe Thornber 
660*6513c29fSJoe Thornber int dm_array_resize(struct dm_array_info *info, dm_block_t root,
661*6513c29fSJoe Thornber 		    uint32_t old_size, uint32_t new_size,
662*6513c29fSJoe Thornber 		    const void *value, dm_block_t *new_root)
663*6513c29fSJoe Thornber 		    __dm_written_to_disk(value)
664*6513c29fSJoe Thornber {
665*6513c29fSJoe Thornber 	int r = array_resize(info, root, old_size, new_size, value, new_root);
666*6513c29fSJoe Thornber 	__dm_unbless_for_disk(value);
667*6513c29fSJoe Thornber 	return r;
668*6513c29fSJoe Thornber }
669*6513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_resize);
670*6513c29fSJoe Thornber 
671*6513c29fSJoe Thornber int dm_array_del(struct dm_array_info *info, dm_block_t root)
672*6513c29fSJoe Thornber {
673*6513c29fSJoe Thornber 	return dm_btree_del(&info->btree_info, root);
674*6513c29fSJoe Thornber }
675*6513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_del);
676*6513c29fSJoe Thornber 
677*6513c29fSJoe Thornber int dm_array_get_value(struct dm_array_info *info, dm_block_t root,
678*6513c29fSJoe Thornber 		       uint32_t index, void *value_le)
679*6513c29fSJoe Thornber {
680*6513c29fSJoe Thornber 	int r;
681*6513c29fSJoe Thornber 	struct dm_block *block;
682*6513c29fSJoe Thornber 	struct array_block *ab;
683*6513c29fSJoe Thornber 	size_t size_of_block;
684*6513c29fSJoe Thornber 	unsigned entry, max_entries;
685*6513c29fSJoe Thornber 
686*6513c29fSJoe Thornber 	size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm));
687*6513c29fSJoe Thornber 	max_entries = calc_max_entries(info->value_type.size, size_of_block);
688*6513c29fSJoe Thornber 
689*6513c29fSJoe Thornber 	r = lookup_ablock(info, root, index / max_entries, &block, &ab);
690*6513c29fSJoe Thornber 	if (r)
691*6513c29fSJoe Thornber 		return r;
692*6513c29fSJoe Thornber 
693*6513c29fSJoe Thornber 	entry = index % max_entries;
694*6513c29fSJoe Thornber 	if (entry >= le32_to_cpu(ab->nr_entries))
695*6513c29fSJoe Thornber 		r = -ENODATA;
696*6513c29fSJoe Thornber 	else
697*6513c29fSJoe Thornber 		memcpy(value_le, element_at(info, ab, entry),
698*6513c29fSJoe Thornber 		       info->value_type.size);
699*6513c29fSJoe Thornber 
700*6513c29fSJoe Thornber 	unlock_ablock(info, block);
701*6513c29fSJoe Thornber 	return r;
702*6513c29fSJoe Thornber }
703*6513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_get_value);
704*6513c29fSJoe Thornber 
705*6513c29fSJoe Thornber static int array_set_value(struct dm_array_info *info, dm_block_t root,
706*6513c29fSJoe Thornber 			   uint32_t index, const void *value, dm_block_t *new_root)
707*6513c29fSJoe Thornber {
708*6513c29fSJoe Thornber 	int r;
709*6513c29fSJoe Thornber 	struct dm_block *block;
710*6513c29fSJoe Thornber 	struct array_block *ab;
711*6513c29fSJoe Thornber 	size_t size_of_block;
712*6513c29fSJoe Thornber 	unsigned max_entries;
713*6513c29fSJoe Thornber 	unsigned entry;
714*6513c29fSJoe Thornber 	void *old_value;
715*6513c29fSJoe Thornber 	struct dm_btree_value_type *vt = &info->value_type;
716*6513c29fSJoe Thornber 
717*6513c29fSJoe Thornber 	size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm));
718*6513c29fSJoe Thornber 	max_entries = calc_max_entries(info->value_type.size, size_of_block);
719*6513c29fSJoe Thornber 
720*6513c29fSJoe Thornber 	r = shadow_ablock(info, &root, index / max_entries, &block, &ab);
721*6513c29fSJoe Thornber 	if (r)
722*6513c29fSJoe Thornber 		return r;
723*6513c29fSJoe Thornber 	*new_root = root;
724*6513c29fSJoe Thornber 
725*6513c29fSJoe Thornber 	entry = index % max_entries;
726*6513c29fSJoe Thornber 	if (entry >= le32_to_cpu(ab->nr_entries)) {
727*6513c29fSJoe Thornber 		r = -ENODATA;
728*6513c29fSJoe Thornber 		goto out;
729*6513c29fSJoe Thornber 	}
730*6513c29fSJoe Thornber 
731*6513c29fSJoe Thornber 	old_value = element_at(info, ab, entry);
732*6513c29fSJoe Thornber 	if (vt->dec &&
733*6513c29fSJoe Thornber 	    (!vt->equal || !vt->equal(vt->context, old_value, value))) {
734*6513c29fSJoe Thornber 		vt->dec(vt->context, old_value);
735*6513c29fSJoe Thornber 		if (vt->inc)
736*6513c29fSJoe Thornber 			vt->inc(vt->context, value);
737*6513c29fSJoe Thornber 	}
738*6513c29fSJoe Thornber 
739*6513c29fSJoe Thornber 	memcpy(old_value, value, info->value_type.size);
740*6513c29fSJoe Thornber 
741*6513c29fSJoe Thornber out:
742*6513c29fSJoe Thornber 	unlock_ablock(info, block);
743*6513c29fSJoe Thornber 	return r;
744*6513c29fSJoe Thornber }
745*6513c29fSJoe Thornber 
746*6513c29fSJoe Thornber int dm_array_set_value(struct dm_array_info *info, dm_block_t root,
747*6513c29fSJoe Thornber 		 uint32_t index, const void *value, dm_block_t *new_root)
748*6513c29fSJoe Thornber 		 __dm_written_to_disk(value)
749*6513c29fSJoe Thornber {
750*6513c29fSJoe Thornber 	int r;
751*6513c29fSJoe Thornber 
752*6513c29fSJoe Thornber 	r = array_set_value(info, root, index, value, new_root);
753*6513c29fSJoe Thornber 	__dm_unbless_for_disk(value);
754*6513c29fSJoe Thornber 	return r;
755*6513c29fSJoe Thornber }
756*6513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_set_value);
757*6513c29fSJoe Thornber 
758*6513c29fSJoe Thornber struct walk_info {
759*6513c29fSJoe Thornber 	struct dm_array_info *info;
760*6513c29fSJoe Thornber 	int (*fn)(void *context, uint64_t key, void *leaf);
761*6513c29fSJoe Thornber 	void *context;
762*6513c29fSJoe Thornber };
763*6513c29fSJoe Thornber 
764*6513c29fSJoe Thornber static int walk_ablock(void *context, uint64_t *keys, void *leaf)
765*6513c29fSJoe Thornber {
766*6513c29fSJoe Thornber 	struct walk_info *wi = context;
767*6513c29fSJoe Thornber 
768*6513c29fSJoe Thornber 	int r;
769*6513c29fSJoe Thornber 	unsigned i;
770*6513c29fSJoe Thornber 	__le64 block_le;
771*6513c29fSJoe Thornber 	unsigned nr_entries, max_entries;
772*6513c29fSJoe Thornber 	struct dm_block *block;
773*6513c29fSJoe Thornber 	struct array_block *ab;
774*6513c29fSJoe Thornber 
775*6513c29fSJoe Thornber 	memcpy(&block_le, leaf, sizeof(block_le));
776*6513c29fSJoe Thornber 	r = get_ablock(wi->info, le64_to_cpu(block_le), &block, &ab);
777*6513c29fSJoe Thornber 	if (r)
778*6513c29fSJoe Thornber 		return r;
779*6513c29fSJoe Thornber 
780*6513c29fSJoe Thornber 	max_entries = le32_to_cpu(ab->max_entries);
781*6513c29fSJoe Thornber 	nr_entries = le32_to_cpu(ab->nr_entries);
782*6513c29fSJoe Thornber 	for (i = 0; i < nr_entries; i++) {
783*6513c29fSJoe Thornber 		r = wi->fn(wi->context, keys[0] * max_entries + i,
784*6513c29fSJoe Thornber 			   element_at(wi->info, ab, i));
785*6513c29fSJoe Thornber 
786*6513c29fSJoe Thornber 		if (r)
787*6513c29fSJoe Thornber 			break;
788*6513c29fSJoe Thornber 	}
789*6513c29fSJoe Thornber 
790*6513c29fSJoe Thornber 	unlock_ablock(wi->info, block);
791*6513c29fSJoe Thornber 	return r;
792*6513c29fSJoe Thornber }
793*6513c29fSJoe Thornber 
794*6513c29fSJoe Thornber int dm_array_walk(struct dm_array_info *info, dm_block_t root,
795*6513c29fSJoe Thornber 		  int (*fn)(void *, uint64_t key, void *leaf),
796*6513c29fSJoe Thornber 		  void *context)
797*6513c29fSJoe Thornber {
798*6513c29fSJoe Thornber 	struct walk_info wi;
799*6513c29fSJoe Thornber 
800*6513c29fSJoe Thornber 	wi.info = info;
801*6513c29fSJoe Thornber 	wi.fn = fn;
802*6513c29fSJoe Thornber 	wi.context = context;
803*6513c29fSJoe Thornber 
804*6513c29fSJoe Thornber 	return dm_btree_walk(&info->btree_info, root, walk_ablock, &wi);
805*6513c29fSJoe Thornber }
806*6513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_walk);
807*6513c29fSJoe Thornber 
808*6513c29fSJoe Thornber /*----------------------------------------------------------------*/
809