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