16513c29fSJoe Thornber /* 26513c29fSJoe Thornber * Copyright (C) 2012 Red Hat, Inc. 36513c29fSJoe Thornber * 46513c29fSJoe Thornber * This file is released under the GPL. 56513c29fSJoe Thornber */ 66513c29fSJoe Thornber 76513c29fSJoe Thornber #include "dm-array.h" 86513c29fSJoe Thornber #include "dm-space-map.h" 96513c29fSJoe Thornber #include "dm-transaction-manager.h" 106513c29fSJoe Thornber 116513c29fSJoe Thornber #include <linux/export.h> 126513c29fSJoe Thornber #include <linux/device-mapper.h> 136513c29fSJoe Thornber 146513c29fSJoe Thornber #define DM_MSG_PREFIX "array" 156513c29fSJoe Thornber 166513c29fSJoe Thornber /*----------------------------------------------------------------*/ 176513c29fSJoe Thornber 186513c29fSJoe Thornber /* 196513c29fSJoe Thornber * The array is implemented as a fully populated btree, which points to 206513c29fSJoe Thornber * blocks that contain the packed values. This is more space efficient 216513c29fSJoe Thornber * than just using a btree since we don't store 1 key per value. 226513c29fSJoe Thornber */ 236513c29fSJoe Thornber struct array_block { 246513c29fSJoe Thornber __le32 csum; 256513c29fSJoe Thornber __le32 max_entries; 266513c29fSJoe Thornber __le32 nr_entries; 276513c29fSJoe Thornber __le32 value_size; 286513c29fSJoe Thornber __le64 blocknr; /* Block this node is supposed to live in. */ 296513c29fSJoe Thornber } __packed; 306513c29fSJoe Thornber 316513c29fSJoe Thornber /*----------------------------------------------------------------*/ 326513c29fSJoe Thornber 336513c29fSJoe Thornber /* 346513c29fSJoe Thornber * Validator methods. As usual we calculate a checksum, and also write the 356513c29fSJoe Thornber * block location into the header (paranoia about ssds remapping areas by 366513c29fSJoe Thornber * mistake). 376513c29fSJoe Thornber */ 386513c29fSJoe Thornber #define CSUM_XOR 595846735 396513c29fSJoe Thornber 406513c29fSJoe Thornber static void array_block_prepare_for_write(struct dm_block_validator *v, 416513c29fSJoe Thornber struct dm_block *b, 426513c29fSJoe Thornber size_t size_of_block) 436513c29fSJoe Thornber { 446513c29fSJoe Thornber struct array_block *bh_le = dm_block_data(b); 456513c29fSJoe Thornber 466513c29fSJoe Thornber bh_le->blocknr = cpu_to_le64(dm_block_location(b)); 476513c29fSJoe Thornber bh_le->csum = cpu_to_le32(dm_bm_checksum(&bh_le->max_entries, 486513c29fSJoe Thornber size_of_block - sizeof(__le32), 496513c29fSJoe Thornber CSUM_XOR)); 506513c29fSJoe Thornber } 516513c29fSJoe Thornber 526513c29fSJoe Thornber static int array_block_check(struct dm_block_validator *v, 536513c29fSJoe Thornber struct dm_block *b, 546513c29fSJoe Thornber size_t size_of_block) 556513c29fSJoe Thornber { 566513c29fSJoe Thornber struct array_block *bh_le = dm_block_data(b); 576513c29fSJoe Thornber __le32 csum_disk; 586513c29fSJoe Thornber 596513c29fSJoe Thornber if (dm_block_location(b) != le64_to_cpu(bh_le->blocknr)) { 606513c29fSJoe Thornber DMERR_LIMIT("array_block_check failed: blocknr %llu != wanted %llu", 616513c29fSJoe Thornber (unsigned long long) le64_to_cpu(bh_le->blocknr), 626513c29fSJoe Thornber (unsigned long long) dm_block_location(b)); 636513c29fSJoe Thornber return -ENOTBLK; 646513c29fSJoe Thornber } 656513c29fSJoe Thornber 666513c29fSJoe Thornber csum_disk = cpu_to_le32(dm_bm_checksum(&bh_le->max_entries, 676513c29fSJoe Thornber size_of_block - sizeof(__le32), 686513c29fSJoe Thornber CSUM_XOR)); 696513c29fSJoe Thornber if (csum_disk != bh_le->csum) { 706513c29fSJoe Thornber DMERR_LIMIT("array_block_check failed: csum %u != wanted %u", 716513c29fSJoe Thornber (unsigned) le32_to_cpu(csum_disk), 726513c29fSJoe Thornber (unsigned) le32_to_cpu(bh_le->csum)); 736513c29fSJoe Thornber return -EILSEQ; 746513c29fSJoe Thornber } 756513c29fSJoe Thornber 766513c29fSJoe Thornber return 0; 776513c29fSJoe Thornber } 786513c29fSJoe Thornber 796513c29fSJoe Thornber static struct dm_block_validator array_validator = { 806513c29fSJoe Thornber .name = "array", 816513c29fSJoe Thornber .prepare_for_write = array_block_prepare_for_write, 826513c29fSJoe Thornber .check = array_block_check 836513c29fSJoe Thornber }; 846513c29fSJoe Thornber 856513c29fSJoe Thornber /*----------------------------------------------------------------*/ 866513c29fSJoe Thornber 876513c29fSJoe Thornber /* 886513c29fSJoe Thornber * Functions for manipulating the array blocks. 896513c29fSJoe Thornber */ 906513c29fSJoe Thornber 916513c29fSJoe Thornber /* 926513c29fSJoe Thornber * Returns a pointer to a value within an array block. 936513c29fSJoe Thornber * 946513c29fSJoe Thornber * index - The index into _this_ specific block. 956513c29fSJoe Thornber */ 966513c29fSJoe Thornber static void *element_at(struct dm_array_info *info, struct array_block *ab, 976513c29fSJoe Thornber unsigned index) 986513c29fSJoe Thornber { 996513c29fSJoe Thornber unsigned char *entry = (unsigned char *) (ab + 1); 1006513c29fSJoe Thornber 1016513c29fSJoe Thornber entry += index * info->value_type.size; 1026513c29fSJoe Thornber 1036513c29fSJoe Thornber return entry; 1046513c29fSJoe Thornber } 1056513c29fSJoe Thornber 1066513c29fSJoe Thornber /* 1076513c29fSJoe Thornber * Utility function that calls one of the value_type methods on every value 1086513c29fSJoe Thornber * in an array block. 1096513c29fSJoe Thornber */ 1106513c29fSJoe Thornber static void on_entries(struct dm_array_info *info, struct array_block *ab, 1116513c29fSJoe Thornber void (*fn)(void *, const void *)) 1126513c29fSJoe Thornber { 1136513c29fSJoe Thornber unsigned i, nr_entries = le32_to_cpu(ab->nr_entries); 1146513c29fSJoe Thornber 1156513c29fSJoe Thornber for (i = 0; i < nr_entries; i++) 1166513c29fSJoe Thornber fn(info->value_type.context, element_at(info, ab, i)); 1176513c29fSJoe Thornber } 1186513c29fSJoe Thornber 1196513c29fSJoe Thornber /* 1206513c29fSJoe Thornber * Increment every value in an array block. 1216513c29fSJoe Thornber */ 1226513c29fSJoe Thornber static void inc_ablock_entries(struct dm_array_info *info, struct array_block *ab) 1236513c29fSJoe Thornber { 1246513c29fSJoe Thornber struct dm_btree_value_type *vt = &info->value_type; 1256513c29fSJoe Thornber 1266513c29fSJoe Thornber if (vt->inc) 1276513c29fSJoe Thornber on_entries(info, ab, vt->inc); 1286513c29fSJoe Thornber } 1296513c29fSJoe Thornber 1306513c29fSJoe Thornber /* 1316513c29fSJoe Thornber * Decrement every value in an array block. 1326513c29fSJoe Thornber */ 1336513c29fSJoe Thornber static void dec_ablock_entries(struct dm_array_info *info, struct array_block *ab) 1346513c29fSJoe Thornber { 1356513c29fSJoe Thornber struct dm_btree_value_type *vt = &info->value_type; 1366513c29fSJoe Thornber 1376513c29fSJoe Thornber if (vt->dec) 1386513c29fSJoe Thornber on_entries(info, ab, vt->dec); 1396513c29fSJoe Thornber } 1406513c29fSJoe Thornber 1416513c29fSJoe Thornber /* 1426513c29fSJoe Thornber * Each array block can hold this many values. 1436513c29fSJoe Thornber */ 1446513c29fSJoe Thornber static uint32_t calc_max_entries(size_t value_size, size_t size_of_block) 1456513c29fSJoe Thornber { 1466513c29fSJoe Thornber return (size_of_block - sizeof(struct array_block)) / value_size; 1476513c29fSJoe Thornber } 1486513c29fSJoe Thornber 1496513c29fSJoe Thornber /* 1506513c29fSJoe Thornber * Allocate a new array block. The caller will need to unlock block. 1516513c29fSJoe Thornber */ 1526513c29fSJoe Thornber static int alloc_ablock(struct dm_array_info *info, size_t size_of_block, 1536513c29fSJoe Thornber uint32_t max_entries, 1546513c29fSJoe Thornber struct dm_block **block, struct array_block **ab) 1556513c29fSJoe Thornber { 1566513c29fSJoe Thornber int r; 1576513c29fSJoe Thornber 1586513c29fSJoe Thornber r = dm_tm_new_block(info->btree_info.tm, &array_validator, block); 1596513c29fSJoe Thornber if (r) 1606513c29fSJoe Thornber return r; 1616513c29fSJoe Thornber 1626513c29fSJoe Thornber (*ab) = dm_block_data(*block); 1636513c29fSJoe Thornber (*ab)->max_entries = cpu_to_le32(max_entries); 1646513c29fSJoe Thornber (*ab)->nr_entries = cpu_to_le32(0); 1656513c29fSJoe Thornber (*ab)->value_size = cpu_to_le32(info->value_type.size); 1666513c29fSJoe Thornber 1676513c29fSJoe Thornber return 0; 1686513c29fSJoe Thornber } 1696513c29fSJoe Thornber 1706513c29fSJoe Thornber /* 1716513c29fSJoe Thornber * Pad an array block out with a particular value. Every instance will 1726513c29fSJoe Thornber * cause an increment of the value_type. new_nr must always be more than 1736513c29fSJoe Thornber * the current number of entries. 1746513c29fSJoe Thornber */ 1756513c29fSJoe Thornber static void fill_ablock(struct dm_array_info *info, struct array_block *ab, 1766513c29fSJoe Thornber const void *value, unsigned new_nr) 1776513c29fSJoe Thornber { 1786513c29fSJoe Thornber unsigned i; 1796513c29fSJoe Thornber uint32_t nr_entries; 1806513c29fSJoe Thornber struct dm_btree_value_type *vt = &info->value_type; 1816513c29fSJoe Thornber 1826513c29fSJoe Thornber BUG_ON(new_nr > le32_to_cpu(ab->max_entries)); 1836513c29fSJoe Thornber BUG_ON(new_nr < le32_to_cpu(ab->nr_entries)); 1846513c29fSJoe Thornber 1856513c29fSJoe Thornber nr_entries = le32_to_cpu(ab->nr_entries); 1866513c29fSJoe Thornber for (i = nr_entries; i < new_nr; i++) { 1876513c29fSJoe Thornber if (vt->inc) 1886513c29fSJoe Thornber vt->inc(vt->context, value); 1896513c29fSJoe Thornber memcpy(element_at(info, ab, i), value, vt->size); 1906513c29fSJoe Thornber } 1916513c29fSJoe Thornber ab->nr_entries = cpu_to_le32(new_nr); 1926513c29fSJoe Thornber } 1936513c29fSJoe Thornber 1946513c29fSJoe Thornber /* 1956513c29fSJoe Thornber * Remove some entries from the back of an array block. Every value 1966513c29fSJoe Thornber * removed will be decremented. new_nr must be <= the current number of 1976513c29fSJoe Thornber * entries. 1986513c29fSJoe Thornber */ 1996513c29fSJoe Thornber static void trim_ablock(struct dm_array_info *info, struct array_block *ab, 2006513c29fSJoe Thornber unsigned new_nr) 2016513c29fSJoe Thornber { 2026513c29fSJoe Thornber unsigned i; 2036513c29fSJoe Thornber uint32_t nr_entries; 2046513c29fSJoe Thornber struct dm_btree_value_type *vt = &info->value_type; 2056513c29fSJoe Thornber 2066513c29fSJoe Thornber BUG_ON(new_nr > le32_to_cpu(ab->max_entries)); 2076513c29fSJoe Thornber BUG_ON(new_nr > le32_to_cpu(ab->nr_entries)); 2086513c29fSJoe Thornber 2096513c29fSJoe Thornber nr_entries = le32_to_cpu(ab->nr_entries); 2106513c29fSJoe Thornber for (i = nr_entries; i > new_nr; i--) 2116513c29fSJoe Thornber if (vt->dec) 2126513c29fSJoe Thornber vt->dec(vt->context, element_at(info, ab, i - 1)); 2136513c29fSJoe Thornber ab->nr_entries = cpu_to_le32(new_nr); 2146513c29fSJoe Thornber } 2156513c29fSJoe Thornber 2166513c29fSJoe Thornber /* 2176513c29fSJoe Thornber * Read locks a block, and coerces it to an array block. The caller must 2186513c29fSJoe Thornber * unlock 'block' when finished. 2196513c29fSJoe Thornber */ 2206513c29fSJoe Thornber static int get_ablock(struct dm_array_info *info, dm_block_t b, 2216513c29fSJoe Thornber struct dm_block **block, struct array_block **ab) 2226513c29fSJoe Thornber { 2236513c29fSJoe Thornber int r; 2246513c29fSJoe Thornber 2256513c29fSJoe Thornber r = dm_tm_read_lock(info->btree_info.tm, b, &array_validator, block); 2266513c29fSJoe Thornber if (r) 2276513c29fSJoe Thornber return r; 2286513c29fSJoe Thornber 2296513c29fSJoe Thornber *ab = dm_block_data(*block); 2306513c29fSJoe Thornber return 0; 2316513c29fSJoe Thornber } 2326513c29fSJoe Thornber 2336513c29fSJoe Thornber /* 2346513c29fSJoe Thornber * Unlocks an array block. 2356513c29fSJoe Thornber */ 2364c7da06fSMikulas Patocka static void unlock_ablock(struct dm_array_info *info, struct dm_block *block) 2376513c29fSJoe Thornber { 2384c7da06fSMikulas Patocka dm_tm_unlock(info->btree_info.tm, block); 2396513c29fSJoe Thornber } 2406513c29fSJoe Thornber 2416513c29fSJoe Thornber /*----------------------------------------------------------------*/ 2426513c29fSJoe Thornber 2436513c29fSJoe Thornber /* 2446513c29fSJoe Thornber * Btree manipulation. 2456513c29fSJoe Thornber */ 2466513c29fSJoe Thornber 2476513c29fSJoe Thornber /* 2486513c29fSJoe Thornber * Looks up an array block in the btree, and then read locks it. 2496513c29fSJoe Thornber * 2506513c29fSJoe Thornber * index is the index of the index of the array_block, (ie. the array index 2516513c29fSJoe Thornber * / max_entries). 2526513c29fSJoe Thornber */ 2536513c29fSJoe Thornber static int lookup_ablock(struct dm_array_info *info, dm_block_t root, 2546513c29fSJoe Thornber unsigned index, struct dm_block **block, 2556513c29fSJoe Thornber struct array_block **ab) 2566513c29fSJoe Thornber { 2576513c29fSJoe Thornber int r; 2586513c29fSJoe Thornber uint64_t key = index; 2596513c29fSJoe Thornber __le64 block_le; 2606513c29fSJoe Thornber 2616513c29fSJoe Thornber r = dm_btree_lookup(&info->btree_info, root, &key, &block_le); 2626513c29fSJoe Thornber if (r) 2636513c29fSJoe Thornber return r; 2646513c29fSJoe Thornber 2656513c29fSJoe Thornber return get_ablock(info, le64_to_cpu(block_le), block, ab); 2666513c29fSJoe Thornber } 2676513c29fSJoe Thornber 2686513c29fSJoe Thornber /* 2696513c29fSJoe Thornber * Insert an array block into the btree. The block is _not_ unlocked. 2706513c29fSJoe Thornber */ 2716513c29fSJoe Thornber static int insert_ablock(struct dm_array_info *info, uint64_t index, 2726513c29fSJoe Thornber struct dm_block *block, dm_block_t *root) 2736513c29fSJoe Thornber { 2746513c29fSJoe Thornber __le64 block_le = cpu_to_le64(dm_block_location(block)); 2756513c29fSJoe Thornber 2766513c29fSJoe Thornber __dm_bless_for_disk(block_le); 2776513c29fSJoe Thornber return dm_btree_insert(&info->btree_info, *root, &index, &block_le, root); 2786513c29fSJoe Thornber } 2796513c29fSJoe Thornber 280dd6a77d9SJoe Thornber /*----------------------------------------------------------------*/ 281dd6a77d9SJoe Thornber 282dd6a77d9SJoe Thornber static int __shadow_ablock(struct dm_array_info *info, dm_block_t b, 283dd6a77d9SJoe Thornber struct dm_block **block, struct array_block **ab) 284dd6a77d9SJoe Thornber { 285dd6a77d9SJoe Thornber int inc; 286dd6a77d9SJoe Thornber int r = dm_tm_shadow_block(info->btree_info.tm, b, 287dd6a77d9SJoe Thornber &array_validator, block, &inc); 288dd6a77d9SJoe Thornber if (r) 289dd6a77d9SJoe Thornber return r; 290dd6a77d9SJoe Thornber 291dd6a77d9SJoe Thornber *ab = dm_block_data(*block); 292dd6a77d9SJoe Thornber if (inc) 293dd6a77d9SJoe Thornber inc_ablock_entries(info, *ab); 294dd6a77d9SJoe Thornber 295dd6a77d9SJoe Thornber return 0; 296dd6a77d9SJoe Thornber } 297dd6a77d9SJoe Thornber 298dd6a77d9SJoe Thornber /* 299dd6a77d9SJoe Thornber * The shadow op will often be a noop. Only insert if it really 300dd6a77d9SJoe Thornber * copied data. 301dd6a77d9SJoe Thornber */ 302dd6a77d9SJoe Thornber static int __reinsert_ablock(struct dm_array_info *info, unsigned index, 303dd6a77d9SJoe Thornber struct dm_block *block, dm_block_t b, 304dd6a77d9SJoe Thornber dm_block_t *root) 305dd6a77d9SJoe Thornber { 306dd6a77d9SJoe Thornber int r = 0; 307dd6a77d9SJoe Thornber 308dd6a77d9SJoe Thornber if (dm_block_location(block) != b) { 309dd6a77d9SJoe Thornber /* 310dd6a77d9SJoe Thornber * dm_tm_shadow_block will have already decremented the old 311dd6a77d9SJoe Thornber * block, but it is still referenced by the btree. We 312dd6a77d9SJoe Thornber * increment to stop the insert decrementing it below zero 313dd6a77d9SJoe Thornber * when overwriting the old value. 314dd6a77d9SJoe Thornber */ 315dd6a77d9SJoe Thornber dm_tm_inc(info->btree_info.tm, b); 316dd6a77d9SJoe Thornber r = insert_ablock(info, index, block, root); 317dd6a77d9SJoe Thornber } 318dd6a77d9SJoe Thornber 319dd6a77d9SJoe Thornber return r; 320dd6a77d9SJoe Thornber } 321dd6a77d9SJoe Thornber 3226513c29fSJoe Thornber /* 3236513c29fSJoe Thornber * Looks up an array block in the btree. Then shadows it, and updates the 3246513c29fSJoe Thornber * btree to point to this new shadow. 'root' is an input/output parameter 3256513c29fSJoe Thornber * for both the current root block, and the new one. 3266513c29fSJoe Thornber */ 3276513c29fSJoe Thornber static int shadow_ablock(struct dm_array_info *info, dm_block_t *root, 3286513c29fSJoe Thornber unsigned index, struct dm_block **block, 3296513c29fSJoe Thornber struct array_block **ab) 3306513c29fSJoe Thornber { 331dd6a77d9SJoe Thornber int r; 3326513c29fSJoe Thornber uint64_t key = index; 3336513c29fSJoe Thornber dm_block_t b; 3346513c29fSJoe Thornber __le64 block_le; 3356513c29fSJoe Thornber 3366513c29fSJoe Thornber r = dm_btree_lookup(&info->btree_info, *root, &key, &block_le); 3376513c29fSJoe Thornber if (r) 3386513c29fSJoe Thornber return r; 3396513c29fSJoe Thornber b = le64_to_cpu(block_le); 3406513c29fSJoe Thornber 341dd6a77d9SJoe Thornber r = __shadow_ablock(info, b, block, ab); 3426513c29fSJoe Thornber if (r) 3436513c29fSJoe Thornber return r; 3446513c29fSJoe Thornber 345dd6a77d9SJoe Thornber return __reinsert_ablock(info, index, *block, b, root); 3466513c29fSJoe Thornber } 3476513c29fSJoe Thornber 3486513c29fSJoe Thornber /* 3496513c29fSJoe Thornber * Allocate an new array block, and fill it with some values. 3506513c29fSJoe Thornber */ 3516513c29fSJoe Thornber static int insert_new_ablock(struct dm_array_info *info, size_t size_of_block, 3526513c29fSJoe Thornber uint32_t max_entries, 3536513c29fSJoe Thornber unsigned block_index, uint32_t nr, 3546513c29fSJoe Thornber const void *value, dm_block_t *root) 3556513c29fSJoe Thornber { 3566513c29fSJoe Thornber int r; 3576513c29fSJoe Thornber struct dm_block *block; 3586513c29fSJoe Thornber struct array_block *ab; 3596513c29fSJoe Thornber 3606513c29fSJoe Thornber r = alloc_ablock(info, size_of_block, max_entries, &block, &ab); 3616513c29fSJoe Thornber if (r) 3626513c29fSJoe Thornber return r; 3636513c29fSJoe Thornber 3646513c29fSJoe Thornber fill_ablock(info, ab, value, nr); 3656513c29fSJoe Thornber r = insert_ablock(info, block_index, block, root); 3666513c29fSJoe Thornber unlock_ablock(info, block); 3676513c29fSJoe Thornber 3686513c29fSJoe Thornber return r; 3696513c29fSJoe Thornber } 3706513c29fSJoe Thornber 3716513c29fSJoe Thornber static int insert_full_ablocks(struct dm_array_info *info, size_t size_of_block, 3726513c29fSJoe Thornber unsigned begin_block, unsigned end_block, 3736513c29fSJoe Thornber unsigned max_entries, const void *value, 3746513c29fSJoe Thornber dm_block_t *root) 3756513c29fSJoe Thornber { 3766513c29fSJoe Thornber int r = 0; 3776513c29fSJoe Thornber 3786513c29fSJoe Thornber for (; !r && begin_block != end_block; begin_block++) 3796513c29fSJoe Thornber r = insert_new_ablock(info, size_of_block, max_entries, begin_block, max_entries, value, root); 3806513c29fSJoe Thornber 3816513c29fSJoe Thornber return r; 3826513c29fSJoe Thornber } 3836513c29fSJoe Thornber 3846513c29fSJoe Thornber /* 3856513c29fSJoe Thornber * There are a bunch of functions involved with resizing an array. This 3866513c29fSJoe Thornber * structure holds information that commonly needed by them. Purely here 3876513c29fSJoe Thornber * to reduce parameter count. 3886513c29fSJoe Thornber */ 3896513c29fSJoe Thornber struct resize { 3906513c29fSJoe Thornber /* 3916513c29fSJoe Thornber * Describes the array. 3926513c29fSJoe Thornber */ 3936513c29fSJoe Thornber struct dm_array_info *info; 3946513c29fSJoe Thornber 3956513c29fSJoe Thornber /* 3966513c29fSJoe Thornber * The current root of the array. This gets updated. 3976513c29fSJoe Thornber */ 3986513c29fSJoe Thornber dm_block_t root; 3996513c29fSJoe Thornber 4006513c29fSJoe Thornber /* 4016513c29fSJoe Thornber * Metadata block size. Used to calculate the nr entries in an 4026513c29fSJoe Thornber * array block. 4036513c29fSJoe Thornber */ 4046513c29fSJoe Thornber size_t size_of_block; 4056513c29fSJoe Thornber 4066513c29fSJoe Thornber /* 4076513c29fSJoe Thornber * Maximum nr entries in an array block. 4086513c29fSJoe Thornber */ 4096513c29fSJoe Thornber unsigned max_entries; 4106513c29fSJoe Thornber 4116513c29fSJoe Thornber /* 4126513c29fSJoe Thornber * nr of completely full blocks in the array. 4136513c29fSJoe Thornber * 4146513c29fSJoe Thornber * 'old' refers to before the resize, 'new' after. 4156513c29fSJoe Thornber */ 4166513c29fSJoe Thornber unsigned old_nr_full_blocks, new_nr_full_blocks; 4176513c29fSJoe Thornber 4186513c29fSJoe Thornber /* 4196513c29fSJoe Thornber * Number of entries in the final block. 0 iff only full blocks in 4206513c29fSJoe Thornber * the array. 4216513c29fSJoe Thornber */ 4226513c29fSJoe Thornber unsigned old_nr_entries_in_last_block, new_nr_entries_in_last_block; 4236513c29fSJoe Thornber 4246513c29fSJoe Thornber /* 4256513c29fSJoe Thornber * The default value used when growing the array. 4266513c29fSJoe Thornber */ 4276513c29fSJoe Thornber const void *value; 4286513c29fSJoe Thornber }; 4296513c29fSJoe Thornber 4306513c29fSJoe Thornber /* 4316513c29fSJoe Thornber * Removes a consecutive set of array blocks from the btree. The values 4326513c29fSJoe Thornber * in block are decremented as a side effect of the btree remove. 4336513c29fSJoe Thornber * 4346513c29fSJoe Thornber * begin_index - the index of the first array block to remove. 4356513c29fSJoe Thornber * end_index - the one-past-the-end value. ie. this block is not removed. 4366513c29fSJoe Thornber */ 4376513c29fSJoe Thornber static int drop_blocks(struct resize *resize, unsigned begin_index, 4386513c29fSJoe Thornber unsigned end_index) 4396513c29fSJoe Thornber { 4406513c29fSJoe Thornber int r; 4416513c29fSJoe Thornber 4426513c29fSJoe Thornber while (begin_index != end_index) { 4436513c29fSJoe Thornber uint64_t key = begin_index++; 4446513c29fSJoe Thornber r = dm_btree_remove(&resize->info->btree_info, resize->root, 4456513c29fSJoe Thornber &key, &resize->root); 4466513c29fSJoe Thornber if (r) 4476513c29fSJoe Thornber return r; 4486513c29fSJoe Thornber } 4496513c29fSJoe Thornber 4506513c29fSJoe Thornber return 0; 4516513c29fSJoe Thornber } 4526513c29fSJoe Thornber 4536513c29fSJoe Thornber /* 4546513c29fSJoe Thornber * Calculates how many blocks are needed for the array. 4556513c29fSJoe Thornber */ 4566513c29fSJoe Thornber static unsigned total_nr_blocks_needed(unsigned nr_full_blocks, 4576513c29fSJoe Thornber unsigned nr_entries_in_last_block) 4586513c29fSJoe Thornber { 4596513c29fSJoe Thornber return nr_full_blocks + (nr_entries_in_last_block ? 1 : 0); 4606513c29fSJoe Thornber } 4616513c29fSJoe Thornber 4626513c29fSJoe Thornber /* 4636513c29fSJoe Thornber * Shrink an array. 4646513c29fSJoe Thornber */ 4656513c29fSJoe Thornber static int shrink(struct resize *resize) 4666513c29fSJoe Thornber { 4676513c29fSJoe Thornber int r; 4686513c29fSJoe Thornber unsigned begin, end; 4696513c29fSJoe Thornber struct dm_block *block; 4706513c29fSJoe Thornber struct array_block *ab; 4716513c29fSJoe Thornber 4726513c29fSJoe Thornber /* 4736513c29fSJoe Thornber * Lose some blocks from the back? 4746513c29fSJoe Thornber */ 4756513c29fSJoe Thornber if (resize->new_nr_full_blocks < resize->old_nr_full_blocks) { 4766513c29fSJoe Thornber begin = total_nr_blocks_needed(resize->new_nr_full_blocks, 4776513c29fSJoe Thornber resize->new_nr_entries_in_last_block); 4786513c29fSJoe Thornber end = total_nr_blocks_needed(resize->old_nr_full_blocks, 4796513c29fSJoe Thornber resize->old_nr_entries_in_last_block); 4806513c29fSJoe Thornber 4816513c29fSJoe Thornber r = drop_blocks(resize, begin, end); 4826513c29fSJoe Thornber if (r) 4836513c29fSJoe Thornber return r; 4846513c29fSJoe Thornber } 4856513c29fSJoe Thornber 4866513c29fSJoe Thornber /* 4876513c29fSJoe Thornber * Trim the new tail block 4886513c29fSJoe Thornber */ 4896513c29fSJoe Thornber if (resize->new_nr_entries_in_last_block) { 4906513c29fSJoe Thornber r = shadow_ablock(resize->info, &resize->root, 4916513c29fSJoe Thornber resize->new_nr_full_blocks, &block, &ab); 4926513c29fSJoe Thornber if (r) 4936513c29fSJoe Thornber return r; 4946513c29fSJoe Thornber 4956513c29fSJoe Thornber trim_ablock(resize->info, ab, resize->new_nr_entries_in_last_block); 4966513c29fSJoe Thornber unlock_ablock(resize->info, block); 4976513c29fSJoe Thornber } 4986513c29fSJoe Thornber 4996513c29fSJoe Thornber return 0; 5006513c29fSJoe Thornber } 5016513c29fSJoe Thornber 5026513c29fSJoe Thornber /* 5036513c29fSJoe Thornber * Grow an array. 5046513c29fSJoe Thornber */ 5056513c29fSJoe Thornber static int grow_extend_tail_block(struct resize *resize, uint32_t new_nr_entries) 5066513c29fSJoe Thornber { 5076513c29fSJoe Thornber int r; 5086513c29fSJoe Thornber struct dm_block *block; 5096513c29fSJoe Thornber struct array_block *ab; 5106513c29fSJoe Thornber 5116513c29fSJoe Thornber r = shadow_ablock(resize->info, &resize->root, 5126513c29fSJoe Thornber resize->old_nr_full_blocks, &block, &ab); 5136513c29fSJoe Thornber if (r) 5146513c29fSJoe Thornber return r; 5156513c29fSJoe Thornber 5166513c29fSJoe Thornber fill_ablock(resize->info, ab, resize->value, new_nr_entries); 5176513c29fSJoe Thornber unlock_ablock(resize->info, block); 5186513c29fSJoe Thornber 5196513c29fSJoe Thornber return r; 5206513c29fSJoe Thornber } 5216513c29fSJoe Thornber 5226513c29fSJoe Thornber static int grow_add_tail_block(struct resize *resize) 5236513c29fSJoe Thornber { 5246513c29fSJoe Thornber return insert_new_ablock(resize->info, resize->size_of_block, 5256513c29fSJoe Thornber resize->max_entries, 5266513c29fSJoe Thornber resize->new_nr_full_blocks, 5276513c29fSJoe Thornber resize->new_nr_entries_in_last_block, 5286513c29fSJoe Thornber resize->value, &resize->root); 5296513c29fSJoe Thornber } 5306513c29fSJoe Thornber 5316513c29fSJoe Thornber static int grow_needs_more_blocks(struct resize *resize) 5326513c29fSJoe Thornber { 5336513c29fSJoe Thornber int r; 5349c1d4de5SJoe Thornber unsigned old_nr_blocks = resize->old_nr_full_blocks; 5356513c29fSJoe Thornber 5366513c29fSJoe Thornber if (resize->old_nr_entries_in_last_block > 0) { 5379c1d4de5SJoe Thornber old_nr_blocks++; 5389c1d4de5SJoe Thornber 5396513c29fSJoe Thornber r = grow_extend_tail_block(resize, resize->max_entries); 5406513c29fSJoe Thornber if (r) 5416513c29fSJoe Thornber return r; 5426513c29fSJoe Thornber } 5436513c29fSJoe Thornber 5446513c29fSJoe Thornber r = insert_full_ablocks(resize->info, resize->size_of_block, 5459c1d4de5SJoe Thornber old_nr_blocks, 5466513c29fSJoe Thornber resize->new_nr_full_blocks, 5476513c29fSJoe Thornber resize->max_entries, resize->value, 5486513c29fSJoe Thornber &resize->root); 5496513c29fSJoe Thornber if (r) 5506513c29fSJoe Thornber return r; 5516513c29fSJoe Thornber 5526513c29fSJoe Thornber if (resize->new_nr_entries_in_last_block) 5536513c29fSJoe Thornber r = grow_add_tail_block(resize); 5546513c29fSJoe Thornber 5556513c29fSJoe Thornber return r; 5566513c29fSJoe Thornber } 5576513c29fSJoe Thornber 5586513c29fSJoe Thornber static int grow(struct resize *resize) 5596513c29fSJoe Thornber { 5606513c29fSJoe Thornber if (resize->new_nr_full_blocks > resize->old_nr_full_blocks) 5616513c29fSJoe Thornber return grow_needs_more_blocks(resize); 5626513c29fSJoe Thornber 5636513c29fSJoe Thornber else if (resize->old_nr_entries_in_last_block) 5646513c29fSJoe Thornber return grow_extend_tail_block(resize, resize->new_nr_entries_in_last_block); 5656513c29fSJoe Thornber 5666513c29fSJoe Thornber else 5676513c29fSJoe Thornber return grow_add_tail_block(resize); 5686513c29fSJoe Thornber } 5696513c29fSJoe Thornber 5706513c29fSJoe Thornber /*----------------------------------------------------------------*/ 5716513c29fSJoe Thornber 5726513c29fSJoe Thornber /* 5736513c29fSJoe Thornber * These are the value_type functions for the btree elements, which point 5746513c29fSJoe Thornber * to array blocks. 5756513c29fSJoe Thornber */ 5766513c29fSJoe Thornber static void block_inc(void *context, const void *value) 5776513c29fSJoe Thornber { 5786513c29fSJoe Thornber __le64 block_le; 5796513c29fSJoe Thornber struct dm_array_info *info = context; 5806513c29fSJoe Thornber 5816513c29fSJoe Thornber memcpy(&block_le, value, sizeof(block_le)); 5826513c29fSJoe Thornber dm_tm_inc(info->btree_info.tm, le64_to_cpu(block_le)); 5836513c29fSJoe Thornber } 5846513c29fSJoe Thornber 5856513c29fSJoe Thornber static void block_dec(void *context, const void *value) 5866513c29fSJoe Thornber { 5876513c29fSJoe Thornber int r; 5886513c29fSJoe Thornber uint64_t b; 5896513c29fSJoe Thornber __le64 block_le; 5906513c29fSJoe Thornber uint32_t ref_count; 5916513c29fSJoe Thornber struct dm_block *block; 5926513c29fSJoe Thornber struct array_block *ab; 5936513c29fSJoe Thornber struct dm_array_info *info = context; 5946513c29fSJoe Thornber 5956513c29fSJoe Thornber memcpy(&block_le, value, sizeof(block_le)); 5966513c29fSJoe Thornber b = le64_to_cpu(block_le); 5976513c29fSJoe Thornber 5986513c29fSJoe Thornber r = dm_tm_ref(info->btree_info.tm, b, &ref_count); 5996513c29fSJoe Thornber if (r) { 6006513c29fSJoe Thornber DMERR_LIMIT("couldn't get reference count for block %llu", 6016513c29fSJoe Thornber (unsigned long long) b); 6026513c29fSJoe Thornber return; 6036513c29fSJoe Thornber } 6046513c29fSJoe Thornber 6056513c29fSJoe Thornber if (ref_count == 1) { 6066513c29fSJoe Thornber /* 6076513c29fSJoe Thornber * We're about to drop the last reference to this ablock. 6086513c29fSJoe Thornber * So we need to decrement the ref count of the contents. 6096513c29fSJoe Thornber */ 6106513c29fSJoe Thornber r = get_ablock(info, b, &block, &ab); 6116513c29fSJoe Thornber if (r) { 6126513c29fSJoe Thornber DMERR_LIMIT("couldn't get array block %llu", 6136513c29fSJoe Thornber (unsigned long long) b); 6146513c29fSJoe Thornber return; 6156513c29fSJoe Thornber } 6166513c29fSJoe Thornber 6176513c29fSJoe Thornber dec_ablock_entries(info, ab); 6186513c29fSJoe Thornber unlock_ablock(info, block); 6196513c29fSJoe Thornber } 6206513c29fSJoe Thornber 6216513c29fSJoe Thornber dm_tm_dec(info->btree_info.tm, b); 6226513c29fSJoe Thornber } 6236513c29fSJoe Thornber 6246513c29fSJoe Thornber static int block_equal(void *context, const void *value1, const void *value2) 6256513c29fSJoe Thornber { 6266513c29fSJoe Thornber return !memcmp(value1, value2, sizeof(__le64)); 6276513c29fSJoe Thornber } 6286513c29fSJoe Thornber 6296513c29fSJoe Thornber /*----------------------------------------------------------------*/ 6306513c29fSJoe Thornber 6316513c29fSJoe Thornber void dm_array_info_init(struct dm_array_info *info, 6326513c29fSJoe Thornber struct dm_transaction_manager *tm, 6336513c29fSJoe Thornber struct dm_btree_value_type *vt) 6346513c29fSJoe Thornber { 6356513c29fSJoe Thornber struct dm_btree_value_type *bvt = &info->btree_info.value_type; 6366513c29fSJoe Thornber 6376513c29fSJoe Thornber memcpy(&info->value_type, vt, sizeof(info->value_type)); 6386513c29fSJoe Thornber info->btree_info.tm = tm; 6396513c29fSJoe Thornber info->btree_info.levels = 1; 6406513c29fSJoe Thornber 6416513c29fSJoe Thornber bvt->context = info; 6426513c29fSJoe Thornber bvt->size = sizeof(__le64); 6436513c29fSJoe Thornber bvt->inc = block_inc; 6446513c29fSJoe Thornber bvt->dec = block_dec; 6456513c29fSJoe Thornber bvt->equal = block_equal; 6466513c29fSJoe Thornber } 6476513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_info_init); 6486513c29fSJoe Thornber 6496513c29fSJoe Thornber int dm_array_empty(struct dm_array_info *info, dm_block_t *root) 6506513c29fSJoe Thornber { 6516513c29fSJoe Thornber return dm_btree_empty(&info->btree_info, root); 6526513c29fSJoe Thornber } 6536513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_empty); 6546513c29fSJoe Thornber 6556513c29fSJoe Thornber static int array_resize(struct dm_array_info *info, dm_block_t root, 6566513c29fSJoe Thornber uint32_t old_size, uint32_t new_size, 6576513c29fSJoe Thornber const void *value, dm_block_t *new_root) 6586513c29fSJoe Thornber { 6596513c29fSJoe Thornber int r; 6606513c29fSJoe Thornber struct resize resize; 6616513c29fSJoe Thornber 6628001e87dSJoe Thornber if (old_size == new_size) { 6638001e87dSJoe Thornber *new_root = root; 6646513c29fSJoe Thornber return 0; 6658001e87dSJoe Thornber } 6666513c29fSJoe Thornber 6676513c29fSJoe Thornber resize.info = info; 6686513c29fSJoe Thornber resize.root = root; 6696513c29fSJoe Thornber resize.size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm)); 6706513c29fSJoe Thornber resize.max_entries = calc_max_entries(info->value_type.size, 6716513c29fSJoe Thornber resize.size_of_block); 6726513c29fSJoe Thornber 6736513c29fSJoe Thornber resize.old_nr_full_blocks = old_size / resize.max_entries; 6746513c29fSJoe Thornber resize.old_nr_entries_in_last_block = old_size % resize.max_entries; 6756513c29fSJoe Thornber resize.new_nr_full_blocks = new_size / resize.max_entries; 6766513c29fSJoe Thornber resize.new_nr_entries_in_last_block = new_size % resize.max_entries; 6776513c29fSJoe Thornber resize.value = value; 6786513c29fSJoe Thornber 6796513c29fSJoe Thornber r = ((new_size > old_size) ? grow : shrink)(&resize); 6806513c29fSJoe Thornber if (r) 6816513c29fSJoe Thornber return r; 6826513c29fSJoe Thornber 6836513c29fSJoe Thornber *new_root = resize.root; 6846513c29fSJoe Thornber return 0; 6856513c29fSJoe Thornber } 6866513c29fSJoe Thornber 6876513c29fSJoe Thornber int dm_array_resize(struct dm_array_info *info, dm_block_t root, 6886513c29fSJoe Thornber uint32_t old_size, uint32_t new_size, 6896513c29fSJoe Thornber const void *value, dm_block_t *new_root) 6906513c29fSJoe Thornber __dm_written_to_disk(value) 6916513c29fSJoe Thornber { 6926513c29fSJoe Thornber int r = array_resize(info, root, old_size, new_size, value, new_root); 6936513c29fSJoe Thornber __dm_unbless_for_disk(value); 6946513c29fSJoe Thornber return r; 6956513c29fSJoe Thornber } 6966513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_resize); 6976513c29fSJoe Thornber 698dd6a77d9SJoe Thornber static int populate_ablock_with_values(struct dm_array_info *info, struct array_block *ab, 699dd6a77d9SJoe Thornber value_fn fn, void *context, unsigned base, unsigned new_nr) 700dd6a77d9SJoe Thornber { 701dd6a77d9SJoe Thornber int r; 702dd6a77d9SJoe Thornber unsigned i; 703dd6a77d9SJoe Thornber struct dm_btree_value_type *vt = &info->value_type; 704dd6a77d9SJoe Thornber 705dd6a77d9SJoe Thornber BUG_ON(le32_to_cpu(ab->nr_entries)); 706dd6a77d9SJoe Thornber BUG_ON(new_nr > le32_to_cpu(ab->max_entries)); 707dd6a77d9SJoe Thornber 708dd6a77d9SJoe Thornber for (i = 0; i < new_nr; i++) { 709dd6a77d9SJoe Thornber r = fn(base + i, element_at(info, ab, i), context); 710dd6a77d9SJoe Thornber if (r) 711dd6a77d9SJoe Thornber return r; 712dd6a77d9SJoe Thornber 713dd6a77d9SJoe Thornber if (vt->inc) 714dd6a77d9SJoe Thornber vt->inc(vt->context, element_at(info, ab, i)); 715dd6a77d9SJoe Thornber } 716dd6a77d9SJoe Thornber 717dd6a77d9SJoe Thornber ab->nr_entries = cpu_to_le32(new_nr); 718dd6a77d9SJoe Thornber return 0; 719dd6a77d9SJoe Thornber } 720dd6a77d9SJoe Thornber 721dd6a77d9SJoe Thornber int dm_array_new(struct dm_array_info *info, dm_block_t *root, 722dd6a77d9SJoe Thornber uint32_t size, value_fn fn, void *context) 723dd6a77d9SJoe Thornber { 724dd6a77d9SJoe Thornber int r; 725dd6a77d9SJoe Thornber struct dm_block *block; 726dd6a77d9SJoe Thornber struct array_block *ab; 727dd6a77d9SJoe Thornber unsigned block_index, end_block, size_of_block, max_entries; 728dd6a77d9SJoe Thornber 729dd6a77d9SJoe Thornber r = dm_array_empty(info, root); 730dd6a77d9SJoe Thornber if (r) 731dd6a77d9SJoe Thornber return r; 732dd6a77d9SJoe Thornber 733dd6a77d9SJoe Thornber size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm)); 734dd6a77d9SJoe Thornber max_entries = calc_max_entries(info->value_type.size, size_of_block); 735dd6a77d9SJoe Thornber end_block = dm_div_up(size, max_entries); 736dd6a77d9SJoe Thornber 737dd6a77d9SJoe Thornber for (block_index = 0; block_index != end_block; block_index++) { 738dd6a77d9SJoe Thornber r = alloc_ablock(info, size_of_block, max_entries, &block, &ab); 739dd6a77d9SJoe Thornber if (r) 740dd6a77d9SJoe Thornber break; 741dd6a77d9SJoe Thornber 742dd6a77d9SJoe Thornber r = populate_ablock_with_values(info, ab, fn, context, 743dd6a77d9SJoe Thornber block_index * max_entries, 744dd6a77d9SJoe Thornber min(max_entries, size)); 745dd6a77d9SJoe Thornber if (r) { 746dd6a77d9SJoe Thornber unlock_ablock(info, block); 747dd6a77d9SJoe Thornber break; 748dd6a77d9SJoe Thornber } 749dd6a77d9SJoe Thornber 750dd6a77d9SJoe Thornber r = insert_ablock(info, block_index, block, root); 751dd6a77d9SJoe Thornber unlock_ablock(info, block); 752dd6a77d9SJoe Thornber if (r) 753dd6a77d9SJoe Thornber break; 754dd6a77d9SJoe Thornber 755dd6a77d9SJoe Thornber size -= max_entries; 756dd6a77d9SJoe Thornber } 757dd6a77d9SJoe Thornber 758dd6a77d9SJoe Thornber return r; 759dd6a77d9SJoe Thornber } 760dd6a77d9SJoe Thornber EXPORT_SYMBOL_GPL(dm_array_new); 761dd6a77d9SJoe Thornber 7626513c29fSJoe Thornber int dm_array_del(struct dm_array_info *info, dm_block_t root) 7636513c29fSJoe Thornber { 7646513c29fSJoe Thornber return dm_btree_del(&info->btree_info, root); 7656513c29fSJoe Thornber } 7666513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_del); 7676513c29fSJoe Thornber 7686513c29fSJoe Thornber int dm_array_get_value(struct dm_array_info *info, dm_block_t root, 7696513c29fSJoe Thornber uint32_t index, void *value_le) 7706513c29fSJoe Thornber { 7716513c29fSJoe Thornber int r; 7726513c29fSJoe Thornber struct dm_block *block; 7736513c29fSJoe Thornber struct array_block *ab; 7746513c29fSJoe Thornber size_t size_of_block; 7756513c29fSJoe Thornber unsigned entry, max_entries; 7766513c29fSJoe Thornber 7776513c29fSJoe Thornber size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm)); 7786513c29fSJoe Thornber max_entries = calc_max_entries(info->value_type.size, size_of_block); 7796513c29fSJoe Thornber 7806513c29fSJoe Thornber r = lookup_ablock(info, root, index / max_entries, &block, &ab); 7816513c29fSJoe Thornber if (r) 7826513c29fSJoe Thornber return r; 7836513c29fSJoe Thornber 7846513c29fSJoe Thornber entry = index % max_entries; 7856513c29fSJoe Thornber if (entry >= le32_to_cpu(ab->nr_entries)) 7866513c29fSJoe Thornber r = -ENODATA; 7876513c29fSJoe Thornber else 7886513c29fSJoe Thornber memcpy(value_le, element_at(info, ab, entry), 7896513c29fSJoe Thornber info->value_type.size); 7906513c29fSJoe Thornber 7916513c29fSJoe Thornber unlock_ablock(info, block); 7926513c29fSJoe Thornber return r; 7936513c29fSJoe Thornber } 7946513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_get_value); 7956513c29fSJoe Thornber 7966513c29fSJoe Thornber static int array_set_value(struct dm_array_info *info, dm_block_t root, 7976513c29fSJoe Thornber uint32_t index, const void *value, dm_block_t *new_root) 7986513c29fSJoe Thornber { 7996513c29fSJoe Thornber int r; 8006513c29fSJoe Thornber struct dm_block *block; 8016513c29fSJoe Thornber struct array_block *ab; 8026513c29fSJoe Thornber size_t size_of_block; 8036513c29fSJoe Thornber unsigned max_entries; 8046513c29fSJoe Thornber unsigned entry; 8056513c29fSJoe Thornber void *old_value; 8066513c29fSJoe Thornber struct dm_btree_value_type *vt = &info->value_type; 8076513c29fSJoe Thornber 8086513c29fSJoe Thornber size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm)); 8096513c29fSJoe Thornber max_entries = calc_max_entries(info->value_type.size, size_of_block); 8106513c29fSJoe Thornber 8116513c29fSJoe Thornber r = shadow_ablock(info, &root, index / max_entries, &block, &ab); 8126513c29fSJoe Thornber if (r) 8136513c29fSJoe Thornber return r; 8146513c29fSJoe Thornber *new_root = root; 8156513c29fSJoe Thornber 8166513c29fSJoe Thornber entry = index % max_entries; 8176513c29fSJoe Thornber if (entry >= le32_to_cpu(ab->nr_entries)) { 8186513c29fSJoe Thornber r = -ENODATA; 8196513c29fSJoe Thornber goto out; 8206513c29fSJoe Thornber } 8216513c29fSJoe Thornber 8226513c29fSJoe Thornber old_value = element_at(info, ab, entry); 8236513c29fSJoe Thornber if (vt->dec && 8246513c29fSJoe Thornber (!vt->equal || !vt->equal(vt->context, old_value, value))) { 8256513c29fSJoe Thornber vt->dec(vt->context, old_value); 8266513c29fSJoe Thornber if (vt->inc) 8276513c29fSJoe Thornber vt->inc(vt->context, value); 8286513c29fSJoe Thornber } 8296513c29fSJoe Thornber 8306513c29fSJoe Thornber memcpy(old_value, value, info->value_type.size); 8316513c29fSJoe Thornber 8326513c29fSJoe Thornber out: 8336513c29fSJoe Thornber unlock_ablock(info, block); 8346513c29fSJoe Thornber return r; 8356513c29fSJoe Thornber } 8366513c29fSJoe Thornber 8376513c29fSJoe Thornber int dm_array_set_value(struct dm_array_info *info, dm_block_t root, 8386513c29fSJoe Thornber uint32_t index, const void *value, dm_block_t *new_root) 8396513c29fSJoe Thornber __dm_written_to_disk(value) 8406513c29fSJoe Thornber { 8416513c29fSJoe Thornber int r; 8426513c29fSJoe Thornber 8436513c29fSJoe Thornber r = array_set_value(info, root, index, value, new_root); 8446513c29fSJoe Thornber __dm_unbless_for_disk(value); 8456513c29fSJoe Thornber return r; 8466513c29fSJoe Thornber } 8476513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_set_value); 8486513c29fSJoe Thornber 8496513c29fSJoe Thornber struct walk_info { 8506513c29fSJoe Thornber struct dm_array_info *info; 8516513c29fSJoe Thornber int (*fn)(void *context, uint64_t key, void *leaf); 8526513c29fSJoe Thornber void *context; 8536513c29fSJoe Thornber }; 8546513c29fSJoe Thornber 8556513c29fSJoe Thornber static int walk_ablock(void *context, uint64_t *keys, void *leaf) 8566513c29fSJoe Thornber { 8576513c29fSJoe Thornber struct walk_info *wi = context; 8586513c29fSJoe Thornber 8596513c29fSJoe Thornber int r; 8606513c29fSJoe Thornber unsigned i; 8616513c29fSJoe Thornber __le64 block_le; 8626513c29fSJoe Thornber unsigned nr_entries, max_entries; 8636513c29fSJoe Thornber struct dm_block *block; 8646513c29fSJoe Thornber struct array_block *ab; 8656513c29fSJoe Thornber 8666513c29fSJoe Thornber memcpy(&block_le, leaf, sizeof(block_le)); 8676513c29fSJoe Thornber r = get_ablock(wi->info, le64_to_cpu(block_le), &block, &ab); 8686513c29fSJoe Thornber if (r) 8696513c29fSJoe Thornber return r; 8706513c29fSJoe Thornber 8716513c29fSJoe Thornber max_entries = le32_to_cpu(ab->max_entries); 8726513c29fSJoe Thornber nr_entries = le32_to_cpu(ab->nr_entries); 8736513c29fSJoe Thornber for (i = 0; i < nr_entries; i++) { 8746513c29fSJoe Thornber r = wi->fn(wi->context, keys[0] * max_entries + i, 8756513c29fSJoe Thornber element_at(wi->info, ab, i)); 8766513c29fSJoe Thornber 8776513c29fSJoe Thornber if (r) 8786513c29fSJoe Thornber break; 8796513c29fSJoe Thornber } 8806513c29fSJoe Thornber 8816513c29fSJoe Thornber unlock_ablock(wi->info, block); 8826513c29fSJoe Thornber return r; 8836513c29fSJoe Thornber } 8846513c29fSJoe Thornber 8856513c29fSJoe Thornber int dm_array_walk(struct dm_array_info *info, dm_block_t root, 8866513c29fSJoe Thornber int (*fn)(void *, uint64_t key, void *leaf), 8876513c29fSJoe Thornber void *context) 8886513c29fSJoe Thornber { 8896513c29fSJoe Thornber struct walk_info wi; 8906513c29fSJoe Thornber 8916513c29fSJoe Thornber wi.info = info; 8926513c29fSJoe Thornber wi.fn = fn; 8936513c29fSJoe Thornber wi.context = context; 8946513c29fSJoe Thornber 8956513c29fSJoe Thornber return dm_btree_walk(&info->btree_info, root, walk_ablock, &wi); 8966513c29fSJoe Thornber } 8976513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_walk); 8986513c29fSJoe Thornber 8996513c29fSJoe Thornber /*----------------------------------------------------------------*/ 900fdd1315aSJoe Thornber 901fdd1315aSJoe Thornber static int load_ablock(struct dm_array_cursor *c) 902fdd1315aSJoe Thornber { 903fdd1315aSJoe Thornber int r; 904fdd1315aSJoe Thornber __le64 value_le; 905fdd1315aSJoe Thornber uint64_t key; 906fdd1315aSJoe Thornber 907fdd1315aSJoe Thornber if (c->block) 908fdd1315aSJoe Thornber unlock_ablock(c->info, c->block); 909fdd1315aSJoe Thornber 910fdd1315aSJoe Thornber c->block = NULL; 911fdd1315aSJoe Thornber c->ab = NULL; 912fdd1315aSJoe Thornber c->index = 0; 913fdd1315aSJoe Thornber 914fdd1315aSJoe Thornber r = dm_btree_cursor_get_value(&c->cursor, &key, &value_le); 915fdd1315aSJoe Thornber if (r) { 916fdd1315aSJoe Thornber DMERR("dm_btree_cursor_get_value failed"); 917fdd1315aSJoe Thornber dm_btree_cursor_end(&c->cursor); 918fdd1315aSJoe Thornber 919fdd1315aSJoe Thornber } else { 920fdd1315aSJoe Thornber r = get_ablock(c->info, le64_to_cpu(value_le), &c->block, &c->ab); 921fdd1315aSJoe Thornber if (r) { 922fdd1315aSJoe Thornber DMERR("get_ablock failed"); 923fdd1315aSJoe Thornber dm_btree_cursor_end(&c->cursor); 924fdd1315aSJoe Thornber } 925fdd1315aSJoe Thornber } 926fdd1315aSJoe Thornber 927fdd1315aSJoe Thornber return r; 928fdd1315aSJoe Thornber } 929fdd1315aSJoe Thornber 930fdd1315aSJoe Thornber int dm_array_cursor_begin(struct dm_array_info *info, dm_block_t root, 931fdd1315aSJoe Thornber struct dm_array_cursor *c) 932fdd1315aSJoe Thornber { 933fdd1315aSJoe Thornber int r; 934fdd1315aSJoe Thornber 935fdd1315aSJoe Thornber memset(c, 0, sizeof(*c)); 936fdd1315aSJoe Thornber c->info = info; 937fdd1315aSJoe Thornber r = dm_btree_cursor_begin(&info->btree_info, root, true, &c->cursor); 938fdd1315aSJoe Thornber if (r) { 939fdd1315aSJoe Thornber DMERR("couldn't create btree cursor"); 940fdd1315aSJoe Thornber return r; 941fdd1315aSJoe Thornber } 942fdd1315aSJoe Thornber 943fdd1315aSJoe Thornber return load_ablock(c); 944fdd1315aSJoe Thornber } 945fdd1315aSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_cursor_begin); 946fdd1315aSJoe Thornber 947fdd1315aSJoe Thornber void dm_array_cursor_end(struct dm_array_cursor *c) 948fdd1315aSJoe Thornber { 949fdd1315aSJoe Thornber if (c->block) { 950fdd1315aSJoe Thornber unlock_ablock(c->info, c->block); 951fdd1315aSJoe Thornber dm_btree_cursor_end(&c->cursor); 952fdd1315aSJoe Thornber } 953fdd1315aSJoe Thornber } 954fdd1315aSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_cursor_end); 955fdd1315aSJoe Thornber 956fdd1315aSJoe Thornber int dm_array_cursor_next(struct dm_array_cursor *c) 957fdd1315aSJoe Thornber { 958fdd1315aSJoe Thornber int r; 959fdd1315aSJoe Thornber 960fdd1315aSJoe Thornber if (!c->block) 961fdd1315aSJoe Thornber return -ENODATA; 962fdd1315aSJoe Thornber 963fdd1315aSJoe Thornber c->index++; 964fdd1315aSJoe Thornber 965fdd1315aSJoe Thornber if (c->index >= le32_to_cpu(c->ab->nr_entries)) { 966fdd1315aSJoe Thornber r = dm_btree_cursor_next(&c->cursor); 967fdd1315aSJoe Thornber if (r) 968fdd1315aSJoe Thornber return r; 969fdd1315aSJoe Thornber 970fdd1315aSJoe Thornber r = load_ablock(c); 971fdd1315aSJoe Thornber if (r) 972fdd1315aSJoe Thornber return r; 973fdd1315aSJoe Thornber } 974fdd1315aSJoe Thornber 975fdd1315aSJoe Thornber return 0; 976fdd1315aSJoe Thornber } 977fdd1315aSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_cursor_next); 978fdd1315aSJoe Thornber 979*9b696229SJoe Thornber int dm_array_cursor_skip(struct dm_array_cursor *c, uint32_t count) 980*9b696229SJoe Thornber { 981*9b696229SJoe Thornber int r; 982*9b696229SJoe Thornber 983*9b696229SJoe Thornber do { 984*9b696229SJoe Thornber uint32_t remaining = le32_to_cpu(c->ab->nr_entries) - c->index; 985*9b696229SJoe Thornber 986*9b696229SJoe Thornber if (count < remaining) { 987*9b696229SJoe Thornber c->index += count; 988*9b696229SJoe Thornber return 0; 989*9b696229SJoe Thornber } 990*9b696229SJoe Thornber 991*9b696229SJoe Thornber count -= remaining; 992*9b696229SJoe Thornber r = dm_array_cursor_next(c); 993*9b696229SJoe Thornber 994*9b696229SJoe Thornber } while (!r); 995*9b696229SJoe Thornber 996*9b696229SJoe Thornber return r; 997*9b696229SJoe Thornber } 998*9b696229SJoe Thornber EXPORT_SYMBOL_GPL(dm_array_cursor_skip); 999*9b696229SJoe Thornber 1000fdd1315aSJoe Thornber void dm_array_cursor_get_value(struct dm_array_cursor *c, void **value_le) 1001fdd1315aSJoe Thornber { 1002fdd1315aSJoe Thornber *value_le = element_at(c->info, c->ab, c->index); 1003fdd1315aSJoe Thornber } 1004fdd1315aSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_cursor_get_value); 1005fdd1315aSJoe Thornber 1006fdd1315aSJoe Thornber /*----------------------------------------------------------------*/ 1007