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 */ 2366513c29fSJoe Thornber static int unlock_ablock(struct dm_array_info *info, struct dm_block *block) 2376513c29fSJoe Thornber { 2386513c29fSJoe Thornber return 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 2806513c29fSJoe Thornber /* 2816513c29fSJoe Thornber * Looks up an array block in the btree. Then shadows it, and updates the 2826513c29fSJoe Thornber * btree to point to this new shadow. 'root' is an input/output parameter 2836513c29fSJoe Thornber * for both the current root block, and the new one. 2846513c29fSJoe Thornber */ 2856513c29fSJoe Thornber static int shadow_ablock(struct dm_array_info *info, dm_block_t *root, 2866513c29fSJoe Thornber unsigned index, struct dm_block **block, 2876513c29fSJoe Thornber struct array_block **ab) 2886513c29fSJoe Thornber { 2896513c29fSJoe Thornber int r, inc; 2906513c29fSJoe Thornber uint64_t key = index; 2916513c29fSJoe Thornber dm_block_t b; 2926513c29fSJoe Thornber __le64 block_le; 2936513c29fSJoe Thornber 2946513c29fSJoe Thornber /* 2956513c29fSJoe Thornber * lookup 2966513c29fSJoe Thornber */ 2976513c29fSJoe Thornber r = dm_btree_lookup(&info->btree_info, *root, &key, &block_le); 2986513c29fSJoe Thornber if (r) 2996513c29fSJoe Thornber return r; 3006513c29fSJoe Thornber b = le64_to_cpu(block_le); 3016513c29fSJoe Thornber 3026513c29fSJoe Thornber /* 3036513c29fSJoe Thornber * shadow 3046513c29fSJoe Thornber */ 3056513c29fSJoe Thornber r = dm_tm_shadow_block(info->btree_info.tm, b, 3066513c29fSJoe Thornber &array_validator, block, &inc); 3076513c29fSJoe Thornber if (r) 3086513c29fSJoe Thornber return r; 3096513c29fSJoe Thornber 3106513c29fSJoe Thornber *ab = dm_block_data(*block); 3116513c29fSJoe Thornber if (inc) 3126513c29fSJoe Thornber inc_ablock_entries(info, *ab); 3136513c29fSJoe Thornber 3146513c29fSJoe Thornber /* 3156513c29fSJoe Thornber * Reinsert. 3166513c29fSJoe Thornber * 3176513c29fSJoe Thornber * The shadow op will often be a noop. Only insert if it really 3186513c29fSJoe Thornber * copied data. 3196513c29fSJoe Thornber */ 3206513c29fSJoe Thornber if (dm_block_location(*block) != b) 3216513c29fSJoe Thornber r = insert_ablock(info, index, *block, root); 3226513c29fSJoe Thornber 3236513c29fSJoe Thornber return r; 3246513c29fSJoe Thornber } 3256513c29fSJoe Thornber 3266513c29fSJoe Thornber /* 3276513c29fSJoe Thornber * Allocate an new array block, and fill it with some values. 3286513c29fSJoe Thornber */ 3296513c29fSJoe Thornber static int insert_new_ablock(struct dm_array_info *info, size_t size_of_block, 3306513c29fSJoe Thornber uint32_t max_entries, 3316513c29fSJoe Thornber unsigned block_index, uint32_t nr, 3326513c29fSJoe Thornber const void *value, dm_block_t *root) 3336513c29fSJoe Thornber { 3346513c29fSJoe Thornber int r; 3356513c29fSJoe Thornber struct dm_block *block; 3366513c29fSJoe Thornber struct array_block *ab; 3376513c29fSJoe Thornber 3386513c29fSJoe Thornber r = alloc_ablock(info, size_of_block, max_entries, &block, &ab); 3396513c29fSJoe Thornber if (r) 3406513c29fSJoe Thornber return r; 3416513c29fSJoe Thornber 3426513c29fSJoe Thornber fill_ablock(info, ab, value, nr); 3436513c29fSJoe Thornber r = insert_ablock(info, block_index, block, root); 3446513c29fSJoe Thornber unlock_ablock(info, block); 3456513c29fSJoe Thornber 3466513c29fSJoe Thornber return r; 3476513c29fSJoe Thornber } 3486513c29fSJoe Thornber 3496513c29fSJoe Thornber static int insert_full_ablocks(struct dm_array_info *info, size_t size_of_block, 3506513c29fSJoe Thornber unsigned begin_block, unsigned end_block, 3516513c29fSJoe Thornber unsigned max_entries, const void *value, 3526513c29fSJoe Thornber dm_block_t *root) 3536513c29fSJoe Thornber { 3546513c29fSJoe Thornber int r = 0; 3556513c29fSJoe Thornber 3566513c29fSJoe Thornber for (; !r && begin_block != end_block; begin_block++) 3576513c29fSJoe Thornber r = insert_new_ablock(info, size_of_block, max_entries, begin_block, max_entries, value, root); 3586513c29fSJoe Thornber 3596513c29fSJoe Thornber return r; 3606513c29fSJoe Thornber } 3616513c29fSJoe Thornber 3626513c29fSJoe Thornber /* 3636513c29fSJoe Thornber * There are a bunch of functions involved with resizing an array. This 3646513c29fSJoe Thornber * structure holds information that commonly needed by them. Purely here 3656513c29fSJoe Thornber * to reduce parameter count. 3666513c29fSJoe Thornber */ 3676513c29fSJoe Thornber struct resize { 3686513c29fSJoe Thornber /* 3696513c29fSJoe Thornber * Describes the array. 3706513c29fSJoe Thornber */ 3716513c29fSJoe Thornber struct dm_array_info *info; 3726513c29fSJoe Thornber 3736513c29fSJoe Thornber /* 3746513c29fSJoe Thornber * The current root of the array. This gets updated. 3756513c29fSJoe Thornber */ 3766513c29fSJoe Thornber dm_block_t root; 3776513c29fSJoe Thornber 3786513c29fSJoe Thornber /* 3796513c29fSJoe Thornber * Metadata block size. Used to calculate the nr entries in an 3806513c29fSJoe Thornber * array block. 3816513c29fSJoe Thornber */ 3826513c29fSJoe Thornber size_t size_of_block; 3836513c29fSJoe Thornber 3846513c29fSJoe Thornber /* 3856513c29fSJoe Thornber * Maximum nr entries in an array block. 3866513c29fSJoe Thornber */ 3876513c29fSJoe Thornber unsigned max_entries; 3886513c29fSJoe Thornber 3896513c29fSJoe Thornber /* 3906513c29fSJoe Thornber * nr of completely full blocks in the array. 3916513c29fSJoe Thornber * 3926513c29fSJoe Thornber * 'old' refers to before the resize, 'new' after. 3936513c29fSJoe Thornber */ 3946513c29fSJoe Thornber unsigned old_nr_full_blocks, new_nr_full_blocks; 3956513c29fSJoe Thornber 3966513c29fSJoe Thornber /* 3976513c29fSJoe Thornber * Number of entries in the final block. 0 iff only full blocks in 3986513c29fSJoe Thornber * the array. 3996513c29fSJoe Thornber */ 4006513c29fSJoe Thornber unsigned old_nr_entries_in_last_block, new_nr_entries_in_last_block; 4016513c29fSJoe Thornber 4026513c29fSJoe Thornber /* 4036513c29fSJoe Thornber * The default value used when growing the array. 4046513c29fSJoe Thornber */ 4056513c29fSJoe Thornber const void *value; 4066513c29fSJoe Thornber }; 4076513c29fSJoe Thornber 4086513c29fSJoe Thornber /* 4096513c29fSJoe Thornber * Removes a consecutive set of array blocks from the btree. The values 4106513c29fSJoe Thornber * in block are decremented as a side effect of the btree remove. 4116513c29fSJoe Thornber * 4126513c29fSJoe Thornber * begin_index - the index of the first array block to remove. 4136513c29fSJoe Thornber * end_index - the one-past-the-end value. ie. this block is not removed. 4146513c29fSJoe Thornber */ 4156513c29fSJoe Thornber static int drop_blocks(struct resize *resize, unsigned begin_index, 4166513c29fSJoe Thornber unsigned end_index) 4176513c29fSJoe Thornber { 4186513c29fSJoe Thornber int r; 4196513c29fSJoe Thornber 4206513c29fSJoe Thornber while (begin_index != end_index) { 4216513c29fSJoe Thornber uint64_t key = begin_index++; 4226513c29fSJoe Thornber r = dm_btree_remove(&resize->info->btree_info, resize->root, 4236513c29fSJoe Thornber &key, &resize->root); 4246513c29fSJoe Thornber if (r) 4256513c29fSJoe Thornber return r; 4266513c29fSJoe Thornber } 4276513c29fSJoe Thornber 4286513c29fSJoe Thornber return 0; 4296513c29fSJoe Thornber } 4306513c29fSJoe Thornber 4316513c29fSJoe Thornber /* 4326513c29fSJoe Thornber * Calculates how many blocks are needed for the array. 4336513c29fSJoe Thornber */ 4346513c29fSJoe Thornber static unsigned total_nr_blocks_needed(unsigned nr_full_blocks, 4356513c29fSJoe Thornber unsigned nr_entries_in_last_block) 4366513c29fSJoe Thornber { 4376513c29fSJoe Thornber return nr_full_blocks + (nr_entries_in_last_block ? 1 : 0); 4386513c29fSJoe Thornber } 4396513c29fSJoe Thornber 4406513c29fSJoe Thornber /* 4416513c29fSJoe Thornber * Shrink an array. 4426513c29fSJoe Thornber */ 4436513c29fSJoe Thornber static int shrink(struct resize *resize) 4446513c29fSJoe Thornber { 4456513c29fSJoe Thornber int r; 4466513c29fSJoe Thornber unsigned begin, end; 4476513c29fSJoe Thornber struct dm_block *block; 4486513c29fSJoe Thornber struct array_block *ab; 4496513c29fSJoe Thornber 4506513c29fSJoe Thornber /* 4516513c29fSJoe Thornber * Lose some blocks from the back? 4526513c29fSJoe Thornber */ 4536513c29fSJoe Thornber if (resize->new_nr_full_blocks < resize->old_nr_full_blocks) { 4546513c29fSJoe Thornber begin = total_nr_blocks_needed(resize->new_nr_full_blocks, 4556513c29fSJoe Thornber resize->new_nr_entries_in_last_block); 4566513c29fSJoe Thornber end = total_nr_blocks_needed(resize->old_nr_full_blocks, 4576513c29fSJoe Thornber resize->old_nr_entries_in_last_block); 4586513c29fSJoe Thornber 4596513c29fSJoe Thornber r = drop_blocks(resize, begin, end); 4606513c29fSJoe Thornber if (r) 4616513c29fSJoe Thornber return r; 4626513c29fSJoe Thornber } 4636513c29fSJoe Thornber 4646513c29fSJoe Thornber /* 4656513c29fSJoe Thornber * Trim the new tail block 4666513c29fSJoe Thornber */ 4676513c29fSJoe Thornber if (resize->new_nr_entries_in_last_block) { 4686513c29fSJoe Thornber r = shadow_ablock(resize->info, &resize->root, 4696513c29fSJoe Thornber resize->new_nr_full_blocks, &block, &ab); 4706513c29fSJoe Thornber if (r) 4716513c29fSJoe Thornber return r; 4726513c29fSJoe Thornber 4736513c29fSJoe Thornber trim_ablock(resize->info, ab, resize->new_nr_entries_in_last_block); 4746513c29fSJoe Thornber unlock_ablock(resize->info, block); 4756513c29fSJoe Thornber } 4766513c29fSJoe Thornber 4776513c29fSJoe Thornber return 0; 4786513c29fSJoe Thornber } 4796513c29fSJoe Thornber 4806513c29fSJoe Thornber /* 4816513c29fSJoe Thornber * Grow an array. 4826513c29fSJoe Thornber */ 4836513c29fSJoe Thornber static int grow_extend_tail_block(struct resize *resize, uint32_t new_nr_entries) 4846513c29fSJoe Thornber { 4856513c29fSJoe Thornber int r; 4866513c29fSJoe Thornber struct dm_block *block; 4876513c29fSJoe Thornber struct array_block *ab; 4886513c29fSJoe Thornber 4896513c29fSJoe Thornber r = shadow_ablock(resize->info, &resize->root, 4906513c29fSJoe Thornber resize->old_nr_full_blocks, &block, &ab); 4916513c29fSJoe Thornber if (r) 4926513c29fSJoe Thornber return r; 4936513c29fSJoe Thornber 4946513c29fSJoe Thornber fill_ablock(resize->info, ab, resize->value, new_nr_entries); 4956513c29fSJoe Thornber unlock_ablock(resize->info, block); 4966513c29fSJoe Thornber 4976513c29fSJoe Thornber return r; 4986513c29fSJoe Thornber } 4996513c29fSJoe Thornber 5006513c29fSJoe Thornber static int grow_add_tail_block(struct resize *resize) 5016513c29fSJoe Thornber { 5026513c29fSJoe Thornber return insert_new_ablock(resize->info, resize->size_of_block, 5036513c29fSJoe Thornber resize->max_entries, 5046513c29fSJoe Thornber resize->new_nr_full_blocks, 5056513c29fSJoe Thornber resize->new_nr_entries_in_last_block, 5066513c29fSJoe Thornber resize->value, &resize->root); 5076513c29fSJoe Thornber } 5086513c29fSJoe Thornber 5096513c29fSJoe Thornber static int grow_needs_more_blocks(struct resize *resize) 5106513c29fSJoe Thornber { 5116513c29fSJoe Thornber int r; 512*9c1d4de5SJoe Thornber unsigned old_nr_blocks = resize->old_nr_full_blocks; 5136513c29fSJoe Thornber 5146513c29fSJoe Thornber if (resize->old_nr_entries_in_last_block > 0) { 515*9c1d4de5SJoe Thornber old_nr_blocks++; 516*9c1d4de5SJoe Thornber 5176513c29fSJoe Thornber r = grow_extend_tail_block(resize, resize->max_entries); 5186513c29fSJoe Thornber if (r) 5196513c29fSJoe Thornber return r; 5206513c29fSJoe Thornber } 5216513c29fSJoe Thornber 5226513c29fSJoe Thornber r = insert_full_ablocks(resize->info, resize->size_of_block, 523*9c1d4de5SJoe Thornber old_nr_blocks, 5246513c29fSJoe Thornber resize->new_nr_full_blocks, 5256513c29fSJoe Thornber resize->max_entries, resize->value, 5266513c29fSJoe Thornber &resize->root); 5276513c29fSJoe Thornber if (r) 5286513c29fSJoe Thornber return r; 5296513c29fSJoe Thornber 5306513c29fSJoe Thornber if (resize->new_nr_entries_in_last_block) 5316513c29fSJoe Thornber r = grow_add_tail_block(resize); 5326513c29fSJoe Thornber 5336513c29fSJoe Thornber return r; 5346513c29fSJoe Thornber } 5356513c29fSJoe Thornber 5366513c29fSJoe Thornber static int grow(struct resize *resize) 5376513c29fSJoe Thornber { 5386513c29fSJoe Thornber if (resize->new_nr_full_blocks > resize->old_nr_full_blocks) 5396513c29fSJoe Thornber return grow_needs_more_blocks(resize); 5406513c29fSJoe Thornber 5416513c29fSJoe Thornber else if (resize->old_nr_entries_in_last_block) 5426513c29fSJoe Thornber return grow_extend_tail_block(resize, resize->new_nr_entries_in_last_block); 5436513c29fSJoe Thornber 5446513c29fSJoe Thornber else 5456513c29fSJoe Thornber return grow_add_tail_block(resize); 5466513c29fSJoe Thornber } 5476513c29fSJoe Thornber 5486513c29fSJoe Thornber /*----------------------------------------------------------------*/ 5496513c29fSJoe Thornber 5506513c29fSJoe Thornber /* 5516513c29fSJoe Thornber * These are the value_type functions for the btree elements, which point 5526513c29fSJoe Thornber * to array blocks. 5536513c29fSJoe Thornber */ 5546513c29fSJoe Thornber static void block_inc(void *context, const void *value) 5556513c29fSJoe Thornber { 5566513c29fSJoe Thornber __le64 block_le; 5576513c29fSJoe Thornber struct dm_array_info *info = context; 5586513c29fSJoe Thornber 5596513c29fSJoe Thornber memcpy(&block_le, value, sizeof(block_le)); 5606513c29fSJoe Thornber dm_tm_inc(info->btree_info.tm, le64_to_cpu(block_le)); 5616513c29fSJoe Thornber } 5626513c29fSJoe Thornber 5636513c29fSJoe Thornber static void block_dec(void *context, const void *value) 5646513c29fSJoe Thornber { 5656513c29fSJoe Thornber int r; 5666513c29fSJoe Thornber uint64_t b; 5676513c29fSJoe Thornber __le64 block_le; 5686513c29fSJoe Thornber uint32_t ref_count; 5696513c29fSJoe Thornber struct dm_block *block; 5706513c29fSJoe Thornber struct array_block *ab; 5716513c29fSJoe Thornber struct dm_array_info *info = context; 5726513c29fSJoe Thornber 5736513c29fSJoe Thornber memcpy(&block_le, value, sizeof(block_le)); 5746513c29fSJoe Thornber b = le64_to_cpu(block_le); 5756513c29fSJoe Thornber 5766513c29fSJoe Thornber r = dm_tm_ref(info->btree_info.tm, b, &ref_count); 5776513c29fSJoe Thornber if (r) { 5786513c29fSJoe Thornber DMERR_LIMIT("couldn't get reference count for block %llu", 5796513c29fSJoe Thornber (unsigned long long) b); 5806513c29fSJoe Thornber return; 5816513c29fSJoe Thornber } 5826513c29fSJoe Thornber 5836513c29fSJoe Thornber if (ref_count == 1) { 5846513c29fSJoe Thornber /* 5856513c29fSJoe Thornber * We're about to drop the last reference to this ablock. 5866513c29fSJoe Thornber * So we need to decrement the ref count of the contents. 5876513c29fSJoe Thornber */ 5886513c29fSJoe Thornber r = get_ablock(info, b, &block, &ab); 5896513c29fSJoe Thornber if (r) { 5906513c29fSJoe Thornber DMERR_LIMIT("couldn't get array block %llu", 5916513c29fSJoe Thornber (unsigned long long) b); 5926513c29fSJoe Thornber return; 5936513c29fSJoe Thornber } 5946513c29fSJoe Thornber 5956513c29fSJoe Thornber dec_ablock_entries(info, ab); 5966513c29fSJoe Thornber unlock_ablock(info, block); 5976513c29fSJoe Thornber } 5986513c29fSJoe Thornber 5996513c29fSJoe Thornber dm_tm_dec(info->btree_info.tm, b); 6006513c29fSJoe Thornber } 6016513c29fSJoe Thornber 6026513c29fSJoe Thornber static int block_equal(void *context, const void *value1, const void *value2) 6036513c29fSJoe Thornber { 6046513c29fSJoe Thornber return !memcmp(value1, value2, sizeof(__le64)); 6056513c29fSJoe Thornber } 6066513c29fSJoe Thornber 6076513c29fSJoe Thornber /*----------------------------------------------------------------*/ 6086513c29fSJoe Thornber 6096513c29fSJoe Thornber void dm_array_info_init(struct dm_array_info *info, 6106513c29fSJoe Thornber struct dm_transaction_manager *tm, 6116513c29fSJoe Thornber struct dm_btree_value_type *vt) 6126513c29fSJoe Thornber { 6136513c29fSJoe Thornber struct dm_btree_value_type *bvt = &info->btree_info.value_type; 6146513c29fSJoe Thornber 6156513c29fSJoe Thornber memcpy(&info->value_type, vt, sizeof(info->value_type)); 6166513c29fSJoe Thornber info->btree_info.tm = tm; 6176513c29fSJoe Thornber info->btree_info.levels = 1; 6186513c29fSJoe Thornber 6196513c29fSJoe Thornber bvt->context = info; 6206513c29fSJoe Thornber bvt->size = sizeof(__le64); 6216513c29fSJoe Thornber bvt->inc = block_inc; 6226513c29fSJoe Thornber bvt->dec = block_dec; 6236513c29fSJoe Thornber bvt->equal = block_equal; 6246513c29fSJoe Thornber } 6256513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_info_init); 6266513c29fSJoe Thornber 6276513c29fSJoe Thornber int dm_array_empty(struct dm_array_info *info, dm_block_t *root) 6286513c29fSJoe Thornber { 6296513c29fSJoe Thornber return dm_btree_empty(&info->btree_info, root); 6306513c29fSJoe Thornber } 6316513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_empty); 6326513c29fSJoe Thornber 6336513c29fSJoe Thornber static int array_resize(struct dm_array_info *info, dm_block_t root, 6346513c29fSJoe Thornber uint32_t old_size, uint32_t new_size, 6356513c29fSJoe Thornber const void *value, dm_block_t *new_root) 6366513c29fSJoe Thornber { 6376513c29fSJoe Thornber int r; 6386513c29fSJoe Thornber struct resize resize; 6396513c29fSJoe Thornber 6406513c29fSJoe Thornber if (old_size == new_size) 6416513c29fSJoe Thornber return 0; 6426513c29fSJoe Thornber 6436513c29fSJoe Thornber resize.info = info; 6446513c29fSJoe Thornber resize.root = root; 6456513c29fSJoe Thornber resize.size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm)); 6466513c29fSJoe Thornber resize.max_entries = calc_max_entries(info->value_type.size, 6476513c29fSJoe Thornber resize.size_of_block); 6486513c29fSJoe Thornber 6496513c29fSJoe Thornber resize.old_nr_full_blocks = old_size / resize.max_entries; 6506513c29fSJoe Thornber resize.old_nr_entries_in_last_block = old_size % resize.max_entries; 6516513c29fSJoe Thornber resize.new_nr_full_blocks = new_size / resize.max_entries; 6526513c29fSJoe Thornber resize.new_nr_entries_in_last_block = new_size % resize.max_entries; 6536513c29fSJoe Thornber resize.value = value; 6546513c29fSJoe Thornber 6556513c29fSJoe Thornber r = ((new_size > old_size) ? grow : shrink)(&resize); 6566513c29fSJoe Thornber if (r) 6576513c29fSJoe Thornber return r; 6586513c29fSJoe Thornber 6596513c29fSJoe Thornber *new_root = resize.root; 6606513c29fSJoe Thornber return 0; 6616513c29fSJoe Thornber } 6626513c29fSJoe Thornber 6636513c29fSJoe Thornber int dm_array_resize(struct dm_array_info *info, dm_block_t root, 6646513c29fSJoe Thornber uint32_t old_size, uint32_t new_size, 6656513c29fSJoe Thornber const void *value, dm_block_t *new_root) 6666513c29fSJoe Thornber __dm_written_to_disk(value) 6676513c29fSJoe Thornber { 6686513c29fSJoe Thornber int r = array_resize(info, root, old_size, new_size, value, new_root); 6696513c29fSJoe Thornber __dm_unbless_for_disk(value); 6706513c29fSJoe Thornber return r; 6716513c29fSJoe Thornber } 6726513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_resize); 6736513c29fSJoe Thornber 6746513c29fSJoe Thornber int dm_array_del(struct dm_array_info *info, dm_block_t root) 6756513c29fSJoe Thornber { 6766513c29fSJoe Thornber return dm_btree_del(&info->btree_info, root); 6776513c29fSJoe Thornber } 6786513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_del); 6796513c29fSJoe Thornber 6806513c29fSJoe Thornber int dm_array_get_value(struct dm_array_info *info, dm_block_t root, 6816513c29fSJoe Thornber uint32_t index, void *value_le) 6826513c29fSJoe Thornber { 6836513c29fSJoe Thornber int r; 6846513c29fSJoe Thornber struct dm_block *block; 6856513c29fSJoe Thornber struct array_block *ab; 6866513c29fSJoe Thornber size_t size_of_block; 6876513c29fSJoe Thornber unsigned entry, max_entries; 6886513c29fSJoe Thornber 6896513c29fSJoe Thornber size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm)); 6906513c29fSJoe Thornber max_entries = calc_max_entries(info->value_type.size, size_of_block); 6916513c29fSJoe Thornber 6926513c29fSJoe Thornber r = lookup_ablock(info, root, index / max_entries, &block, &ab); 6936513c29fSJoe Thornber if (r) 6946513c29fSJoe Thornber return r; 6956513c29fSJoe Thornber 6966513c29fSJoe Thornber entry = index % max_entries; 6976513c29fSJoe Thornber if (entry >= le32_to_cpu(ab->nr_entries)) 6986513c29fSJoe Thornber r = -ENODATA; 6996513c29fSJoe Thornber else 7006513c29fSJoe Thornber memcpy(value_le, element_at(info, ab, entry), 7016513c29fSJoe Thornber info->value_type.size); 7026513c29fSJoe Thornber 7036513c29fSJoe Thornber unlock_ablock(info, block); 7046513c29fSJoe Thornber return r; 7056513c29fSJoe Thornber } 7066513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_get_value); 7076513c29fSJoe Thornber 7086513c29fSJoe Thornber static int array_set_value(struct dm_array_info *info, dm_block_t root, 7096513c29fSJoe Thornber uint32_t index, const void *value, dm_block_t *new_root) 7106513c29fSJoe Thornber { 7116513c29fSJoe Thornber int r; 7126513c29fSJoe Thornber struct dm_block *block; 7136513c29fSJoe Thornber struct array_block *ab; 7146513c29fSJoe Thornber size_t size_of_block; 7156513c29fSJoe Thornber unsigned max_entries; 7166513c29fSJoe Thornber unsigned entry; 7176513c29fSJoe Thornber void *old_value; 7186513c29fSJoe Thornber struct dm_btree_value_type *vt = &info->value_type; 7196513c29fSJoe Thornber 7206513c29fSJoe Thornber size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm)); 7216513c29fSJoe Thornber max_entries = calc_max_entries(info->value_type.size, size_of_block); 7226513c29fSJoe Thornber 7236513c29fSJoe Thornber r = shadow_ablock(info, &root, index / max_entries, &block, &ab); 7246513c29fSJoe Thornber if (r) 7256513c29fSJoe Thornber return r; 7266513c29fSJoe Thornber *new_root = root; 7276513c29fSJoe Thornber 7286513c29fSJoe Thornber entry = index % max_entries; 7296513c29fSJoe Thornber if (entry >= le32_to_cpu(ab->nr_entries)) { 7306513c29fSJoe Thornber r = -ENODATA; 7316513c29fSJoe Thornber goto out; 7326513c29fSJoe Thornber } 7336513c29fSJoe Thornber 7346513c29fSJoe Thornber old_value = element_at(info, ab, entry); 7356513c29fSJoe Thornber if (vt->dec && 7366513c29fSJoe Thornber (!vt->equal || !vt->equal(vt->context, old_value, value))) { 7376513c29fSJoe Thornber vt->dec(vt->context, old_value); 7386513c29fSJoe Thornber if (vt->inc) 7396513c29fSJoe Thornber vt->inc(vt->context, value); 7406513c29fSJoe Thornber } 7416513c29fSJoe Thornber 7426513c29fSJoe Thornber memcpy(old_value, value, info->value_type.size); 7436513c29fSJoe Thornber 7446513c29fSJoe Thornber out: 7456513c29fSJoe Thornber unlock_ablock(info, block); 7466513c29fSJoe Thornber return r; 7476513c29fSJoe Thornber } 7486513c29fSJoe Thornber 7496513c29fSJoe Thornber int dm_array_set_value(struct dm_array_info *info, dm_block_t root, 7506513c29fSJoe Thornber uint32_t index, const void *value, dm_block_t *new_root) 7516513c29fSJoe Thornber __dm_written_to_disk(value) 7526513c29fSJoe Thornber { 7536513c29fSJoe Thornber int r; 7546513c29fSJoe Thornber 7556513c29fSJoe Thornber r = array_set_value(info, root, index, value, new_root); 7566513c29fSJoe Thornber __dm_unbless_for_disk(value); 7576513c29fSJoe Thornber return r; 7586513c29fSJoe Thornber } 7596513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_set_value); 7606513c29fSJoe Thornber 7616513c29fSJoe Thornber struct walk_info { 7626513c29fSJoe Thornber struct dm_array_info *info; 7636513c29fSJoe Thornber int (*fn)(void *context, uint64_t key, void *leaf); 7646513c29fSJoe Thornber void *context; 7656513c29fSJoe Thornber }; 7666513c29fSJoe Thornber 7676513c29fSJoe Thornber static int walk_ablock(void *context, uint64_t *keys, void *leaf) 7686513c29fSJoe Thornber { 7696513c29fSJoe Thornber struct walk_info *wi = context; 7706513c29fSJoe Thornber 7716513c29fSJoe Thornber int r; 7726513c29fSJoe Thornber unsigned i; 7736513c29fSJoe Thornber __le64 block_le; 7746513c29fSJoe Thornber unsigned nr_entries, max_entries; 7756513c29fSJoe Thornber struct dm_block *block; 7766513c29fSJoe Thornber struct array_block *ab; 7776513c29fSJoe Thornber 7786513c29fSJoe Thornber memcpy(&block_le, leaf, sizeof(block_le)); 7796513c29fSJoe Thornber r = get_ablock(wi->info, le64_to_cpu(block_le), &block, &ab); 7806513c29fSJoe Thornber if (r) 7816513c29fSJoe Thornber return r; 7826513c29fSJoe Thornber 7836513c29fSJoe Thornber max_entries = le32_to_cpu(ab->max_entries); 7846513c29fSJoe Thornber nr_entries = le32_to_cpu(ab->nr_entries); 7856513c29fSJoe Thornber for (i = 0; i < nr_entries; i++) { 7866513c29fSJoe Thornber r = wi->fn(wi->context, keys[0] * max_entries + i, 7876513c29fSJoe Thornber element_at(wi->info, ab, i)); 7886513c29fSJoe Thornber 7896513c29fSJoe Thornber if (r) 7906513c29fSJoe Thornber break; 7916513c29fSJoe Thornber } 7926513c29fSJoe Thornber 7936513c29fSJoe Thornber unlock_ablock(wi->info, block); 7946513c29fSJoe Thornber return r; 7956513c29fSJoe Thornber } 7966513c29fSJoe Thornber 7976513c29fSJoe Thornber int dm_array_walk(struct dm_array_info *info, dm_block_t root, 7986513c29fSJoe Thornber int (*fn)(void *, uint64_t key, void *leaf), 7996513c29fSJoe Thornber void *context) 8006513c29fSJoe Thornber { 8016513c29fSJoe Thornber struct walk_info wi; 8026513c29fSJoe Thornber 8036513c29fSJoe Thornber wi.info = info; 8046513c29fSJoe Thornber wi.fn = fn; 8056513c29fSJoe Thornber wi.context = context; 8066513c29fSJoe Thornber 8076513c29fSJoe Thornber return dm_btree_walk(&info->btree_info, root, walk_ablock, &wi); 8086513c29fSJoe Thornber } 8096513c29fSJoe Thornber EXPORT_SYMBOL_GPL(dm_array_walk); 8106513c29fSJoe Thornber 8116513c29fSJoe Thornber /*----------------------------------------------------------------*/ 812