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, 111*be500ed7SJoe Thornber void (*fn)(void *, const void *, unsigned)) 1126513c29fSJoe Thornber { 113*be500ed7SJoe Thornber unsigned nr_entries = le32_to_cpu(ab->nr_entries); 114*be500ed7SJoe Thornber fn(info->value_type.context, element_at(info, ab, 0), nr_entries); 1156513c29fSJoe Thornber } 1166513c29fSJoe Thornber 1176513c29fSJoe Thornber /* 1186513c29fSJoe Thornber * Increment every value in an array block. 1196513c29fSJoe Thornber */ 1206513c29fSJoe Thornber static void inc_ablock_entries(struct dm_array_info *info, struct array_block *ab) 1216513c29fSJoe Thornber { 1226513c29fSJoe Thornber struct dm_btree_value_type *vt = &info->value_type; 1236513c29fSJoe Thornber 1246513c29fSJoe Thornber if (vt->inc) 1256513c29fSJoe Thornber on_entries(info, ab, vt->inc); 1266513c29fSJoe Thornber } 1276513c29fSJoe Thornber 1286513c29fSJoe Thornber /* 1296513c29fSJoe Thornber * Decrement every value in an array block. 1306513c29fSJoe Thornber */ 1316513c29fSJoe Thornber static void dec_ablock_entries(struct dm_array_info *info, struct array_block *ab) 1326513c29fSJoe Thornber { 1336513c29fSJoe Thornber struct dm_btree_value_type *vt = &info->value_type; 1346513c29fSJoe Thornber 1356513c29fSJoe Thornber if (vt->dec) 1366513c29fSJoe Thornber on_entries(info, ab, vt->dec); 1376513c29fSJoe Thornber } 1386513c29fSJoe Thornber 1396513c29fSJoe Thornber /* 1406513c29fSJoe Thornber * Each array block can hold this many values. 1416513c29fSJoe Thornber */ 1426513c29fSJoe Thornber static uint32_t calc_max_entries(size_t value_size, size_t size_of_block) 1436513c29fSJoe Thornber { 1446513c29fSJoe Thornber return (size_of_block - sizeof(struct array_block)) / value_size; 1456513c29fSJoe Thornber } 1466513c29fSJoe Thornber 1476513c29fSJoe Thornber /* 1486513c29fSJoe Thornber * Allocate a new array block. The caller will need to unlock block. 1496513c29fSJoe Thornber */ 1506513c29fSJoe Thornber static int alloc_ablock(struct dm_array_info *info, size_t size_of_block, 1516513c29fSJoe Thornber uint32_t max_entries, 1526513c29fSJoe Thornber struct dm_block **block, struct array_block **ab) 1536513c29fSJoe Thornber { 1546513c29fSJoe Thornber int r; 1556513c29fSJoe Thornber 1566513c29fSJoe Thornber r = dm_tm_new_block(info->btree_info.tm, &array_validator, block); 1576513c29fSJoe Thornber if (r) 1586513c29fSJoe Thornber return r; 1596513c29fSJoe Thornber 1606513c29fSJoe Thornber (*ab) = dm_block_data(*block); 1616513c29fSJoe Thornber (*ab)->max_entries = cpu_to_le32(max_entries); 1626513c29fSJoe Thornber (*ab)->nr_entries = cpu_to_le32(0); 1636513c29fSJoe Thornber (*ab)->value_size = cpu_to_le32(info->value_type.size); 1646513c29fSJoe Thornber 1656513c29fSJoe Thornber return 0; 1666513c29fSJoe Thornber } 1676513c29fSJoe Thornber 1686513c29fSJoe Thornber /* 1696513c29fSJoe Thornber * Pad an array block out with a particular value. Every instance will 1706513c29fSJoe Thornber * cause an increment of the value_type. new_nr must always be more than 1716513c29fSJoe Thornber * the current number of entries. 1726513c29fSJoe Thornber */ 1736513c29fSJoe Thornber static void fill_ablock(struct dm_array_info *info, struct array_block *ab, 1746513c29fSJoe Thornber const void *value, unsigned new_nr) 1756513c29fSJoe Thornber { 176*be500ed7SJoe Thornber uint32_t nr_entries, delta, i; 1776513c29fSJoe Thornber struct dm_btree_value_type *vt = &info->value_type; 1786513c29fSJoe Thornber 1796513c29fSJoe Thornber BUG_ON(new_nr > le32_to_cpu(ab->max_entries)); 1806513c29fSJoe Thornber BUG_ON(new_nr < le32_to_cpu(ab->nr_entries)); 1816513c29fSJoe Thornber 1826513c29fSJoe Thornber nr_entries = le32_to_cpu(ab->nr_entries); 183*be500ed7SJoe Thornber delta = new_nr - nr_entries; 1846513c29fSJoe Thornber if (vt->inc) 185*be500ed7SJoe Thornber vt->inc(vt->context, value, delta); 186*be500ed7SJoe Thornber for (i = nr_entries; i < new_nr; i++) 1876513c29fSJoe Thornber memcpy(element_at(info, ab, i), value, vt->size); 1886513c29fSJoe Thornber ab->nr_entries = cpu_to_le32(new_nr); 1896513c29fSJoe Thornber } 1906513c29fSJoe Thornber 1916513c29fSJoe Thornber /* 1926513c29fSJoe Thornber * Remove some entries from the back of an array block. Every value 1936513c29fSJoe Thornber * removed will be decremented. new_nr must be <= the current number of 1946513c29fSJoe Thornber * entries. 1956513c29fSJoe Thornber */ 1966513c29fSJoe Thornber static void trim_ablock(struct dm_array_info *info, struct array_block *ab, 1976513c29fSJoe Thornber unsigned new_nr) 1986513c29fSJoe Thornber { 199*be500ed7SJoe Thornber uint32_t nr_entries, delta; 2006513c29fSJoe Thornber struct dm_btree_value_type *vt = &info->value_type; 2016513c29fSJoe Thornber 2026513c29fSJoe Thornber BUG_ON(new_nr > le32_to_cpu(ab->max_entries)); 2036513c29fSJoe Thornber BUG_ON(new_nr > le32_to_cpu(ab->nr_entries)); 2046513c29fSJoe Thornber 2056513c29fSJoe Thornber nr_entries = le32_to_cpu(ab->nr_entries); 206*be500ed7SJoe Thornber delta = nr_entries - new_nr; 2076513c29fSJoe Thornber if (vt->dec) 208*be500ed7SJoe Thornber vt->dec(vt->context, element_at(info, ab, new_nr - 1), delta); 2096513c29fSJoe Thornber ab->nr_entries = cpu_to_le32(new_nr); 2106513c29fSJoe Thornber } 2116513c29fSJoe Thornber 2126513c29fSJoe Thornber /* 2136513c29fSJoe Thornber * Read locks a block, and coerces it to an array block. The caller must 2146513c29fSJoe Thornber * unlock 'block' when finished. 2156513c29fSJoe Thornber */ 2166513c29fSJoe Thornber static int get_ablock(struct dm_array_info *info, dm_block_t b, 2176513c29fSJoe Thornber struct dm_block **block, struct array_block **ab) 2186513c29fSJoe Thornber { 2196513c29fSJoe Thornber int r; 2206513c29fSJoe Thornber 2216513c29fSJoe Thornber r = dm_tm_read_lock(info->btree_info.tm, b, &array_validator, block); 2226513c29fSJoe Thornber if (r) 2236513c29fSJoe Thornber return r; 2246513c29fSJoe Thornber 2256513c29fSJoe Thornber *ab = dm_block_data(*block); 2266513c29fSJoe Thornber return 0; 2276513c29fSJoe Thornber } 2286513c29fSJoe Thornber 2296513c29fSJoe Thornber /* 2306513c29fSJoe Thornber * Unlocks an array block. 2316513c29fSJoe Thornber */ 2324c7da06fSMikulas Patocka static void unlock_ablock(struct dm_array_info *info, struct dm_block *block) 2336513c29fSJoe Thornber { 2344c7da06fSMikulas Patocka dm_tm_unlock(info->btree_info.tm, block); 2356513c29fSJoe Thornber } 2366513c29fSJoe Thornber 2376513c29fSJoe Thornber /*----------------------------------------------------------------*/ 2386513c29fSJoe Thornber 2396513c29fSJoe Thornber /* 2406513c29fSJoe Thornber * Btree manipulation. 2416513c29fSJoe Thornber */ 2426513c29fSJoe Thornber 2436513c29fSJoe Thornber /* 2446513c29fSJoe Thornber * Looks up an array block in the btree, and then read locks it. 2456513c29fSJoe Thornber * 2466513c29fSJoe Thornber * index is the index of the index of the array_block, (ie. the array index 2476513c29fSJoe Thornber * / max_entries). 2486513c29fSJoe Thornber */ 2496513c29fSJoe Thornber static int lookup_ablock(struct dm_array_info *info, dm_block_t root, 2506513c29fSJoe Thornber unsigned index, struct dm_block **block, 2516513c29fSJoe Thornber struct array_block **ab) 2526513c29fSJoe Thornber { 2536513c29fSJoe Thornber int r; 2546513c29fSJoe Thornber uint64_t key = index; 2556513c29fSJoe Thornber __le64 block_le; 2566513c29fSJoe Thornber 2576513c29fSJoe Thornber r = dm_btree_lookup(&info->btree_info, root, &key, &block_le); 2586513c29fSJoe Thornber if (r) 2596513c29fSJoe Thornber return r; 2606513c29fSJoe Thornber 2616513c29fSJoe Thornber return get_ablock(info, le64_to_cpu(block_le), block, ab); 2626513c29fSJoe Thornber } 2636513c29fSJoe Thornber 2646513c29fSJoe Thornber /* 2656513c29fSJoe Thornber * Insert an array block into the btree. The block is _not_ unlocked. 2666513c29fSJoe Thornber */ 2676513c29fSJoe Thornber static int insert_ablock(struct dm_array_info *info, uint64_t index, 2686513c29fSJoe Thornber struct dm_block *block, dm_block_t *root) 2696513c29fSJoe Thornber { 2706513c29fSJoe Thornber __le64 block_le = cpu_to_le64(dm_block_location(block)); 2716513c29fSJoe Thornber 2726513c29fSJoe Thornber __dm_bless_for_disk(block_le); 2736513c29fSJoe Thornber return dm_btree_insert(&info->btree_info, *root, &index, &block_le, root); 2746513c29fSJoe Thornber } 2756513c29fSJoe Thornber 276dd6a77d9SJoe Thornber /*----------------------------------------------------------------*/ 277dd6a77d9SJoe Thornber 278dd6a77d9SJoe Thornber static int __shadow_ablock(struct dm_array_info *info, dm_block_t b, 279dd6a77d9SJoe Thornber struct dm_block **block, struct array_block **ab) 280dd6a77d9SJoe Thornber { 281dd6a77d9SJoe Thornber int inc; 282dd6a77d9SJoe Thornber int r = dm_tm_shadow_block(info->btree_info.tm, b, 283dd6a77d9SJoe Thornber &array_validator, block, &inc); 284dd6a77d9SJoe Thornber if (r) 285dd6a77d9SJoe Thornber return r; 286dd6a77d9SJoe Thornber 287dd6a77d9SJoe Thornber *ab = dm_block_data(*block); 288dd6a77d9SJoe Thornber if (inc) 289dd6a77d9SJoe Thornber inc_ablock_entries(info, *ab); 290dd6a77d9SJoe Thornber 291dd6a77d9SJoe Thornber return 0; 292dd6a77d9SJoe Thornber } 293dd6a77d9SJoe Thornber 294dd6a77d9SJoe Thornber /* 295dd6a77d9SJoe Thornber * The shadow op will often be a noop. Only insert if it really 296dd6a77d9SJoe Thornber * copied data. 297dd6a77d9SJoe Thornber */ 298dd6a77d9SJoe Thornber static int __reinsert_ablock(struct dm_array_info *info, unsigned index, 299dd6a77d9SJoe Thornber struct dm_block *block, dm_block_t b, 300dd6a77d9SJoe Thornber dm_block_t *root) 301dd6a77d9SJoe Thornber { 302dd6a77d9SJoe Thornber int r = 0; 303dd6a77d9SJoe Thornber 304dd6a77d9SJoe Thornber if (dm_block_location(block) != b) { 305dd6a77d9SJoe Thornber /* 306dd6a77d9SJoe Thornber * dm_tm_shadow_block will have already decremented the old 307dd6a77d9SJoe Thornber * block, but it is still referenced by the btree. We 308dd6a77d9SJoe Thornber * increment to stop the insert decrementing it below zero 309dd6a77d9SJoe Thornber * when overwriting the old value. 310dd6a77d9SJoe Thornber */ 311dd6a77d9SJoe Thornber dm_tm_inc(info->btree_info.tm, b); 312dd6a77d9SJoe Thornber r = insert_ablock(info, index, block, root); 313dd6a77d9SJoe Thornber } 314dd6a77d9SJoe Thornber 315dd6a77d9SJoe Thornber return r; 316dd6a77d9SJoe Thornber } 317dd6a77d9SJoe Thornber 3186513c29fSJoe Thornber /* 3196513c29fSJoe Thornber * Looks up an array block in the btree. Then shadows it, and updates the 3206513c29fSJoe Thornber * btree to point to this new shadow. 'root' is an input/output parameter 3216513c29fSJoe Thornber * for both the current root block, and the new one. 3226513c29fSJoe Thornber */ 3236513c29fSJoe Thornber static int shadow_ablock(struct dm_array_info *info, dm_block_t *root, 3246513c29fSJoe Thornber unsigned index, struct dm_block **block, 3256513c29fSJoe Thornber struct array_block **ab) 3266513c29fSJoe Thornber { 327dd6a77d9SJoe Thornber int r; 3286513c29fSJoe Thornber uint64_t key = index; 3296513c29fSJoe Thornber dm_block_t b; 3306513c29fSJoe Thornber __le64 block_le; 3316513c29fSJoe Thornber 3326513c29fSJoe Thornber r = dm_btree_lookup(&info->btree_info, *root, &key, &block_le); 3336513c29fSJoe Thornber if (r) 3346513c29fSJoe Thornber return r; 3356513c29fSJoe Thornber b = le64_to_cpu(block_le); 3366513c29fSJoe Thornber 337dd6a77d9SJoe Thornber r = __shadow_ablock(info, b, block, ab); 3386513c29fSJoe Thornber if (r) 3396513c29fSJoe Thornber return r; 3406513c29fSJoe Thornber 341dd6a77d9SJoe Thornber return __reinsert_ablock(info, index, *block, b, root); 3426513c29fSJoe Thornber } 3436513c29fSJoe Thornber 3446513c29fSJoe Thornber /* 3456513c29fSJoe Thornber * Allocate an new array block, and fill it with some values. 3466513c29fSJoe Thornber */ 3476513c29fSJoe Thornber static int insert_new_ablock(struct dm_array_info *info, size_t size_of_block, 3486513c29fSJoe Thornber uint32_t max_entries, 3496513c29fSJoe Thornber unsigned block_index, uint32_t nr, 3506513c29fSJoe Thornber const void *value, dm_block_t *root) 3516513c29fSJoe Thornber { 3526513c29fSJoe Thornber int r; 3536513c29fSJoe Thornber struct dm_block *block; 3546513c29fSJoe Thornber struct array_block *ab; 3556513c29fSJoe Thornber 3566513c29fSJoe Thornber r = alloc_ablock(info, size_of_block, max_entries, &block, &ab); 3576513c29fSJoe Thornber if (r) 3586513c29fSJoe Thornber return r; 3596513c29fSJoe Thornber 3606513c29fSJoe Thornber fill_ablock(info, ab, value, nr); 3616513c29fSJoe Thornber r = insert_ablock(info, block_index, block, root); 3626513c29fSJoe Thornber unlock_ablock(info, block); 3636513c29fSJoe Thornber 3646513c29fSJoe Thornber return r; 3656513c29fSJoe Thornber } 3666513c29fSJoe Thornber 3676513c29fSJoe Thornber static int insert_full_ablocks(struct dm_array_info *info, size_t size_of_block, 3686513c29fSJoe Thornber unsigned begin_block, unsigned end_block, 3696513c29fSJoe Thornber unsigned max_entries, const void *value, 3706513c29fSJoe Thornber dm_block_t *root) 3716513c29fSJoe Thornber { 3726513c29fSJoe Thornber int r = 0; 3736513c29fSJoe Thornber 3746513c29fSJoe Thornber for (; !r && begin_block != end_block; begin_block++) 3756513c29fSJoe Thornber r = insert_new_ablock(info, size_of_block, max_entries, begin_block, max_entries, value, root); 3766513c29fSJoe Thornber 3776513c29fSJoe Thornber return r; 3786513c29fSJoe Thornber } 3796513c29fSJoe Thornber 3806513c29fSJoe Thornber /* 3816513c29fSJoe Thornber * There are a bunch of functions involved with resizing an array. This 3826513c29fSJoe Thornber * structure holds information that commonly needed by them. Purely here 3836513c29fSJoe Thornber * to reduce parameter count. 3846513c29fSJoe Thornber */ 3856513c29fSJoe Thornber struct resize { 3866513c29fSJoe Thornber /* 3876513c29fSJoe Thornber * Describes the array. 3886513c29fSJoe Thornber */ 3896513c29fSJoe Thornber struct dm_array_info *info; 3906513c29fSJoe Thornber 3916513c29fSJoe Thornber /* 3926513c29fSJoe Thornber * The current root of the array. This gets updated. 3936513c29fSJoe Thornber */ 3946513c29fSJoe Thornber dm_block_t root; 3956513c29fSJoe Thornber 3966513c29fSJoe Thornber /* 3976513c29fSJoe Thornber * Metadata block size. Used to calculate the nr entries in an 3986513c29fSJoe Thornber * array block. 3996513c29fSJoe Thornber */ 4006513c29fSJoe Thornber size_t size_of_block; 4016513c29fSJoe Thornber 4026513c29fSJoe Thornber /* 4036513c29fSJoe Thornber * Maximum nr entries in an array block. 4046513c29fSJoe Thornber */ 4056513c29fSJoe Thornber unsigned max_entries; 4066513c29fSJoe Thornber 4076513c29fSJoe Thornber /* 4086513c29fSJoe Thornber * nr of completely full blocks in the array. 4096513c29fSJoe Thornber * 4106513c29fSJoe Thornber * 'old' refers to before the resize, 'new' after. 4116513c29fSJoe Thornber */ 4126513c29fSJoe Thornber unsigned old_nr_full_blocks, new_nr_full_blocks; 4136513c29fSJoe Thornber 4146513c29fSJoe Thornber /* 4156513c29fSJoe Thornber * Number of entries in the final block. 0 iff only full blocks in 4166513c29fSJoe Thornber * the array. 4176513c29fSJoe Thornber */ 4186513c29fSJoe Thornber unsigned old_nr_entries_in_last_block, new_nr_entries_in_last_block; 4196513c29fSJoe Thornber 4206513c29fSJoe Thornber /* 4216513c29fSJoe Thornber * The default value used when growing the array. 4226513c29fSJoe Thornber */ 4236513c29fSJoe Thornber const void *value; 4246513c29fSJoe Thornber }; 4256513c29fSJoe Thornber 4266513c29fSJoe Thornber /* 4276513c29fSJoe Thornber * Removes a consecutive set of array blocks from the btree. The values 4286513c29fSJoe Thornber * in block are decremented as a side effect of the btree remove. 4296513c29fSJoe Thornber * 4306513c29fSJoe Thornber * begin_index - the index of the first array block to remove. 4316513c29fSJoe Thornber * end_index - the one-past-the-end value. ie. this block is not removed. 4326513c29fSJoe Thornber */ 4336513c29fSJoe Thornber static int drop_blocks(struct resize *resize, unsigned begin_index, 4346513c29fSJoe Thornber unsigned end_index) 4356513c29fSJoe Thornber { 4366513c29fSJoe Thornber int r; 4376513c29fSJoe Thornber 4386513c29fSJoe Thornber while (begin_index != end_index) { 4396513c29fSJoe Thornber uint64_t key = begin_index++; 4406513c29fSJoe Thornber r = dm_btree_remove(&resize->info->btree_info, resize->root, 4416513c29fSJoe Thornber &key, &resize->root); 4426513c29fSJoe Thornber if (r) 4436513c29fSJoe Thornber return r; 4446513c29fSJoe Thornber } 4456513c29fSJoe Thornber 4466513c29fSJoe Thornber return 0; 4476513c29fSJoe Thornber } 4486513c29fSJoe Thornber 4496513c29fSJoe Thornber /* 4506513c29fSJoe Thornber * Calculates how many blocks are needed for the array. 4516513c29fSJoe Thornber */ 4526513c29fSJoe Thornber static unsigned total_nr_blocks_needed(unsigned nr_full_blocks, 4536513c29fSJoe Thornber unsigned nr_entries_in_last_block) 4546513c29fSJoe Thornber { 4556513c29fSJoe Thornber return nr_full_blocks + (nr_entries_in_last_block ? 1 : 0); 4566513c29fSJoe Thornber } 4576513c29fSJoe Thornber 4586513c29fSJoe Thornber /* 4596513c29fSJoe Thornber * Shrink an array. 4606513c29fSJoe Thornber */ 4616513c29fSJoe Thornber static int shrink(struct resize *resize) 4626513c29fSJoe Thornber { 4636513c29fSJoe Thornber int r; 4646513c29fSJoe Thornber unsigned begin, end; 4656513c29fSJoe Thornber struct dm_block *block; 4666513c29fSJoe Thornber struct array_block *ab; 4676513c29fSJoe Thornber 4686513c29fSJoe Thornber /* 4696513c29fSJoe Thornber * Lose some blocks from the back? 4706513c29fSJoe Thornber */ 4716513c29fSJoe Thornber if (resize->new_nr_full_blocks < resize->old_nr_full_blocks) { 4726513c29fSJoe Thornber begin = total_nr_blocks_needed(resize->new_nr_full_blocks, 4736513c29fSJoe Thornber resize->new_nr_entries_in_last_block); 4746513c29fSJoe Thornber end = total_nr_blocks_needed(resize->old_nr_full_blocks, 4756513c29fSJoe Thornber resize->old_nr_entries_in_last_block); 4766513c29fSJoe Thornber 4776513c29fSJoe Thornber r = drop_blocks(resize, begin, end); 4786513c29fSJoe Thornber if (r) 4796513c29fSJoe Thornber return r; 4806513c29fSJoe Thornber } 4816513c29fSJoe Thornber 4826513c29fSJoe Thornber /* 4836513c29fSJoe Thornber * Trim the new tail block 4846513c29fSJoe Thornber */ 4856513c29fSJoe Thornber if (resize->new_nr_entries_in_last_block) { 4866513c29fSJoe Thornber r = shadow_ablock(resize->info, &resize->root, 4876513c29fSJoe Thornber resize->new_nr_full_blocks, &block, &ab); 4886513c29fSJoe Thornber if (r) 4896513c29fSJoe Thornber return r; 4906513c29fSJoe Thornber 4916513c29fSJoe Thornber trim_ablock(resize->info, ab, resize->new_nr_entries_in_last_block); 4926513c29fSJoe Thornber unlock_ablock(resize->info, block); 4936513c29fSJoe Thornber } 4946513c29fSJoe Thornber 4956513c29fSJoe Thornber return 0; 4966513c29fSJoe Thornber } 4976513c29fSJoe Thornber 4986513c29fSJoe Thornber /* 4996513c29fSJoe Thornber * Grow an array. 5006513c29fSJoe Thornber */ 5016513c29fSJoe Thornber static int grow_extend_tail_block(struct resize *resize, uint32_t new_nr_entries) 5026513c29fSJoe Thornber { 5036513c29fSJoe Thornber int r; 5046513c29fSJoe Thornber struct dm_block *block; 5056513c29fSJoe Thornber struct array_block *ab; 5066513c29fSJoe Thornber 5076513c29fSJoe Thornber r = shadow_ablock(resize->info, &resize->root, 5086513c29fSJoe Thornber resize->old_nr_full_blocks, &block, &ab); 5096513c29fSJoe Thornber if (r) 5106513c29fSJoe Thornber return r; 5116513c29fSJoe Thornber 5126513c29fSJoe Thornber fill_ablock(resize->info, ab, resize->value, new_nr_entries); 5136513c29fSJoe Thornber unlock_ablock(resize->info, block); 5146513c29fSJoe Thornber 5156513c29fSJoe Thornber return r; 5166513c29fSJoe Thornber } 5176513c29fSJoe Thornber 5186513c29fSJoe Thornber static int grow_add_tail_block(struct resize *resize) 5196513c29fSJoe Thornber { 5206513c29fSJoe Thornber return insert_new_ablock(resize->info, resize->size_of_block, 5216513c29fSJoe Thornber resize->max_entries, 5226513c29fSJoe Thornber resize->new_nr_full_blocks, 5236513c29fSJoe Thornber resize->new_nr_entries_in_last_block, 5246513c29fSJoe Thornber resize->value, &resize->root); 5256513c29fSJoe Thornber } 5266513c29fSJoe Thornber 5276513c29fSJoe Thornber static int grow_needs_more_blocks(struct resize *resize) 5286513c29fSJoe Thornber { 5296513c29fSJoe Thornber int r; 5309c1d4de5SJoe Thornber unsigned old_nr_blocks = resize->old_nr_full_blocks; 5316513c29fSJoe Thornber 5326513c29fSJoe Thornber if (resize->old_nr_entries_in_last_block > 0) { 5339c1d4de5SJoe Thornber old_nr_blocks++; 5349c1d4de5SJoe Thornber 5356513c29fSJoe Thornber r = grow_extend_tail_block(resize, resize->max_entries); 5366513c29fSJoe Thornber if (r) 5376513c29fSJoe Thornber return r; 5386513c29fSJoe Thornber } 5396513c29fSJoe Thornber 5406513c29fSJoe Thornber r = insert_full_ablocks(resize->info, resize->size_of_block, 5419c1d4de5SJoe Thornber old_nr_blocks, 5426513c29fSJoe Thornber resize->new_nr_full_blocks, 5436513c29fSJoe Thornber resize->max_entries, resize->value, 5446513c29fSJoe Thornber &resize->root); 5456513c29fSJoe Thornber if (r) 5466513c29fSJoe Thornber return r; 5476513c29fSJoe Thornber 5486513c29fSJoe Thornber if (resize->new_nr_entries_in_last_block) 5496513c29fSJoe Thornber r = grow_add_tail_block(resize); 5506513c29fSJoe Thornber 5516513c29fSJoe Thornber return r; 5526513c29fSJoe Thornber } 5536513c29fSJoe Thornber 5546513c29fSJoe Thornber static int grow(struct resize *resize) 5556513c29fSJoe Thornber { 5566513c29fSJoe Thornber if (resize->new_nr_full_blocks > resize->old_nr_full_blocks) 5576513c29fSJoe Thornber return grow_needs_more_blocks(resize); 5586513c29fSJoe Thornber 5596513c29fSJoe Thornber else if (resize->old_nr_entries_in_last_block) 5606513c29fSJoe Thornber return grow_extend_tail_block(resize, resize->new_nr_entries_in_last_block); 5616513c29fSJoe Thornber 5626513c29fSJoe Thornber else 5636513c29fSJoe Thornber return grow_add_tail_block(resize); 5646513c29fSJoe Thornber } 5656513c29fSJoe Thornber 5666513c29fSJoe Thornber /*----------------------------------------------------------------*/ 5676513c29fSJoe Thornber 5686513c29fSJoe Thornber /* 5696513c29fSJoe Thornber * These are the value_type functions for the btree elements, which point 5706513c29fSJoe Thornber * to array blocks. 5716513c29fSJoe Thornber */ 572*be500ed7SJoe Thornber static void block_inc(void *context, const void *value, unsigned count) 5736513c29fSJoe Thornber { 574*be500ed7SJoe Thornber const __le64 *block_le = value; 5756513c29fSJoe Thornber struct dm_array_info *info = context; 576*be500ed7SJoe Thornber unsigned i; 5776513c29fSJoe Thornber 578*be500ed7SJoe Thornber for (i = 0; i < count; i++, block_le++) 579*be500ed7SJoe Thornber dm_tm_inc(info->btree_info.tm, le64_to_cpu(*block_le)); 5806513c29fSJoe Thornber } 5816513c29fSJoe Thornber 582*be500ed7SJoe Thornber static void __block_dec(void *context, const void *value) 5836513c29fSJoe Thornber { 5846513c29fSJoe Thornber int r; 5856513c29fSJoe Thornber uint64_t b; 5866513c29fSJoe Thornber __le64 block_le; 5876513c29fSJoe Thornber uint32_t ref_count; 5886513c29fSJoe Thornber struct dm_block *block; 5896513c29fSJoe Thornber struct array_block *ab; 5906513c29fSJoe Thornber struct dm_array_info *info = context; 5916513c29fSJoe Thornber 5926513c29fSJoe Thornber memcpy(&block_le, value, sizeof(block_le)); 5936513c29fSJoe Thornber b = le64_to_cpu(block_le); 5946513c29fSJoe Thornber 5956513c29fSJoe Thornber r = dm_tm_ref(info->btree_info.tm, b, &ref_count); 5966513c29fSJoe Thornber if (r) { 5976513c29fSJoe Thornber DMERR_LIMIT("couldn't get reference count for block %llu", 5986513c29fSJoe Thornber (unsigned long long) b); 5996513c29fSJoe Thornber return; 6006513c29fSJoe Thornber } 6016513c29fSJoe Thornber 6026513c29fSJoe Thornber if (ref_count == 1) { 6036513c29fSJoe Thornber /* 6046513c29fSJoe Thornber * We're about to drop the last reference to this ablock. 6056513c29fSJoe Thornber * So we need to decrement the ref count of the contents. 6066513c29fSJoe Thornber */ 6076513c29fSJoe Thornber r = get_ablock(info, b, &block, &ab); 6086513c29fSJoe Thornber if (r) { 6096513c29fSJoe Thornber DMERR_LIMIT("couldn't get array block %llu", 6106513c29fSJoe Thornber (unsigned long long) b); 6116513c29fSJoe Thornber return; 6126513c29fSJoe Thornber } 6136513c29fSJoe Thornber 6146513c29fSJoe Thornber dec_ablock_entries(info, ab); 6156513c29fSJoe Thornber unlock_ablock(info, block); 6166513c29fSJoe Thornber } 6176513c29fSJoe Thornber 6186513c29fSJoe Thornber dm_tm_dec(info->btree_info.tm, b); 6196513c29fSJoe Thornber } 6206513c29fSJoe Thornber 621*be500ed7SJoe Thornber static void block_dec(void *context, const void *value, unsigned count) 622*be500ed7SJoe Thornber { 623*be500ed7SJoe Thornber unsigned i; 624*be500ed7SJoe Thornber for (i = 0; i < count; i++, value += sizeof(__le64)) 625*be500ed7SJoe Thornber __block_dec(context, value); 626*be500ed7SJoe Thornber } 627*be500ed7SJoe Thornber 6286513c29fSJoe Thornber static int block_equal(void *context, const void *value1, const void *value2) 6296513c29fSJoe Thornber { 6306513c29fSJoe Thornber return !memcmp(value1, value2, sizeof(__le64)); 6316513c29fSJoe Thornber } 6326513c29fSJoe Thornber 6336513c29fSJoe Thornber /*----------------------------------------------------------------*/ 6346513c29fSJoe Thornber 6356513c29fSJoe Thornber void dm_array_info_init(struct dm_array_info *info, 6366513c29fSJoe Thornber struct dm_transaction_manager *tm, 6376513c29fSJoe Thornber struct dm_btree_value_type *vt) 6386513c29fSJoe Thornber { 6396513c29fSJoe Thornber struct dm_btree_value_type *bvt = &info->btree_info.value_type; 6406513c29fSJoe Thornber 6416513c29fSJoe Thornber memcpy(&info->value_type, vt, sizeof(info->value_type)); 6426513c29fSJoe Thornber info->btree_info.tm = tm; 6436513c29fSJoe Thornber info->btree_info.levels = 1; 6446513c29fSJoe Thornber 6456513c29fSJoe Thornber bvt->context = info; 6466513c29fSJoe Thornber bvt->size = sizeof(__le64); 6476513c29fSJoe Thornber bvt->inc = block_inc; 6486513c29fSJoe Thornber bvt->dec = block_dec; 6496513c29fSJoe Thornber bvt->equal = block_equal; 6506513c29fSJoe Thornber } 6516513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_info_init); 6526513c29fSJoe Thornber 6536513c29fSJoe Thornber int dm_array_empty(struct dm_array_info *info, dm_block_t *root) 6546513c29fSJoe Thornber { 6556513c29fSJoe Thornber return dm_btree_empty(&info->btree_info, root); 6566513c29fSJoe Thornber } 6576513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_empty); 6586513c29fSJoe Thornber 6596513c29fSJoe Thornber static int array_resize(struct dm_array_info *info, dm_block_t root, 6606513c29fSJoe Thornber uint32_t old_size, uint32_t new_size, 6616513c29fSJoe Thornber const void *value, dm_block_t *new_root) 6626513c29fSJoe Thornber { 6636513c29fSJoe Thornber int r; 6646513c29fSJoe Thornber struct resize resize; 6656513c29fSJoe Thornber 6668001e87dSJoe Thornber if (old_size == new_size) { 6678001e87dSJoe Thornber *new_root = root; 6686513c29fSJoe Thornber return 0; 6698001e87dSJoe Thornber } 6706513c29fSJoe Thornber 6716513c29fSJoe Thornber resize.info = info; 6726513c29fSJoe Thornber resize.root = root; 6736513c29fSJoe Thornber resize.size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm)); 6746513c29fSJoe Thornber resize.max_entries = calc_max_entries(info->value_type.size, 6756513c29fSJoe Thornber resize.size_of_block); 6766513c29fSJoe Thornber 6776513c29fSJoe Thornber resize.old_nr_full_blocks = old_size / resize.max_entries; 6786513c29fSJoe Thornber resize.old_nr_entries_in_last_block = old_size % resize.max_entries; 6796513c29fSJoe Thornber resize.new_nr_full_blocks = new_size / resize.max_entries; 6806513c29fSJoe Thornber resize.new_nr_entries_in_last_block = new_size % resize.max_entries; 6816513c29fSJoe Thornber resize.value = value; 6826513c29fSJoe Thornber 6836513c29fSJoe Thornber r = ((new_size > old_size) ? grow : shrink)(&resize); 6846513c29fSJoe Thornber if (r) 6856513c29fSJoe Thornber return r; 6866513c29fSJoe Thornber 6876513c29fSJoe Thornber *new_root = resize.root; 6886513c29fSJoe Thornber return 0; 6896513c29fSJoe Thornber } 6906513c29fSJoe Thornber 6916513c29fSJoe Thornber int dm_array_resize(struct dm_array_info *info, dm_block_t root, 6926513c29fSJoe Thornber uint32_t old_size, uint32_t new_size, 6936513c29fSJoe Thornber const void *value, dm_block_t *new_root) 6946513c29fSJoe Thornber __dm_written_to_disk(value) 6956513c29fSJoe Thornber { 6966513c29fSJoe Thornber int r = array_resize(info, root, old_size, new_size, value, new_root); 6976513c29fSJoe Thornber __dm_unbless_for_disk(value); 6986513c29fSJoe Thornber return r; 6996513c29fSJoe Thornber } 7006513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_resize); 7016513c29fSJoe Thornber 702dd6a77d9SJoe Thornber static int populate_ablock_with_values(struct dm_array_info *info, struct array_block *ab, 703dd6a77d9SJoe Thornber value_fn fn, void *context, unsigned base, unsigned new_nr) 704dd6a77d9SJoe Thornber { 705dd6a77d9SJoe Thornber int r; 706dd6a77d9SJoe Thornber unsigned i; 707dd6a77d9SJoe Thornber struct dm_btree_value_type *vt = &info->value_type; 708dd6a77d9SJoe Thornber 709dd6a77d9SJoe Thornber BUG_ON(le32_to_cpu(ab->nr_entries)); 710dd6a77d9SJoe Thornber BUG_ON(new_nr > le32_to_cpu(ab->max_entries)); 711dd6a77d9SJoe Thornber 712dd6a77d9SJoe Thornber for (i = 0; i < new_nr; i++) { 713dd6a77d9SJoe Thornber r = fn(base + i, element_at(info, ab, i), context); 714dd6a77d9SJoe Thornber if (r) 715dd6a77d9SJoe Thornber return r; 716dd6a77d9SJoe Thornber 717dd6a77d9SJoe Thornber if (vt->inc) 718*be500ed7SJoe Thornber vt->inc(vt->context, element_at(info, ab, i), 1); 719dd6a77d9SJoe Thornber } 720dd6a77d9SJoe Thornber 721dd6a77d9SJoe Thornber ab->nr_entries = cpu_to_le32(new_nr); 722dd6a77d9SJoe Thornber return 0; 723dd6a77d9SJoe Thornber } 724dd6a77d9SJoe Thornber 725dd6a77d9SJoe Thornber int dm_array_new(struct dm_array_info *info, dm_block_t *root, 726dd6a77d9SJoe Thornber uint32_t size, value_fn fn, void *context) 727dd6a77d9SJoe Thornber { 728dd6a77d9SJoe Thornber int r; 729dd6a77d9SJoe Thornber struct dm_block *block; 730dd6a77d9SJoe Thornber struct array_block *ab; 731dd6a77d9SJoe Thornber unsigned block_index, end_block, size_of_block, max_entries; 732dd6a77d9SJoe Thornber 733dd6a77d9SJoe Thornber r = dm_array_empty(info, root); 734dd6a77d9SJoe Thornber if (r) 735dd6a77d9SJoe Thornber return r; 736dd6a77d9SJoe Thornber 737dd6a77d9SJoe Thornber size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm)); 738dd6a77d9SJoe Thornber max_entries = calc_max_entries(info->value_type.size, size_of_block); 739dd6a77d9SJoe Thornber end_block = dm_div_up(size, max_entries); 740dd6a77d9SJoe Thornber 741dd6a77d9SJoe Thornber for (block_index = 0; block_index != end_block; block_index++) { 742dd6a77d9SJoe Thornber r = alloc_ablock(info, size_of_block, max_entries, &block, &ab); 743dd6a77d9SJoe Thornber if (r) 744dd6a77d9SJoe Thornber break; 745dd6a77d9SJoe Thornber 746dd6a77d9SJoe Thornber r = populate_ablock_with_values(info, ab, fn, context, 747dd6a77d9SJoe Thornber block_index * max_entries, 748dd6a77d9SJoe Thornber min(max_entries, size)); 749dd6a77d9SJoe Thornber if (r) { 750dd6a77d9SJoe Thornber unlock_ablock(info, block); 751dd6a77d9SJoe Thornber break; 752dd6a77d9SJoe Thornber } 753dd6a77d9SJoe Thornber 754dd6a77d9SJoe Thornber r = insert_ablock(info, block_index, block, root); 755dd6a77d9SJoe Thornber unlock_ablock(info, block); 756dd6a77d9SJoe Thornber if (r) 757dd6a77d9SJoe Thornber break; 758dd6a77d9SJoe Thornber 759dd6a77d9SJoe Thornber size -= max_entries; 760dd6a77d9SJoe Thornber } 761dd6a77d9SJoe Thornber 762dd6a77d9SJoe Thornber return r; 763dd6a77d9SJoe Thornber } 764dd6a77d9SJoe Thornber EXPORT_SYMBOL_GPL(dm_array_new); 765dd6a77d9SJoe Thornber 7666513c29fSJoe Thornber int dm_array_del(struct dm_array_info *info, dm_block_t root) 7676513c29fSJoe Thornber { 7686513c29fSJoe Thornber return dm_btree_del(&info->btree_info, root); 7696513c29fSJoe Thornber } 7706513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_del); 7716513c29fSJoe Thornber 7726513c29fSJoe Thornber int dm_array_get_value(struct dm_array_info *info, dm_block_t root, 7736513c29fSJoe Thornber uint32_t index, void *value_le) 7746513c29fSJoe Thornber { 7756513c29fSJoe Thornber int r; 7766513c29fSJoe Thornber struct dm_block *block; 7776513c29fSJoe Thornber struct array_block *ab; 7786513c29fSJoe Thornber size_t size_of_block; 7796513c29fSJoe Thornber unsigned entry, max_entries; 7806513c29fSJoe Thornber 7816513c29fSJoe Thornber size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm)); 7826513c29fSJoe Thornber max_entries = calc_max_entries(info->value_type.size, size_of_block); 7836513c29fSJoe Thornber 7846513c29fSJoe Thornber r = lookup_ablock(info, root, index / max_entries, &block, &ab); 7856513c29fSJoe Thornber if (r) 7866513c29fSJoe Thornber return r; 7876513c29fSJoe Thornber 7886513c29fSJoe Thornber entry = index % max_entries; 7896513c29fSJoe Thornber if (entry >= le32_to_cpu(ab->nr_entries)) 7906513c29fSJoe Thornber r = -ENODATA; 7916513c29fSJoe Thornber else 7926513c29fSJoe Thornber memcpy(value_le, element_at(info, ab, entry), 7936513c29fSJoe Thornber info->value_type.size); 7946513c29fSJoe Thornber 7956513c29fSJoe Thornber unlock_ablock(info, block); 7966513c29fSJoe Thornber return r; 7976513c29fSJoe Thornber } 7986513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_get_value); 7996513c29fSJoe Thornber 8006513c29fSJoe Thornber static int array_set_value(struct dm_array_info *info, dm_block_t root, 8016513c29fSJoe Thornber uint32_t index, const void *value, dm_block_t *new_root) 8026513c29fSJoe Thornber { 8036513c29fSJoe Thornber int r; 8046513c29fSJoe Thornber struct dm_block *block; 8056513c29fSJoe Thornber struct array_block *ab; 8066513c29fSJoe Thornber size_t size_of_block; 8076513c29fSJoe Thornber unsigned max_entries; 8086513c29fSJoe Thornber unsigned entry; 8096513c29fSJoe Thornber void *old_value; 8106513c29fSJoe Thornber struct dm_btree_value_type *vt = &info->value_type; 8116513c29fSJoe Thornber 8126513c29fSJoe Thornber size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm)); 8136513c29fSJoe Thornber max_entries = calc_max_entries(info->value_type.size, size_of_block); 8146513c29fSJoe Thornber 8156513c29fSJoe Thornber r = shadow_ablock(info, &root, index / max_entries, &block, &ab); 8166513c29fSJoe Thornber if (r) 8176513c29fSJoe Thornber return r; 8186513c29fSJoe Thornber *new_root = root; 8196513c29fSJoe Thornber 8206513c29fSJoe Thornber entry = index % max_entries; 8216513c29fSJoe Thornber if (entry >= le32_to_cpu(ab->nr_entries)) { 8226513c29fSJoe Thornber r = -ENODATA; 8236513c29fSJoe Thornber goto out; 8246513c29fSJoe Thornber } 8256513c29fSJoe Thornber 8266513c29fSJoe Thornber old_value = element_at(info, ab, entry); 8276513c29fSJoe Thornber if (vt->dec && 8286513c29fSJoe Thornber (!vt->equal || !vt->equal(vt->context, old_value, value))) { 829*be500ed7SJoe Thornber vt->dec(vt->context, old_value, 1); 8306513c29fSJoe Thornber if (vt->inc) 831*be500ed7SJoe Thornber vt->inc(vt->context, value, 1); 8326513c29fSJoe Thornber } 8336513c29fSJoe Thornber 8346513c29fSJoe Thornber memcpy(old_value, value, info->value_type.size); 8356513c29fSJoe Thornber 8366513c29fSJoe Thornber out: 8376513c29fSJoe Thornber unlock_ablock(info, block); 8386513c29fSJoe Thornber return r; 8396513c29fSJoe Thornber } 8406513c29fSJoe Thornber 8416513c29fSJoe Thornber int dm_array_set_value(struct dm_array_info *info, dm_block_t root, 8426513c29fSJoe Thornber uint32_t index, const void *value, dm_block_t *new_root) 8436513c29fSJoe Thornber __dm_written_to_disk(value) 8446513c29fSJoe Thornber { 8456513c29fSJoe Thornber int r; 8466513c29fSJoe Thornber 8476513c29fSJoe Thornber r = array_set_value(info, root, index, value, new_root); 8486513c29fSJoe Thornber __dm_unbless_for_disk(value); 8496513c29fSJoe Thornber return r; 8506513c29fSJoe Thornber } 8516513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_set_value); 8526513c29fSJoe Thornber 8536513c29fSJoe Thornber struct walk_info { 8546513c29fSJoe Thornber struct dm_array_info *info; 8556513c29fSJoe Thornber int (*fn)(void *context, uint64_t key, void *leaf); 8566513c29fSJoe Thornber void *context; 8576513c29fSJoe Thornber }; 8586513c29fSJoe Thornber 8596513c29fSJoe Thornber static int walk_ablock(void *context, uint64_t *keys, void *leaf) 8606513c29fSJoe Thornber { 8616513c29fSJoe Thornber struct walk_info *wi = context; 8626513c29fSJoe Thornber 8636513c29fSJoe Thornber int r; 8646513c29fSJoe Thornber unsigned i; 8656513c29fSJoe Thornber __le64 block_le; 8666513c29fSJoe Thornber unsigned nr_entries, max_entries; 8676513c29fSJoe Thornber struct dm_block *block; 8686513c29fSJoe Thornber struct array_block *ab; 8696513c29fSJoe Thornber 8706513c29fSJoe Thornber memcpy(&block_le, leaf, sizeof(block_le)); 8716513c29fSJoe Thornber r = get_ablock(wi->info, le64_to_cpu(block_le), &block, &ab); 8726513c29fSJoe Thornber if (r) 8736513c29fSJoe Thornber return r; 8746513c29fSJoe Thornber 8756513c29fSJoe Thornber max_entries = le32_to_cpu(ab->max_entries); 8766513c29fSJoe Thornber nr_entries = le32_to_cpu(ab->nr_entries); 8776513c29fSJoe Thornber for (i = 0; i < nr_entries; i++) { 8786513c29fSJoe Thornber r = wi->fn(wi->context, keys[0] * max_entries + i, 8796513c29fSJoe Thornber element_at(wi->info, ab, i)); 8806513c29fSJoe Thornber 8816513c29fSJoe Thornber if (r) 8826513c29fSJoe Thornber break; 8836513c29fSJoe Thornber } 8846513c29fSJoe Thornber 8856513c29fSJoe Thornber unlock_ablock(wi->info, block); 8866513c29fSJoe Thornber return r; 8876513c29fSJoe Thornber } 8886513c29fSJoe Thornber 8896513c29fSJoe Thornber int dm_array_walk(struct dm_array_info *info, dm_block_t root, 8906513c29fSJoe Thornber int (*fn)(void *, uint64_t key, void *leaf), 8916513c29fSJoe Thornber void *context) 8926513c29fSJoe Thornber { 8936513c29fSJoe Thornber struct walk_info wi; 8946513c29fSJoe Thornber 8956513c29fSJoe Thornber wi.info = info; 8966513c29fSJoe Thornber wi.fn = fn; 8976513c29fSJoe Thornber wi.context = context; 8986513c29fSJoe Thornber 8996513c29fSJoe Thornber return dm_btree_walk(&info->btree_info, root, walk_ablock, &wi); 9006513c29fSJoe Thornber } 9016513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_walk); 9026513c29fSJoe Thornber 9036513c29fSJoe Thornber /*----------------------------------------------------------------*/ 904fdd1315aSJoe Thornber 905fdd1315aSJoe Thornber static int load_ablock(struct dm_array_cursor *c) 906fdd1315aSJoe Thornber { 907fdd1315aSJoe Thornber int r; 908fdd1315aSJoe Thornber __le64 value_le; 909fdd1315aSJoe Thornber uint64_t key; 910fdd1315aSJoe Thornber 911fdd1315aSJoe Thornber if (c->block) 912fdd1315aSJoe Thornber unlock_ablock(c->info, c->block); 913fdd1315aSJoe Thornber 914fdd1315aSJoe Thornber c->block = NULL; 915fdd1315aSJoe Thornber c->ab = NULL; 916fdd1315aSJoe Thornber c->index = 0; 917fdd1315aSJoe Thornber 918fdd1315aSJoe Thornber r = dm_btree_cursor_get_value(&c->cursor, &key, &value_le); 919fdd1315aSJoe Thornber if (r) { 920fdd1315aSJoe Thornber DMERR("dm_btree_cursor_get_value failed"); 921fdd1315aSJoe Thornber dm_btree_cursor_end(&c->cursor); 922fdd1315aSJoe Thornber 923fdd1315aSJoe Thornber } else { 924fdd1315aSJoe Thornber r = get_ablock(c->info, le64_to_cpu(value_le), &c->block, &c->ab); 925fdd1315aSJoe Thornber if (r) { 926fdd1315aSJoe Thornber DMERR("get_ablock failed"); 927fdd1315aSJoe Thornber dm_btree_cursor_end(&c->cursor); 928fdd1315aSJoe Thornber } 929fdd1315aSJoe Thornber } 930fdd1315aSJoe Thornber 931fdd1315aSJoe Thornber return r; 932fdd1315aSJoe Thornber } 933fdd1315aSJoe Thornber 934fdd1315aSJoe Thornber int dm_array_cursor_begin(struct dm_array_info *info, dm_block_t root, 935fdd1315aSJoe Thornber struct dm_array_cursor *c) 936fdd1315aSJoe Thornber { 937fdd1315aSJoe Thornber int r; 938fdd1315aSJoe Thornber 939fdd1315aSJoe Thornber memset(c, 0, sizeof(*c)); 940fdd1315aSJoe Thornber c->info = info; 941fdd1315aSJoe Thornber r = dm_btree_cursor_begin(&info->btree_info, root, true, &c->cursor); 942fdd1315aSJoe Thornber if (r) { 943fdd1315aSJoe Thornber DMERR("couldn't create btree cursor"); 944fdd1315aSJoe Thornber return r; 945fdd1315aSJoe Thornber } 946fdd1315aSJoe Thornber 947fdd1315aSJoe Thornber return load_ablock(c); 948fdd1315aSJoe Thornber } 949fdd1315aSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_cursor_begin); 950fdd1315aSJoe Thornber 951fdd1315aSJoe Thornber void dm_array_cursor_end(struct dm_array_cursor *c) 952fdd1315aSJoe Thornber { 953fdd1315aSJoe Thornber if (c->block) { 954fdd1315aSJoe Thornber unlock_ablock(c->info, c->block); 955fdd1315aSJoe Thornber dm_btree_cursor_end(&c->cursor); 956fdd1315aSJoe Thornber } 957fdd1315aSJoe Thornber } 958fdd1315aSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_cursor_end); 959fdd1315aSJoe Thornber 960fdd1315aSJoe Thornber int dm_array_cursor_next(struct dm_array_cursor *c) 961fdd1315aSJoe Thornber { 962fdd1315aSJoe Thornber int r; 963fdd1315aSJoe Thornber 964fdd1315aSJoe Thornber if (!c->block) 965fdd1315aSJoe Thornber return -ENODATA; 966fdd1315aSJoe Thornber 967fdd1315aSJoe Thornber c->index++; 968fdd1315aSJoe Thornber 969fdd1315aSJoe Thornber if (c->index >= le32_to_cpu(c->ab->nr_entries)) { 970fdd1315aSJoe Thornber r = dm_btree_cursor_next(&c->cursor); 971fdd1315aSJoe Thornber if (r) 972fdd1315aSJoe Thornber return r; 973fdd1315aSJoe Thornber 974fdd1315aSJoe Thornber r = load_ablock(c); 975fdd1315aSJoe Thornber if (r) 976fdd1315aSJoe Thornber return r; 977fdd1315aSJoe Thornber } 978fdd1315aSJoe Thornber 979fdd1315aSJoe Thornber return 0; 980fdd1315aSJoe Thornber } 981fdd1315aSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_cursor_next); 982fdd1315aSJoe Thornber 9839b696229SJoe Thornber int dm_array_cursor_skip(struct dm_array_cursor *c, uint32_t count) 9849b696229SJoe Thornber { 9859b696229SJoe Thornber int r; 9869b696229SJoe Thornber 9879b696229SJoe Thornber do { 9889b696229SJoe Thornber uint32_t remaining = le32_to_cpu(c->ab->nr_entries) - c->index; 9899b696229SJoe Thornber 9909b696229SJoe Thornber if (count < remaining) { 9919b696229SJoe Thornber c->index += count; 9929b696229SJoe Thornber return 0; 9939b696229SJoe Thornber } 9949b696229SJoe Thornber 9959b696229SJoe Thornber count -= remaining; 9969b696229SJoe Thornber r = dm_array_cursor_next(c); 9979b696229SJoe Thornber 9989b696229SJoe Thornber } while (!r); 9999b696229SJoe Thornber 10009b696229SJoe Thornber return r; 10019b696229SJoe Thornber } 10029b696229SJoe Thornber EXPORT_SYMBOL_GPL(dm_array_cursor_skip); 10039b696229SJoe Thornber 1004fdd1315aSJoe Thornber void dm_array_cursor_get_value(struct dm_array_cursor *c, void **value_le) 1005fdd1315aSJoe Thornber { 1006fdd1315aSJoe Thornber *value_le = element_at(c->info, c->ab, c->index); 1007fdd1315aSJoe Thornber } 1008fdd1315aSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_cursor_get_value); 1009fdd1315aSJoe Thornber 1010fdd1315aSJoe Thornber /*----------------------------------------------------------------*/ 1011