18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2011 Red Hat, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is released under the GPL. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "dm-space-map-common.h" 88c2ecf20Sopenharmony_ci#include "dm-transaction-manager.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/bitops.h> 118c2ecf20Sopenharmony_ci#include <linux/device-mapper.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define DM_MSG_PREFIX "space map common" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * Index validator. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci#define INDEX_CSUM_XOR 160478 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic void index_prepare_for_write(struct dm_block_validator *v, 238c2ecf20Sopenharmony_ci struct dm_block *b, 248c2ecf20Sopenharmony_ci size_t block_size) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct disk_metadata_index *mi_le = dm_block_data(b); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci mi_le->blocknr = cpu_to_le64(dm_block_location(b)); 298c2ecf20Sopenharmony_ci mi_le->csum = cpu_to_le32(dm_bm_checksum(&mi_le->padding, 308c2ecf20Sopenharmony_ci block_size - sizeof(__le32), 318c2ecf20Sopenharmony_ci INDEX_CSUM_XOR)); 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int index_check(struct dm_block_validator *v, 358c2ecf20Sopenharmony_ci struct dm_block *b, 368c2ecf20Sopenharmony_ci size_t block_size) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct disk_metadata_index *mi_le = dm_block_data(b); 398c2ecf20Sopenharmony_ci __le32 csum_disk; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (dm_block_location(b) != le64_to_cpu(mi_le->blocknr)) { 428c2ecf20Sopenharmony_ci DMERR_LIMIT("index_check failed: blocknr %llu != wanted %llu", 438c2ecf20Sopenharmony_ci le64_to_cpu(mi_le->blocknr), dm_block_location(b)); 448c2ecf20Sopenharmony_ci return -ENOTBLK; 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci csum_disk = cpu_to_le32(dm_bm_checksum(&mi_le->padding, 488c2ecf20Sopenharmony_ci block_size - sizeof(__le32), 498c2ecf20Sopenharmony_ci INDEX_CSUM_XOR)); 508c2ecf20Sopenharmony_ci if (csum_disk != mi_le->csum) { 518c2ecf20Sopenharmony_ci DMERR_LIMIT("index_check failed: csum %u != wanted %u", 528c2ecf20Sopenharmony_ci le32_to_cpu(csum_disk), le32_to_cpu(mi_le->csum)); 538c2ecf20Sopenharmony_ci return -EILSEQ; 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return 0; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic struct dm_block_validator index_validator = { 608c2ecf20Sopenharmony_ci .name = "index", 618c2ecf20Sopenharmony_ci .prepare_for_write = index_prepare_for_write, 628c2ecf20Sopenharmony_ci .check = index_check 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* 688c2ecf20Sopenharmony_ci * Bitmap validator 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ci#define BITMAP_CSUM_XOR 240779 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void dm_bitmap_prepare_for_write(struct dm_block_validator *v, 738c2ecf20Sopenharmony_ci struct dm_block *b, 748c2ecf20Sopenharmony_ci size_t block_size) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct disk_bitmap_header *disk_header = dm_block_data(b); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci disk_header->blocknr = cpu_to_le64(dm_block_location(b)); 798c2ecf20Sopenharmony_ci disk_header->csum = cpu_to_le32(dm_bm_checksum(&disk_header->not_used, 808c2ecf20Sopenharmony_ci block_size - sizeof(__le32), 818c2ecf20Sopenharmony_ci BITMAP_CSUM_XOR)); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int dm_bitmap_check(struct dm_block_validator *v, 858c2ecf20Sopenharmony_ci struct dm_block *b, 868c2ecf20Sopenharmony_ci size_t block_size) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct disk_bitmap_header *disk_header = dm_block_data(b); 898c2ecf20Sopenharmony_ci __le32 csum_disk; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (dm_block_location(b) != le64_to_cpu(disk_header->blocknr)) { 928c2ecf20Sopenharmony_ci DMERR_LIMIT("bitmap check failed: blocknr %llu != wanted %llu", 938c2ecf20Sopenharmony_ci le64_to_cpu(disk_header->blocknr), dm_block_location(b)); 948c2ecf20Sopenharmony_ci return -ENOTBLK; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci csum_disk = cpu_to_le32(dm_bm_checksum(&disk_header->not_used, 988c2ecf20Sopenharmony_ci block_size - sizeof(__le32), 998c2ecf20Sopenharmony_ci BITMAP_CSUM_XOR)); 1008c2ecf20Sopenharmony_ci if (csum_disk != disk_header->csum) { 1018c2ecf20Sopenharmony_ci DMERR_LIMIT("bitmap check failed: csum %u != wanted %u", 1028c2ecf20Sopenharmony_ci le32_to_cpu(csum_disk), le32_to_cpu(disk_header->csum)); 1038c2ecf20Sopenharmony_ci return -EILSEQ; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return 0; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic struct dm_block_validator dm_sm_bitmap_validator = { 1108c2ecf20Sopenharmony_ci .name = "sm_bitmap", 1118c2ecf20Sopenharmony_ci .prepare_for_write = dm_bitmap_prepare_for_write, 1128c2ecf20Sopenharmony_ci .check = dm_bitmap_check, 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#define ENTRIES_PER_WORD 32 1188c2ecf20Sopenharmony_ci#define ENTRIES_SHIFT 5 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void *dm_bitmap_data(struct dm_block *b) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci return dm_block_data(b) + sizeof(struct disk_bitmap_header); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#define WORD_MASK_HIGH 0xAAAAAAAAAAAAAAAAULL 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic unsigned dm_bitmap_word_used(void *addr, unsigned b) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci __le64 *words_le = addr; 1308c2ecf20Sopenharmony_ci __le64 *w_le = words_le + (b >> ENTRIES_SHIFT); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci uint64_t bits = le64_to_cpu(*w_le); 1338c2ecf20Sopenharmony_ci uint64_t mask = (bits + WORD_MASK_HIGH + 1) & WORD_MASK_HIGH; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return !(~bits & mask); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic unsigned sm_lookup_bitmap(void *addr, unsigned b) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci __le64 *words_le = addr; 1418c2ecf20Sopenharmony_ci __le64 *w_le = words_le + (b >> ENTRIES_SHIFT); 1428c2ecf20Sopenharmony_ci unsigned hi, lo; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci b = (b & (ENTRIES_PER_WORD - 1)) << 1; 1458c2ecf20Sopenharmony_ci hi = !!test_bit_le(b, (void *) w_le); 1468c2ecf20Sopenharmony_ci lo = !!test_bit_le(b + 1, (void *) w_le); 1478c2ecf20Sopenharmony_ci return (hi << 1) | lo; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic void sm_set_bitmap(void *addr, unsigned b, unsigned val) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci __le64 *words_le = addr; 1538c2ecf20Sopenharmony_ci __le64 *w_le = words_le + (b >> ENTRIES_SHIFT); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci b = (b & (ENTRIES_PER_WORD - 1)) << 1; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (val & 2) 1588c2ecf20Sopenharmony_ci __set_bit_le(b, (void *) w_le); 1598c2ecf20Sopenharmony_ci else 1608c2ecf20Sopenharmony_ci __clear_bit_le(b, (void *) w_le); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (val & 1) 1638c2ecf20Sopenharmony_ci __set_bit_le(b + 1, (void *) w_le); 1648c2ecf20Sopenharmony_ci else 1658c2ecf20Sopenharmony_ci __clear_bit_le(b + 1, (void *) w_le); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int sm_find_free(void *addr, unsigned begin, unsigned end, 1698c2ecf20Sopenharmony_ci unsigned *result) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci while (begin < end) { 1728c2ecf20Sopenharmony_ci if (!(begin & (ENTRIES_PER_WORD - 1)) && 1738c2ecf20Sopenharmony_ci dm_bitmap_word_used(addr, begin)) { 1748c2ecf20Sopenharmony_ci begin += ENTRIES_PER_WORD; 1758c2ecf20Sopenharmony_ci continue; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (!sm_lookup_bitmap(addr, begin)) { 1798c2ecf20Sopenharmony_ci *result = begin; 1808c2ecf20Sopenharmony_ci return 0; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci begin++; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return -ENOSPC; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic int sm_ll_init(struct ll_disk *ll, struct dm_transaction_manager *tm) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci memset(ll, 0, sizeof(struct ll_disk)); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci ll->tm = tm; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci ll->bitmap_info.tm = tm; 1988c2ecf20Sopenharmony_ci ll->bitmap_info.levels = 1; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* 2018c2ecf20Sopenharmony_ci * Because the new bitmap blocks are created via a shadow 2028c2ecf20Sopenharmony_ci * operation, the old entry has already had its reference count 2038c2ecf20Sopenharmony_ci * decremented and we don't need the btree to do any bookkeeping. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ci ll->bitmap_info.value_type.size = sizeof(struct disk_index_entry); 2068c2ecf20Sopenharmony_ci ll->bitmap_info.value_type.inc = NULL; 2078c2ecf20Sopenharmony_ci ll->bitmap_info.value_type.dec = NULL; 2088c2ecf20Sopenharmony_ci ll->bitmap_info.value_type.equal = NULL; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci ll->ref_count_info.tm = tm; 2118c2ecf20Sopenharmony_ci ll->ref_count_info.levels = 1; 2128c2ecf20Sopenharmony_ci ll->ref_count_info.value_type.size = sizeof(uint32_t); 2138c2ecf20Sopenharmony_ci ll->ref_count_info.value_type.inc = NULL; 2148c2ecf20Sopenharmony_ci ll->ref_count_info.value_type.dec = NULL; 2158c2ecf20Sopenharmony_ci ll->ref_count_info.value_type.equal = NULL; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci ll->block_size = dm_bm_block_size(dm_tm_get_bm(tm)); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (ll->block_size > (1 << 30)) { 2208c2ecf20Sopenharmony_ci DMERR("block size too big to hold bitmaps"); 2218c2ecf20Sopenharmony_ci return -EINVAL; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci ll->entries_per_block = (ll->block_size - sizeof(struct disk_bitmap_header)) * 2258c2ecf20Sopenharmony_ci ENTRIES_PER_BYTE; 2268c2ecf20Sopenharmony_ci ll->nr_blocks = 0; 2278c2ecf20Sopenharmony_ci ll->bitmap_root = 0; 2288c2ecf20Sopenharmony_ci ll->ref_count_root = 0; 2298c2ecf20Sopenharmony_ci ll->bitmap_index_changed = false; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return 0; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ciint sm_ll_extend(struct ll_disk *ll, dm_block_t extra_blocks) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci int r; 2378c2ecf20Sopenharmony_ci dm_block_t i, nr_blocks, nr_indexes; 2388c2ecf20Sopenharmony_ci unsigned old_blocks, blocks; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci nr_blocks = ll->nr_blocks + extra_blocks; 2418c2ecf20Sopenharmony_ci old_blocks = dm_sector_div_up(ll->nr_blocks, ll->entries_per_block); 2428c2ecf20Sopenharmony_ci blocks = dm_sector_div_up(nr_blocks, ll->entries_per_block); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci nr_indexes = dm_sector_div_up(nr_blocks, ll->entries_per_block); 2458c2ecf20Sopenharmony_ci if (nr_indexes > ll->max_entries(ll)) { 2468c2ecf20Sopenharmony_ci DMERR("space map too large"); 2478c2ecf20Sopenharmony_ci return -EINVAL; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* 2518c2ecf20Sopenharmony_ci * We need to set this before the dm_tm_new_block() call below. 2528c2ecf20Sopenharmony_ci */ 2538c2ecf20Sopenharmony_ci ll->nr_blocks = nr_blocks; 2548c2ecf20Sopenharmony_ci for (i = old_blocks; i < blocks; i++) { 2558c2ecf20Sopenharmony_ci struct dm_block *b; 2568c2ecf20Sopenharmony_ci struct disk_index_entry idx; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci r = dm_tm_new_block(ll->tm, &dm_sm_bitmap_validator, &b); 2598c2ecf20Sopenharmony_ci if (r < 0) 2608c2ecf20Sopenharmony_ci return r; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci idx.blocknr = cpu_to_le64(dm_block_location(b)); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci dm_tm_unlock(ll->tm, b); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci idx.nr_free = cpu_to_le32(ll->entries_per_block); 2678c2ecf20Sopenharmony_ci idx.none_free_before = 0; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci r = ll->save_ie(ll, i, &idx); 2708c2ecf20Sopenharmony_ci if (r < 0) 2718c2ecf20Sopenharmony_ci return r; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return 0; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ciint sm_ll_lookup_bitmap(struct ll_disk *ll, dm_block_t b, uint32_t *result) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci int r; 2808c2ecf20Sopenharmony_ci dm_block_t index = b; 2818c2ecf20Sopenharmony_ci struct disk_index_entry ie_disk; 2828c2ecf20Sopenharmony_ci struct dm_block *blk; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (b >= ll->nr_blocks) { 2858c2ecf20Sopenharmony_ci DMERR_LIMIT("metadata block out of bounds"); 2868c2ecf20Sopenharmony_ci return -EINVAL; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci b = do_div(index, ll->entries_per_block); 2908c2ecf20Sopenharmony_ci r = ll->load_ie(ll, index, &ie_disk); 2918c2ecf20Sopenharmony_ci if (r < 0) 2928c2ecf20Sopenharmony_ci return r; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci r = dm_tm_read_lock(ll->tm, le64_to_cpu(ie_disk.blocknr), 2958c2ecf20Sopenharmony_ci &dm_sm_bitmap_validator, &blk); 2968c2ecf20Sopenharmony_ci if (r < 0) 2978c2ecf20Sopenharmony_ci return r; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci *result = sm_lookup_bitmap(dm_bitmap_data(blk), b); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci dm_tm_unlock(ll->tm, blk); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return 0; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic int sm_ll_lookup_big_ref_count(struct ll_disk *ll, dm_block_t b, 3078c2ecf20Sopenharmony_ci uint32_t *result) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci __le32 le_rc; 3108c2ecf20Sopenharmony_ci int r; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci r = dm_btree_lookup(&ll->ref_count_info, ll->ref_count_root, &b, &le_rc); 3138c2ecf20Sopenharmony_ci if (r < 0) 3148c2ecf20Sopenharmony_ci return r; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci *result = le32_to_cpu(le_rc); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return r; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ciint sm_ll_lookup(struct ll_disk *ll, dm_block_t b, uint32_t *result) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci int r = sm_ll_lookup_bitmap(ll, b, result); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (r) 3268c2ecf20Sopenharmony_ci return r; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (*result != 3) 3298c2ecf20Sopenharmony_ci return r; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci return sm_ll_lookup_big_ref_count(ll, b, result); 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ciint sm_ll_find_free_block(struct ll_disk *ll, dm_block_t begin, 3358c2ecf20Sopenharmony_ci dm_block_t end, dm_block_t *result) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci int r; 3388c2ecf20Sopenharmony_ci struct disk_index_entry ie_disk; 3398c2ecf20Sopenharmony_ci dm_block_t i, index_begin = begin; 3408c2ecf20Sopenharmony_ci dm_block_t index_end = dm_sector_div_up(end, ll->entries_per_block); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* 3438c2ecf20Sopenharmony_ci * FIXME: Use shifts 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci begin = do_div(index_begin, ll->entries_per_block); 3468c2ecf20Sopenharmony_ci end = do_div(end, ll->entries_per_block); 3478c2ecf20Sopenharmony_ci if (end == 0) 3488c2ecf20Sopenharmony_ci end = ll->entries_per_block; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci for (i = index_begin; i < index_end; i++, begin = 0) { 3518c2ecf20Sopenharmony_ci struct dm_block *blk; 3528c2ecf20Sopenharmony_ci unsigned position; 3538c2ecf20Sopenharmony_ci uint32_t bit_end; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci r = ll->load_ie(ll, i, &ie_disk); 3568c2ecf20Sopenharmony_ci if (r < 0) 3578c2ecf20Sopenharmony_ci return r; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (le32_to_cpu(ie_disk.nr_free) == 0) 3608c2ecf20Sopenharmony_ci continue; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci r = dm_tm_read_lock(ll->tm, le64_to_cpu(ie_disk.blocknr), 3638c2ecf20Sopenharmony_ci &dm_sm_bitmap_validator, &blk); 3648c2ecf20Sopenharmony_ci if (r < 0) 3658c2ecf20Sopenharmony_ci return r; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci bit_end = (i == index_end - 1) ? end : ll->entries_per_block; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci r = sm_find_free(dm_bitmap_data(blk), 3708c2ecf20Sopenharmony_ci max_t(unsigned, begin, le32_to_cpu(ie_disk.none_free_before)), 3718c2ecf20Sopenharmony_ci bit_end, &position); 3728c2ecf20Sopenharmony_ci if (r == -ENOSPC) { 3738c2ecf20Sopenharmony_ci /* 3748c2ecf20Sopenharmony_ci * This might happen because we started searching 3758c2ecf20Sopenharmony_ci * part way through the bitmap. 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_ci dm_tm_unlock(ll->tm, blk); 3788c2ecf20Sopenharmony_ci continue; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci dm_tm_unlock(ll->tm, blk); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci *result = i * ll->entries_per_block + (dm_block_t) position; 3848c2ecf20Sopenharmony_ci return 0; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci return -ENOSPC; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ciint sm_ll_find_common_free_block(struct ll_disk *old_ll, struct ll_disk *new_ll, 3918c2ecf20Sopenharmony_ci dm_block_t begin, dm_block_t end, dm_block_t *b) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci int r; 3948c2ecf20Sopenharmony_ci uint32_t count; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci do { 3978c2ecf20Sopenharmony_ci r = sm_ll_find_free_block(new_ll, begin, new_ll->nr_blocks, b); 3988c2ecf20Sopenharmony_ci if (r) 3998c2ecf20Sopenharmony_ci break; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* double check this block wasn't used in the old transaction */ 4028c2ecf20Sopenharmony_ci if (*b >= old_ll->nr_blocks) 4038c2ecf20Sopenharmony_ci count = 0; 4048c2ecf20Sopenharmony_ci else { 4058c2ecf20Sopenharmony_ci r = sm_ll_lookup(old_ll, *b, &count); 4068c2ecf20Sopenharmony_ci if (r) 4078c2ecf20Sopenharmony_ci break; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (count) 4108c2ecf20Sopenharmony_ci begin = *b + 1; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci } while (count); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci return r; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic int sm_ll_mutate(struct ll_disk *ll, dm_block_t b, 4188c2ecf20Sopenharmony_ci int (*mutator)(void *context, uint32_t old, uint32_t *new), 4198c2ecf20Sopenharmony_ci void *context, enum allocation_event *ev) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci int r; 4228c2ecf20Sopenharmony_ci uint32_t bit, old, ref_count; 4238c2ecf20Sopenharmony_ci struct dm_block *nb; 4248c2ecf20Sopenharmony_ci dm_block_t index = b; 4258c2ecf20Sopenharmony_ci struct disk_index_entry ie_disk; 4268c2ecf20Sopenharmony_ci void *bm_le; 4278c2ecf20Sopenharmony_ci int inc; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci bit = do_div(index, ll->entries_per_block); 4308c2ecf20Sopenharmony_ci r = ll->load_ie(ll, index, &ie_disk); 4318c2ecf20Sopenharmony_ci if (r < 0) 4328c2ecf20Sopenharmony_ci return r; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci r = dm_tm_shadow_block(ll->tm, le64_to_cpu(ie_disk.blocknr), 4358c2ecf20Sopenharmony_ci &dm_sm_bitmap_validator, &nb, &inc); 4368c2ecf20Sopenharmony_ci if (r < 0) { 4378c2ecf20Sopenharmony_ci DMERR("dm_tm_shadow_block() failed"); 4388c2ecf20Sopenharmony_ci return r; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci ie_disk.blocknr = cpu_to_le64(dm_block_location(nb)); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci bm_le = dm_bitmap_data(nb); 4438c2ecf20Sopenharmony_ci old = sm_lookup_bitmap(bm_le, bit); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (old > 2) { 4468c2ecf20Sopenharmony_ci r = sm_ll_lookup_big_ref_count(ll, b, &old); 4478c2ecf20Sopenharmony_ci if (r < 0) { 4488c2ecf20Sopenharmony_ci dm_tm_unlock(ll->tm, nb); 4498c2ecf20Sopenharmony_ci return r; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci r = mutator(context, old, &ref_count); 4548c2ecf20Sopenharmony_ci if (r) { 4558c2ecf20Sopenharmony_ci dm_tm_unlock(ll->tm, nb); 4568c2ecf20Sopenharmony_ci return r; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (ref_count <= 2) { 4608c2ecf20Sopenharmony_ci sm_set_bitmap(bm_le, bit, ref_count); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci dm_tm_unlock(ll->tm, nb); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (old > 2) { 4658c2ecf20Sopenharmony_ci r = dm_btree_remove(&ll->ref_count_info, 4668c2ecf20Sopenharmony_ci ll->ref_count_root, 4678c2ecf20Sopenharmony_ci &b, &ll->ref_count_root); 4688c2ecf20Sopenharmony_ci if (r) 4698c2ecf20Sopenharmony_ci return r; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci } else { 4738c2ecf20Sopenharmony_ci __le32 le_rc = cpu_to_le32(ref_count); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci sm_set_bitmap(bm_le, bit, 3); 4768c2ecf20Sopenharmony_ci dm_tm_unlock(ll->tm, nb); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci __dm_bless_for_disk(&le_rc); 4798c2ecf20Sopenharmony_ci r = dm_btree_insert(&ll->ref_count_info, ll->ref_count_root, 4808c2ecf20Sopenharmony_ci &b, &le_rc, &ll->ref_count_root); 4818c2ecf20Sopenharmony_ci if (r < 0) { 4828c2ecf20Sopenharmony_ci DMERR("ref count insert failed"); 4838c2ecf20Sopenharmony_ci return r; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (ref_count && !old) { 4888c2ecf20Sopenharmony_ci *ev = SM_ALLOC; 4898c2ecf20Sopenharmony_ci ll->nr_allocated++; 4908c2ecf20Sopenharmony_ci le32_add_cpu(&ie_disk.nr_free, -1); 4918c2ecf20Sopenharmony_ci if (le32_to_cpu(ie_disk.none_free_before) == bit) 4928c2ecf20Sopenharmony_ci ie_disk.none_free_before = cpu_to_le32(bit + 1); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci } else if (old && !ref_count) { 4958c2ecf20Sopenharmony_ci *ev = SM_FREE; 4968c2ecf20Sopenharmony_ci ll->nr_allocated--; 4978c2ecf20Sopenharmony_ci le32_add_cpu(&ie_disk.nr_free, 1); 4988c2ecf20Sopenharmony_ci ie_disk.none_free_before = cpu_to_le32(min(le32_to_cpu(ie_disk.none_free_before), bit)); 4998c2ecf20Sopenharmony_ci } else 5008c2ecf20Sopenharmony_ci *ev = SM_NONE; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci return ll->save_ie(ll, index, &ie_disk); 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic int set_ref_count(void *context, uint32_t old, uint32_t *new) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci *new = *((uint32_t *) context); 5088c2ecf20Sopenharmony_ci return 0; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ciint sm_ll_insert(struct ll_disk *ll, dm_block_t b, 5128c2ecf20Sopenharmony_ci uint32_t ref_count, enum allocation_event *ev) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci return sm_ll_mutate(ll, b, set_ref_count, &ref_count, ev); 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic int inc_ref_count(void *context, uint32_t old, uint32_t *new) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci *new = old + 1; 5208c2ecf20Sopenharmony_ci return 0; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ciint sm_ll_inc(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci return sm_ll_mutate(ll, b, inc_ref_count, NULL, ev); 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic int dec_ref_count(void *context, uint32_t old, uint32_t *new) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci if (!old) { 5318c2ecf20Sopenharmony_ci DMERR_LIMIT("unable to decrement a reference count below 0"); 5328c2ecf20Sopenharmony_ci return -EINVAL; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci *new = old - 1; 5368c2ecf20Sopenharmony_ci return 0; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ciint sm_ll_dec(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci return sm_ll_mutate(ll, b, dec_ref_count, NULL, ev); 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ciint sm_ll_commit(struct ll_disk *ll) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci int r = 0; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (ll->bitmap_index_changed) { 5498c2ecf20Sopenharmony_ci r = ll->commit(ll); 5508c2ecf20Sopenharmony_ci if (!r) 5518c2ecf20Sopenharmony_ci ll->bitmap_index_changed = false; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci return r; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic int metadata_ll_load_ie(struct ll_disk *ll, dm_block_t index, 5608c2ecf20Sopenharmony_ci struct disk_index_entry *ie) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci memcpy(ie, ll->mi_le.index + index, sizeof(*ie)); 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic int metadata_ll_save_ie(struct ll_disk *ll, dm_block_t index, 5678c2ecf20Sopenharmony_ci struct disk_index_entry *ie) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci ll->bitmap_index_changed = true; 5708c2ecf20Sopenharmony_ci memcpy(ll->mi_le.index + index, ie, sizeof(*ie)); 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic int metadata_ll_init_index(struct ll_disk *ll) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci int r; 5778c2ecf20Sopenharmony_ci struct dm_block *b; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci r = dm_tm_new_block(ll->tm, &index_validator, &b); 5808c2ecf20Sopenharmony_ci if (r < 0) 5818c2ecf20Sopenharmony_ci return r; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci ll->bitmap_root = dm_block_location(b); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci dm_tm_unlock(ll->tm, b); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci return 0; 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic int metadata_ll_open(struct ll_disk *ll) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci int r; 5938c2ecf20Sopenharmony_ci struct dm_block *block; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci r = dm_tm_read_lock(ll->tm, ll->bitmap_root, 5968c2ecf20Sopenharmony_ci &index_validator, &block); 5978c2ecf20Sopenharmony_ci if (r) 5988c2ecf20Sopenharmony_ci return r; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci memcpy(&ll->mi_le, dm_block_data(block), sizeof(ll->mi_le)); 6018c2ecf20Sopenharmony_ci dm_tm_unlock(ll->tm, block); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci return 0; 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic dm_block_t metadata_ll_max_entries(struct ll_disk *ll) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci return MAX_METADATA_BITMAPS; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic int metadata_ll_commit(struct ll_disk *ll) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci int r, inc; 6148c2ecf20Sopenharmony_ci struct dm_block *b; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci r = dm_tm_shadow_block(ll->tm, ll->bitmap_root, &index_validator, &b, &inc); 6178c2ecf20Sopenharmony_ci if (r) 6188c2ecf20Sopenharmony_ci return r; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci memcpy(dm_block_data(b), &ll->mi_le, sizeof(ll->mi_le)); 6218c2ecf20Sopenharmony_ci ll->bitmap_root = dm_block_location(b); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci dm_tm_unlock(ll->tm, b); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci return 0; 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ciint sm_ll_new_metadata(struct ll_disk *ll, struct dm_transaction_manager *tm) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci int r; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci r = sm_ll_init(ll, tm); 6338c2ecf20Sopenharmony_ci if (r < 0) 6348c2ecf20Sopenharmony_ci return r; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci ll->load_ie = metadata_ll_load_ie; 6378c2ecf20Sopenharmony_ci ll->save_ie = metadata_ll_save_ie; 6388c2ecf20Sopenharmony_ci ll->init_index = metadata_ll_init_index; 6398c2ecf20Sopenharmony_ci ll->open_index = metadata_ll_open; 6408c2ecf20Sopenharmony_ci ll->max_entries = metadata_ll_max_entries; 6418c2ecf20Sopenharmony_ci ll->commit = metadata_ll_commit; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci ll->nr_blocks = 0; 6448c2ecf20Sopenharmony_ci ll->nr_allocated = 0; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci r = ll->init_index(ll); 6478c2ecf20Sopenharmony_ci if (r < 0) 6488c2ecf20Sopenharmony_ci return r; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci r = dm_btree_empty(&ll->ref_count_info, &ll->ref_count_root); 6518c2ecf20Sopenharmony_ci if (r < 0) 6528c2ecf20Sopenharmony_ci return r; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci return 0; 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ciint sm_ll_open_metadata(struct ll_disk *ll, struct dm_transaction_manager *tm, 6588c2ecf20Sopenharmony_ci void *root_le, size_t len) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci int r; 6618c2ecf20Sopenharmony_ci struct disk_sm_root smr; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (len < sizeof(struct disk_sm_root)) { 6648c2ecf20Sopenharmony_ci DMERR("sm_metadata root too small"); 6658c2ecf20Sopenharmony_ci return -ENOMEM; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci /* 6698c2ecf20Sopenharmony_ci * We don't know the alignment of the root_le buffer, so need to 6708c2ecf20Sopenharmony_ci * copy into a new structure. 6718c2ecf20Sopenharmony_ci */ 6728c2ecf20Sopenharmony_ci memcpy(&smr, root_le, sizeof(smr)); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci r = sm_ll_init(ll, tm); 6758c2ecf20Sopenharmony_ci if (r < 0) 6768c2ecf20Sopenharmony_ci return r; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci ll->load_ie = metadata_ll_load_ie; 6798c2ecf20Sopenharmony_ci ll->save_ie = metadata_ll_save_ie; 6808c2ecf20Sopenharmony_ci ll->init_index = metadata_ll_init_index; 6818c2ecf20Sopenharmony_ci ll->open_index = metadata_ll_open; 6828c2ecf20Sopenharmony_ci ll->max_entries = metadata_ll_max_entries; 6838c2ecf20Sopenharmony_ci ll->commit = metadata_ll_commit; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci ll->nr_blocks = le64_to_cpu(smr.nr_blocks); 6868c2ecf20Sopenharmony_ci ll->nr_allocated = le64_to_cpu(smr.nr_allocated); 6878c2ecf20Sopenharmony_ci ll->bitmap_root = le64_to_cpu(smr.bitmap_root); 6888c2ecf20Sopenharmony_ci ll->ref_count_root = le64_to_cpu(smr.ref_count_root); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci return ll->open_index(ll); 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_cistatic int disk_ll_load_ie(struct ll_disk *ll, dm_block_t index, 6968c2ecf20Sopenharmony_ci struct disk_index_entry *ie) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci return dm_btree_lookup(&ll->bitmap_info, ll->bitmap_root, &index, ie); 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic int disk_ll_save_ie(struct ll_disk *ll, dm_block_t index, 7028c2ecf20Sopenharmony_ci struct disk_index_entry *ie) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci __dm_bless_for_disk(ie); 7058c2ecf20Sopenharmony_ci return dm_btree_insert(&ll->bitmap_info, ll->bitmap_root, 7068c2ecf20Sopenharmony_ci &index, ie, &ll->bitmap_root); 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cistatic int disk_ll_init_index(struct ll_disk *ll) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci return dm_btree_empty(&ll->bitmap_info, &ll->bitmap_root); 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic int disk_ll_open(struct ll_disk *ll) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci /* nothing to do */ 7178c2ecf20Sopenharmony_ci return 0; 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic dm_block_t disk_ll_max_entries(struct ll_disk *ll) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci return -1ULL; 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic int disk_ll_commit(struct ll_disk *ll) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci return 0; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ciint sm_ll_new_disk(struct ll_disk *ll, struct dm_transaction_manager *tm) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci int r; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci r = sm_ll_init(ll, tm); 7358c2ecf20Sopenharmony_ci if (r < 0) 7368c2ecf20Sopenharmony_ci return r; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci ll->load_ie = disk_ll_load_ie; 7398c2ecf20Sopenharmony_ci ll->save_ie = disk_ll_save_ie; 7408c2ecf20Sopenharmony_ci ll->init_index = disk_ll_init_index; 7418c2ecf20Sopenharmony_ci ll->open_index = disk_ll_open; 7428c2ecf20Sopenharmony_ci ll->max_entries = disk_ll_max_entries; 7438c2ecf20Sopenharmony_ci ll->commit = disk_ll_commit; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci ll->nr_blocks = 0; 7468c2ecf20Sopenharmony_ci ll->nr_allocated = 0; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci r = ll->init_index(ll); 7498c2ecf20Sopenharmony_ci if (r < 0) 7508c2ecf20Sopenharmony_ci return r; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci r = dm_btree_empty(&ll->ref_count_info, &ll->ref_count_root); 7538c2ecf20Sopenharmony_ci if (r < 0) 7548c2ecf20Sopenharmony_ci return r; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci return 0; 7578c2ecf20Sopenharmony_ci} 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ciint sm_ll_open_disk(struct ll_disk *ll, struct dm_transaction_manager *tm, 7608c2ecf20Sopenharmony_ci void *root_le, size_t len) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci int r; 7638c2ecf20Sopenharmony_ci struct disk_sm_root *smr = root_le; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci if (len < sizeof(struct disk_sm_root)) { 7668c2ecf20Sopenharmony_ci DMERR("sm_metadata root too small"); 7678c2ecf20Sopenharmony_ci return -ENOMEM; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci r = sm_ll_init(ll, tm); 7718c2ecf20Sopenharmony_ci if (r < 0) 7728c2ecf20Sopenharmony_ci return r; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci ll->load_ie = disk_ll_load_ie; 7758c2ecf20Sopenharmony_ci ll->save_ie = disk_ll_save_ie; 7768c2ecf20Sopenharmony_ci ll->init_index = disk_ll_init_index; 7778c2ecf20Sopenharmony_ci ll->open_index = disk_ll_open; 7788c2ecf20Sopenharmony_ci ll->max_entries = disk_ll_max_entries; 7798c2ecf20Sopenharmony_ci ll->commit = disk_ll_commit; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci ll->nr_blocks = le64_to_cpu(smr->nr_blocks); 7828c2ecf20Sopenharmony_ci ll->nr_allocated = le64_to_cpu(smr->nr_allocated); 7838c2ecf20Sopenharmony_ci ll->bitmap_root = le64_to_cpu(smr->bitmap_root); 7848c2ecf20Sopenharmony_ci ll->ref_count_root = le64_to_cpu(smr->ref_count_root); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci return ll->open_index(ll); 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 790