18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2019 Arrikto, Inc. All Rights Reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/mm.h> 78c2ecf20Sopenharmony_ci#include <linux/err.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/rwsem.h> 108c2ecf20Sopenharmony_ci#include <linux/bitops.h> 118c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 128c2ecf20Sopenharmony_ci#include <linux/device-mapper.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "persistent-data/dm-bitset.h" 158c2ecf20Sopenharmony_ci#include "persistent-data/dm-space-map.h" 168c2ecf20Sopenharmony_ci#include "persistent-data/dm-block-manager.h" 178c2ecf20Sopenharmony_ci#include "persistent-data/dm-transaction-manager.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "dm-clone-metadata.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define DM_MSG_PREFIX "clone metadata" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define SUPERBLOCK_LOCATION 0 248c2ecf20Sopenharmony_ci#define SUPERBLOCK_MAGIC 0x8af27f64 258c2ecf20Sopenharmony_ci#define SUPERBLOCK_CSUM_XOR 257649492 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define DM_CLONE_MAX_CONCURRENT_LOCKS 5 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define UUID_LEN 16 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* Min and max dm-clone metadata versions supported */ 328c2ecf20Sopenharmony_ci#define DM_CLONE_MIN_METADATA_VERSION 1 338c2ecf20Sopenharmony_ci#define DM_CLONE_MAX_METADATA_VERSION 1 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * On-disk metadata layout 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_cistruct superblock_disk { 398c2ecf20Sopenharmony_ci __le32 csum; 408c2ecf20Sopenharmony_ci __le32 flags; 418c2ecf20Sopenharmony_ci __le64 blocknr; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci __u8 uuid[UUID_LEN]; 448c2ecf20Sopenharmony_ci __le64 magic; 458c2ecf20Sopenharmony_ci __le32 version; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE]; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci __le64 region_size; 508c2ecf20Sopenharmony_ci __le64 target_size; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci __le64 bitset_root; 538c2ecf20Sopenharmony_ci} __packed; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* 568c2ecf20Sopenharmony_ci * Region and Dirty bitmaps. 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * dm-clone logically splits the source and destination devices in regions of 598c2ecf20Sopenharmony_ci * fixed size. The destination device's regions are gradually hydrated, i.e., 608c2ecf20Sopenharmony_ci * we copy (clone) the source's regions to the destination device. Eventually, 618c2ecf20Sopenharmony_ci * all regions will get hydrated and all I/O will be served from the 628c2ecf20Sopenharmony_ci * destination device. 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * We maintain an on-disk bitmap which tracks the state of each of the 658c2ecf20Sopenharmony_ci * destination device's regions, i.e., whether they are hydrated or not. 668c2ecf20Sopenharmony_ci * 678c2ecf20Sopenharmony_ci * To save constantly doing look ups on disk we keep an in core copy of the 688c2ecf20Sopenharmony_ci * on-disk bitmap, the region_map. 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci * In order to track which regions are hydrated during a metadata transaction, 718c2ecf20Sopenharmony_ci * we use a second set of bitmaps, the dmap (dirty bitmap), which includes two 728c2ecf20Sopenharmony_ci * bitmaps, namely dirty_regions and dirty_words. The dirty_regions bitmap 738c2ecf20Sopenharmony_ci * tracks the regions that got hydrated during the current metadata 748c2ecf20Sopenharmony_ci * transaction. The dirty_words bitmap tracks the dirty words, i.e. longs, of 758c2ecf20Sopenharmony_ci * the dirty_regions bitmap. 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci * This allows us to precisely track the regions that were hydrated during the 788c2ecf20Sopenharmony_ci * current metadata transaction and update the metadata accordingly, when we 798c2ecf20Sopenharmony_ci * commit the current transaction. This is important because dm-clone should 808c2ecf20Sopenharmony_ci * only commit the metadata of regions that were properly flushed to the 818c2ecf20Sopenharmony_ci * destination device beforehand. Otherwise, in case of a crash, we could end 828c2ecf20Sopenharmony_ci * up with a corrupted dm-clone device. 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * When a region finishes hydrating dm-clone calls 858c2ecf20Sopenharmony_ci * dm_clone_set_region_hydrated(), or for discard requests 868c2ecf20Sopenharmony_ci * dm_clone_cond_set_range(), which sets the corresponding bits in region_map 878c2ecf20Sopenharmony_ci * and dmap. 888c2ecf20Sopenharmony_ci * 898c2ecf20Sopenharmony_ci * During a metadata commit we scan dmap->dirty_words and dmap->dirty_regions 908c2ecf20Sopenharmony_ci * and update the on-disk metadata accordingly. Thus, we don't have to flush to 918c2ecf20Sopenharmony_ci * disk the whole region_map. We can just flush the dirty region_map bits. 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * We use the helper dmap->dirty_words bitmap, which is smaller than the 948c2ecf20Sopenharmony_ci * original region_map, to reduce the amount of memory accesses during a 958c2ecf20Sopenharmony_ci * metadata commit. Moreover, as dm-bitset also accesses the on-disk bitmap in 968c2ecf20Sopenharmony_ci * 64-bit word granularity, the dirty_words bitmap helps us avoid useless disk 978c2ecf20Sopenharmony_ci * accesses. 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * We could update directly the on-disk bitmap, when dm-clone calls either 1008c2ecf20Sopenharmony_ci * dm_clone_set_region_hydrated() or dm_clone_cond_set_range(), buts this 1018c2ecf20Sopenharmony_ci * inserts significant metadata I/O overhead in dm-clone's I/O path. Also, as 1028c2ecf20Sopenharmony_ci * these two functions don't block, we can call them in interrupt context, 1038c2ecf20Sopenharmony_ci * e.g., in a hooked overwrite bio's completion routine, and further reduce the 1048c2ecf20Sopenharmony_ci * I/O completion latency. 1058c2ecf20Sopenharmony_ci * 1068c2ecf20Sopenharmony_ci * We maintain two dirty bitmap sets. During a metadata commit we atomically 1078c2ecf20Sopenharmony_ci * swap the currently used dmap with the unused one. This allows the metadata 1088c2ecf20Sopenharmony_ci * update functions to run concurrently with an ongoing commit. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_cistruct dirty_map { 1118c2ecf20Sopenharmony_ci unsigned long *dirty_words; 1128c2ecf20Sopenharmony_ci unsigned long *dirty_regions; 1138c2ecf20Sopenharmony_ci unsigned int changed; 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistruct dm_clone_metadata { 1178c2ecf20Sopenharmony_ci /* The metadata block device */ 1188c2ecf20Sopenharmony_ci struct block_device *bdev; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci sector_t target_size; 1218c2ecf20Sopenharmony_ci sector_t region_size; 1228c2ecf20Sopenharmony_ci unsigned long nr_regions; 1238c2ecf20Sopenharmony_ci unsigned long nr_words; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* Spinlock protecting the region and dirty bitmaps. */ 1268c2ecf20Sopenharmony_ci spinlock_t bitmap_lock; 1278c2ecf20Sopenharmony_ci struct dirty_map dmap[2]; 1288c2ecf20Sopenharmony_ci struct dirty_map *current_dmap; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* Protected by lock */ 1318c2ecf20Sopenharmony_ci struct dirty_map *committing_dmap; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* 1348c2ecf20Sopenharmony_ci * In core copy of the on-disk bitmap to save constantly doing look ups 1358c2ecf20Sopenharmony_ci * on disk. 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_ci unsigned long *region_map; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* Protected by bitmap_lock */ 1408c2ecf20Sopenharmony_ci unsigned int read_only; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci struct dm_block_manager *bm; 1438c2ecf20Sopenharmony_ci struct dm_space_map *sm; 1448c2ecf20Sopenharmony_ci struct dm_transaction_manager *tm; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci struct rw_semaphore lock; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci struct dm_disk_bitset bitset_info; 1498c2ecf20Sopenharmony_ci dm_block_t bitset_root; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* 1528c2ecf20Sopenharmony_ci * Reading the space map root can fail, so we read it into this 1538c2ecf20Sopenharmony_ci * buffer before the superblock is locked and updated. 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_ci __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE]; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci bool hydration_done:1; 1588c2ecf20Sopenharmony_ci bool fail_io:1; 1598c2ecf20Sopenharmony_ci}; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------------*/ 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/* 1648c2ecf20Sopenharmony_ci * Superblock validation. 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_cistatic void sb_prepare_for_write(struct dm_block_validator *v, 1678c2ecf20Sopenharmony_ci struct dm_block *b, size_t sb_block_size) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct superblock_disk *sb; 1708c2ecf20Sopenharmony_ci u32 csum; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci sb = dm_block_data(b); 1738c2ecf20Sopenharmony_ci sb->blocknr = cpu_to_le64(dm_block_location(b)); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci csum = dm_bm_checksum(&sb->flags, sb_block_size - sizeof(__le32), 1768c2ecf20Sopenharmony_ci SUPERBLOCK_CSUM_XOR); 1778c2ecf20Sopenharmony_ci sb->csum = cpu_to_le32(csum); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic int sb_check(struct dm_block_validator *v, struct dm_block *b, 1818c2ecf20Sopenharmony_ci size_t sb_block_size) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct superblock_disk *sb; 1848c2ecf20Sopenharmony_ci u32 csum, metadata_version; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci sb = dm_block_data(b); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (dm_block_location(b) != le64_to_cpu(sb->blocknr)) { 1898c2ecf20Sopenharmony_ci DMERR("Superblock check failed: blocknr %llu, expected %llu", 1908c2ecf20Sopenharmony_ci le64_to_cpu(sb->blocknr), 1918c2ecf20Sopenharmony_ci (unsigned long long)dm_block_location(b)); 1928c2ecf20Sopenharmony_ci return -ENOTBLK; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (le64_to_cpu(sb->magic) != SUPERBLOCK_MAGIC) { 1968c2ecf20Sopenharmony_ci DMERR("Superblock check failed: magic %llu, expected %llu", 1978c2ecf20Sopenharmony_ci le64_to_cpu(sb->magic), 1988c2ecf20Sopenharmony_ci (unsigned long long)SUPERBLOCK_MAGIC); 1998c2ecf20Sopenharmony_ci return -EILSEQ; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci csum = dm_bm_checksum(&sb->flags, sb_block_size - sizeof(__le32), 2038c2ecf20Sopenharmony_ci SUPERBLOCK_CSUM_XOR); 2048c2ecf20Sopenharmony_ci if (sb->csum != cpu_to_le32(csum)) { 2058c2ecf20Sopenharmony_ci DMERR("Superblock check failed: checksum %u, expected %u", 2068c2ecf20Sopenharmony_ci csum, le32_to_cpu(sb->csum)); 2078c2ecf20Sopenharmony_ci return -EILSEQ; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* Check metadata version */ 2118c2ecf20Sopenharmony_ci metadata_version = le32_to_cpu(sb->version); 2128c2ecf20Sopenharmony_ci if (metadata_version < DM_CLONE_MIN_METADATA_VERSION || 2138c2ecf20Sopenharmony_ci metadata_version > DM_CLONE_MAX_METADATA_VERSION) { 2148c2ecf20Sopenharmony_ci DMERR("Clone metadata version %u found, but only versions between %u and %u supported.", 2158c2ecf20Sopenharmony_ci metadata_version, DM_CLONE_MIN_METADATA_VERSION, 2168c2ecf20Sopenharmony_ci DM_CLONE_MAX_METADATA_VERSION); 2178c2ecf20Sopenharmony_ci return -EINVAL; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic struct dm_block_validator sb_validator = { 2248c2ecf20Sopenharmony_ci .name = "superblock", 2258c2ecf20Sopenharmony_ci .prepare_for_write = sb_prepare_for_write, 2268c2ecf20Sopenharmony_ci .check = sb_check 2278c2ecf20Sopenharmony_ci}; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci/* 2308c2ecf20Sopenharmony_ci * Check if the superblock is formatted or not. We consider the superblock to 2318c2ecf20Sopenharmony_ci * be formatted in case we find non-zero bytes in it. 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_cistatic int __superblock_all_zeroes(struct dm_block_manager *bm, bool *formatted) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci int r; 2368c2ecf20Sopenharmony_ci unsigned int i, nr_words; 2378c2ecf20Sopenharmony_ci struct dm_block *sblock; 2388c2ecf20Sopenharmony_ci __le64 *data_le, zero = cpu_to_le64(0); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* 2418c2ecf20Sopenharmony_ci * We don't use a validator here because the superblock could be all 2428c2ecf20Sopenharmony_ci * zeroes. 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_ci r = dm_bm_read_lock(bm, SUPERBLOCK_LOCATION, NULL, &sblock); 2458c2ecf20Sopenharmony_ci if (r) { 2468c2ecf20Sopenharmony_ci DMERR("Failed to read_lock superblock"); 2478c2ecf20Sopenharmony_ci return r; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci data_le = dm_block_data(sblock); 2518c2ecf20Sopenharmony_ci *formatted = false; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* This assumes that the block size is a multiple of 8 bytes */ 2548c2ecf20Sopenharmony_ci BUG_ON(dm_bm_block_size(bm) % sizeof(__le64)); 2558c2ecf20Sopenharmony_ci nr_words = dm_bm_block_size(bm) / sizeof(__le64); 2568c2ecf20Sopenharmony_ci for (i = 0; i < nr_words; i++) { 2578c2ecf20Sopenharmony_ci if (data_le[i] != zero) { 2588c2ecf20Sopenharmony_ci *formatted = true; 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci dm_bm_unlock(sblock); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci return 0; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------------*/ 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci/* 2718c2ecf20Sopenharmony_ci * Low-level metadata handling. 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_cistatic inline int superblock_read_lock(struct dm_clone_metadata *cmd, 2748c2ecf20Sopenharmony_ci struct dm_block **sblock) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci return dm_bm_read_lock(cmd->bm, SUPERBLOCK_LOCATION, &sb_validator, sblock); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic inline int superblock_write_lock(struct dm_clone_metadata *cmd, 2808c2ecf20Sopenharmony_ci struct dm_block **sblock) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci return dm_bm_write_lock(cmd->bm, SUPERBLOCK_LOCATION, &sb_validator, sblock); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic inline int superblock_write_lock_zero(struct dm_clone_metadata *cmd, 2868c2ecf20Sopenharmony_ci struct dm_block **sblock) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci return dm_bm_write_lock_zero(cmd->bm, SUPERBLOCK_LOCATION, &sb_validator, sblock); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic int __copy_sm_root(struct dm_clone_metadata *cmd) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci int r; 2948c2ecf20Sopenharmony_ci size_t root_size; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci r = dm_sm_root_size(cmd->sm, &root_size); 2978c2ecf20Sopenharmony_ci if (r) 2988c2ecf20Sopenharmony_ci return r; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return dm_sm_copy_root(cmd->sm, &cmd->metadata_space_map_root, root_size); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci/* Save dm-clone metadata in superblock */ 3048c2ecf20Sopenharmony_cistatic void __prepare_superblock(struct dm_clone_metadata *cmd, 3058c2ecf20Sopenharmony_ci struct superblock_disk *sb) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci sb->flags = cpu_to_le32(0UL); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* FIXME: UUID is currently unused */ 3108c2ecf20Sopenharmony_ci memset(sb->uuid, 0, sizeof(sb->uuid)); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci sb->magic = cpu_to_le64(SUPERBLOCK_MAGIC); 3138c2ecf20Sopenharmony_ci sb->version = cpu_to_le32(DM_CLONE_MAX_METADATA_VERSION); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* Save the metadata space_map root */ 3168c2ecf20Sopenharmony_ci memcpy(&sb->metadata_space_map_root, &cmd->metadata_space_map_root, 3178c2ecf20Sopenharmony_ci sizeof(cmd->metadata_space_map_root)); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci sb->region_size = cpu_to_le64(cmd->region_size); 3208c2ecf20Sopenharmony_ci sb->target_size = cpu_to_le64(cmd->target_size); 3218c2ecf20Sopenharmony_ci sb->bitset_root = cpu_to_le64(cmd->bitset_root); 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic int __open_metadata(struct dm_clone_metadata *cmd) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci int r; 3278c2ecf20Sopenharmony_ci struct dm_block *sblock; 3288c2ecf20Sopenharmony_ci struct superblock_disk *sb; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci r = superblock_read_lock(cmd, &sblock); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (r) { 3338c2ecf20Sopenharmony_ci DMERR("Failed to read_lock superblock"); 3348c2ecf20Sopenharmony_ci return r; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci sb = dm_block_data(sblock); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* Verify that target_size and region_size haven't changed. */ 3408c2ecf20Sopenharmony_ci if (cmd->region_size != le64_to_cpu(sb->region_size) || 3418c2ecf20Sopenharmony_ci cmd->target_size != le64_to_cpu(sb->target_size)) { 3428c2ecf20Sopenharmony_ci DMERR("Region and/or target size don't match the ones in metadata"); 3438c2ecf20Sopenharmony_ci r = -EINVAL; 3448c2ecf20Sopenharmony_ci goto out_with_lock; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci r = dm_tm_open_with_sm(cmd->bm, SUPERBLOCK_LOCATION, 3488c2ecf20Sopenharmony_ci sb->metadata_space_map_root, 3498c2ecf20Sopenharmony_ci sizeof(sb->metadata_space_map_root), 3508c2ecf20Sopenharmony_ci &cmd->tm, &cmd->sm); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (r) { 3538c2ecf20Sopenharmony_ci DMERR("dm_tm_open_with_sm failed"); 3548c2ecf20Sopenharmony_ci goto out_with_lock; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci dm_disk_bitset_init(cmd->tm, &cmd->bitset_info); 3588c2ecf20Sopenharmony_ci cmd->bitset_root = le64_to_cpu(sb->bitset_root); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ciout_with_lock: 3618c2ecf20Sopenharmony_ci dm_bm_unlock(sblock); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return r; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int __format_metadata(struct dm_clone_metadata *cmd) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci int r; 3698c2ecf20Sopenharmony_ci struct dm_block *sblock; 3708c2ecf20Sopenharmony_ci struct superblock_disk *sb; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci r = dm_tm_create_with_sm(cmd->bm, SUPERBLOCK_LOCATION, &cmd->tm, &cmd->sm); 3738c2ecf20Sopenharmony_ci if (r) { 3748c2ecf20Sopenharmony_ci DMERR("Failed to create transaction manager"); 3758c2ecf20Sopenharmony_ci return r; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci dm_disk_bitset_init(cmd->tm, &cmd->bitset_info); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci r = dm_bitset_empty(&cmd->bitset_info, &cmd->bitset_root); 3818c2ecf20Sopenharmony_ci if (r) { 3828c2ecf20Sopenharmony_ci DMERR("Failed to create empty on-disk bitset"); 3838c2ecf20Sopenharmony_ci goto err_with_tm; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci r = dm_bitset_resize(&cmd->bitset_info, cmd->bitset_root, 0, 3878c2ecf20Sopenharmony_ci cmd->nr_regions, false, &cmd->bitset_root); 3888c2ecf20Sopenharmony_ci if (r) { 3898c2ecf20Sopenharmony_ci DMERR("Failed to resize on-disk bitset to %lu entries", cmd->nr_regions); 3908c2ecf20Sopenharmony_ci goto err_with_tm; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* Flush to disk all blocks, except the superblock */ 3948c2ecf20Sopenharmony_ci r = dm_tm_pre_commit(cmd->tm); 3958c2ecf20Sopenharmony_ci if (r) { 3968c2ecf20Sopenharmony_ci DMERR("dm_tm_pre_commit failed"); 3978c2ecf20Sopenharmony_ci goto err_with_tm; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci r = __copy_sm_root(cmd); 4018c2ecf20Sopenharmony_ci if (r) { 4028c2ecf20Sopenharmony_ci DMERR("__copy_sm_root failed"); 4038c2ecf20Sopenharmony_ci goto err_with_tm; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci r = superblock_write_lock_zero(cmd, &sblock); 4078c2ecf20Sopenharmony_ci if (r) { 4088c2ecf20Sopenharmony_ci DMERR("Failed to write_lock superblock"); 4098c2ecf20Sopenharmony_ci goto err_with_tm; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci sb = dm_block_data(sblock); 4138c2ecf20Sopenharmony_ci __prepare_superblock(cmd, sb); 4148c2ecf20Sopenharmony_ci r = dm_tm_commit(cmd->tm, sblock); 4158c2ecf20Sopenharmony_ci if (r) { 4168c2ecf20Sopenharmony_ci DMERR("Failed to commit superblock"); 4178c2ecf20Sopenharmony_ci goto err_with_tm; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cierr_with_tm: 4238c2ecf20Sopenharmony_ci dm_sm_destroy(cmd->sm); 4248c2ecf20Sopenharmony_ci dm_tm_destroy(cmd->tm); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci return r; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic int __open_or_format_metadata(struct dm_clone_metadata *cmd, bool may_format_device) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci int r; 4328c2ecf20Sopenharmony_ci bool formatted = false; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci r = __superblock_all_zeroes(cmd->bm, &formatted); 4358c2ecf20Sopenharmony_ci if (r) 4368c2ecf20Sopenharmony_ci return r; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (!formatted) 4398c2ecf20Sopenharmony_ci return may_format_device ? __format_metadata(cmd) : -EPERM; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci return __open_metadata(cmd); 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int __create_persistent_data_structures(struct dm_clone_metadata *cmd, 4458c2ecf20Sopenharmony_ci bool may_format_device) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci int r; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* Create block manager */ 4508c2ecf20Sopenharmony_ci cmd->bm = dm_block_manager_create(cmd->bdev, 4518c2ecf20Sopenharmony_ci DM_CLONE_METADATA_BLOCK_SIZE << SECTOR_SHIFT, 4528c2ecf20Sopenharmony_ci DM_CLONE_MAX_CONCURRENT_LOCKS); 4538c2ecf20Sopenharmony_ci if (IS_ERR(cmd->bm)) { 4548c2ecf20Sopenharmony_ci DMERR("Failed to create block manager"); 4558c2ecf20Sopenharmony_ci return PTR_ERR(cmd->bm); 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci r = __open_or_format_metadata(cmd, may_format_device); 4598c2ecf20Sopenharmony_ci if (r) 4608c2ecf20Sopenharmony_ci dm_block_manager_destroy(cmd->bm); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return r; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic void __destroy_persistent_data_structures(struct dm_clone_metadata *cmd) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci dm_sm_destroy(cmd->sm); 4688c2ecf20Sopenharmony_ci dm_tm_destroy(cmd->tm); 4698c2ecf20Sopenharmony_ci dm_block_manager_destroy(cmd->bm); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------------*/ 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic size_t bitmap_size(unsigned long nr_bits) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci return BITS_TO_LONGS(nr_bits) * sizeof(long); 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic int __dirty_map_init(struct dirty_map *dmap, unsigned long nr_words, 4808c2ecf20Sopenharmony_ci unsigned long nr_regions) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci dmap->changed = 0; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci dmap->dirty_words = kvzalloc(bitmap_size(nr_words), GFP_KERNEL); 4858c2ecf20Sopenharmony_ci if (!dmap->dirty_words) 4868c2ecf20Sopenharmony_ci return -ENOMEM; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci dmap->dirty_regions = kvzalloc(bitmap_size(nr_regions), GFP_KERNEL); 4898c2ecf20Sopenharmony_ci if (!dmap->dirty_regions) { 4908c2ecf20Sopenharmony_ci kvfree(dmap->dirty_words); 4918c2ecf20Sopenharmony_ci return -ENOMEM; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return 0; 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic void __dirty_map_exit(struct dirty_map *dmap) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci kvfree(dmap->dirty_words); 5008c2ecf20Sopenharmony_ci kvfree(dmap->dirty_regions); 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic int dirty_map_init(struct dm_clone_metadata *cmd) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci if (__dirty_map_init(&cmd->dmap[0], cmd->nr_words, cmd->nr_regions)) { 5068c2ecf20Sopenharmony_ci DMERR("Failed to allocate dirty bitmap"); 5078c2ecf20Sopenharmony_ci return -ENOMEM; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (__dirty_map_init(&cmd->dmap[1], cmd->nr_words, cmd->nr_regions)) { 5118c2ecf20Sopenharmony_ci DMERR("Failed to allocate dirty bitmap"); 5128c2ecf20Sopenharmony_ci __dirty_map_exit(&cmd->dmap[0]); 5138c2ecf20Sopenharmony_ci return -ENOMEM; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci cmd->current_dmap = &cmd->dmap[0]; 5178c2ecf20Sopenharmony_ci cmd->committing_dmap = NULL; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci return 0; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic void dirty_map_exit(struct dm_clone_metadata *cmd) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci __dirty_map_exit(&cmd->dmap[0]); 5258c2ecf20Sopenharmony_ci __dirty_map_exit(&cmd->dmap[1]); 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic int __load_bitset_in_core(struct dm_clone_metadata *cmd) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci int r; 5318c2ecf20Sopenharmony_ci unsigned long i; 5328c2ecf20Sopenharmony_ci struct dm_bitset_cursor c; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* Flush bitset cache */ 5358c2ecf20Sopenharmony_ci r = dm_bitset_flush(&cmd->bitset_info, cmd->bitset_root, &cmd->bitset_root); 5368c2ecf20Sopenharmony_ci if (r) 5378c2ecf20Sopenharmony_ci return r; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci r = dm_bitset_cursor_begin(&cmd->bitset_info, cmd->bitset_root, cmd->nr_regions, &c); 5408c2ecf20Sopenharmony_ci if (r) 5418c2ecf20Sopenharmony_ci return r; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci for (i = 0; ; i++) { 5448c2ecf20Sopenharmony_ci if (dm_bitset_cursor_get_value(&c)) 5458c2ecf20Sopenharmony_ci __set_bit(i, cmd->region_map); 5468c2ecf20Sopenharmony_ci else 5478c2ecf20Sopenharmony_ci __clear_bit(i, cmd->region_map); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (i >= (cmd->nr_regions - 1)) 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci r = dm_bitset_cursor_next(&c); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (r) 5558c2ecf20Sopenharmony_ci break; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci dm_bitset_cursor_end(&c); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci return r; 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cistruct dm_clone_metadata *dm_clone_metadata_open(struct block_device *bdev, 5648c2ecf20Sopenharmony_ci sector_t target_size, 5658c2ecf20Sopenharmony_ci sector_t region_size) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci int r; 5688c2ecf20Sopenharmony_ci struct dm_clone_metadata *cmd; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 5718c2ecf20Sopenharmony_ci if (!cmd) { 5728c2ecf20Sopenharmony_ci DMERR("Failed to allocate memory for dm-clone metadata"); 5738c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci cmd->bdev = bdev; 5778c2ecf20Sopenharmony_ci cmd->target_size = target_size; 5788c2ecf20Sopenharmony_ci cmd->region_size = region_size; 5798c2ecf20Sopenharmony_ci cmd->nr_regions = dm_sector_div_up(cmd->target_size, cmd->region_size); 5808c2ecf20Sopenharmony_ci cmd->nr_words = BITS_TO_LONGS(cmd->nr_regions); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci init_rwsem(&cmd->lock); 5838c2ecf20Sopenharmony_ci spin_lock_init(&cmd->bitmap_lock); 5848c2ecf20Sopenharmony_ci cmd->read_only = 0; 5858c2ecf20Sopenharmony_ci cmd->fail_io = false; 5868c2ecf20Sopenharmony_ci cmd->hydration_done = false; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci cmd->region_map = kvmalloc(bitmap_size(cmd->nr_regions), GFP_KERNEL); 5898c2ecf20Sopenharmony_ci if (!cmd->region_map) { 5908c2ecf20Sopenharmony_ci DMERR("Failed to allocate memory for region bitmap"); 5918c2ecf20Sopenharmony_ci r = -ENOMEM; 5928c2ecf20Sopenharmony_ci goto out_with_md; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci r = __create_persistent_data_structures(cmd, true); 5968c2ecf20Sopenharmony_ci if (r) 5978c2ecf20Sopenharmony_ci goto out_with_region_map; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci r = __load_bitset_in_core(cmd); 6008c2ecf20Sopenharmony_ci if (r) { 6018c2ecf20Sopenharmony_ci DMERR("Failed to load on-disk region map"); 6028c2ecf20Sopenharmony_ci goto out_with_pds; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci r = dirty_map_init(cmd); 6068c2ecf20Sopenharmony_ci if (r) 6078c2ecf20Sopenharmony_ci goto out_with_pds; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (bitmap_full(cmd->region_map, cmd->nr_regions)) 6108c2ecf20Sopenharmony_ci cmd->hydration_done = true; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci return cmd; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ciout_with_pds: 6158c2ecf20Sopenharmony_ci __destroy_persistent_data_structures(cmd); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ciout_with_region_map: 6188c2ecf20Sopenharmony_ci kvfree(cmd->region_map); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ciout_with_md: 6218c2ecf20Sopenharmony_ci kfree(cmd); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci return ERR_PTR(r); 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_civoid dm_clone_metadata_close(struct dm_clone_metadata *cmd) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci if (!cmd->fail_io) 6298c2ecf20Sopenharmony_ci __destroy_persistent_data_structures(cmd); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci dirty_map_exit(cmd); 6328c2ecf20Sopenharmony_ci kvfree(cmd->region_map); 6338c2ecf20Sopenharmony_ci kfree(cmd); 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cibool dm_clone_is_hydration_done(struct dm_clone_metadata *cmd) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci return cmd->hydration_done; 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cibool dm_clone_is_region_hydrated(struct dm_clone_metadata *cmd, unsigned long region_nr) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci return dm_clone_is_hydration_done(cmd) || test_bit(region_nr, cmd->region_map); 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cibool dm_clone_is_range_hydrated(struct dm_clone_metadata *cmd, 6478c2ecf20Sopenharmony_ci unsigned long start, unsigned long nr_regions) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci unsigned long bit; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (dm_clone_is_hydration_done(cmd)) 6528c2ecf20Sopenharmony_ci return true; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci bit = find_next_zero_bit(cmd->region_map, cmd->nr_regions, start); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci return (bit >= (start + nr_regions)); 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ciunsigned int dm_clone_nr_of_hydrated_regions(struct dm_clone_metadata *cmd) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci return bitmap_weight(cmd->region_map, cmd->nr_regions); 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ciunsigned long dm_clone_find_next_unhydrated_region(struct dm_clone_metadata *cmd, 6658c2ecf20Sopenharmony_ci unsigned long start) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci return find_next_zero_bit(cmd->region_map, cmd->nr_regions, start); 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistatic int __update_metadata_word(struct dm_clone_metadata *cmd, 6718c2ecf20Sopenharmony_ci unsigned long *dirty_regions, 6728c2ecf20Sopenharmony_ci unsigned long word) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci int r; 6758c2ecf20Sopenharmony_ci unsigned long index = word * BITS_PER_LONG; 6768c2ecf20Sopenharmony_ci unsigned long max_index = min(cmd->nr_regions, (word + 1) * BITS_PER_LONG); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci while (index < max_index) { 6798c2ecf20Sopenharmony_ci if (test_bit(index, dirty_regions)) { 6808c2ecf20Sopenharmony_ci r = dm_bitset_set_bit(&cmd->bitset_info, cmd->bitset_root, 6818c2ecf20Sopenharmony_ci index, &cmd->bitset_root); 6828c2ecf20Sopenharmony_ci if (r) { 6838c2ecf20Sopenharmony_ci DMERR("dm_bitset_set_bit failed"); 6848c2ecf20Sopenharmony_ci return r; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci __clear_bit(index, dirty_regions); 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci index++; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci return 0; 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic int __metadata_commit(struct dm_clone_metadata *cmd) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci int r; 6978c2ecf20Sopenharmony_ci struct dm_block *sblock; 6988c2ecf20Sopenharmony_ci struct superblock_disk *sb; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* Flush bitset cache */ 7018c2ecf20Sopenharmony_ci r = dm_bitset_flush(&cmd->bitset_info, cmd->bitset_root, &cmd->bitset_root); 7028c2ecf20Sopenharmony_ci if (r) { 7038c2ecf20Sopenharmony_ci DMERR("dm_bitset_flush failed"); 7048c2ecf20Sopenharmony_ci return r; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* Flush to disk all blocks, except the superblock */ 7088c2ecf20Sopenharmony_ci r = dm_tm_pre_commit(cmd->tm); 7098c2ecf20Sopenharmony_ci if (r) { 7108c2ecf20Sopenharmony_ci DMERR("dm_tm_pre_commit failed"); 7118c2ecf20Sopenharmony_ci return r; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* Save the space map root in cmd->metadata_space_map_root */ 7158c2ecf20Sopenharmony_ci r = __copy_sm_root(cmd); 7168c2ecf20Sopenharmony_ci if (r) { 7178c2ecf20Sopenharmony_ci DMERR("__copy_sm_root failed"); 7188c2ecf20Sopenharmony_ci return r; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci /* Lock the superblock */ 7228c2ecf20Sopenharmony_ci r = superblock_write_lock_zero(cmd, &sblock); 7238c2ecf20Sopenharmony_ci if (r) { 7248c2ecf20Sopenharmony_ci DMERR("Failed to write_lock superblock"); 7258c2ecf20Sopenharmony_ci return r; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci /* Save the metadata in superblock */ 7298c2ecf20Sopenharmony_ci sb = dm_block_data(sblock); 7308c2ecf20Sopenharmony_ci __prepare_superblock(cmd, sb); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci /* Unlock superblock and commit it to disk */ 7338c2ecf20Sopenharmony_ci r = dm_tm_commit(cmd->tm, sblock); 7348c2ecf20Sopenharmony_ci if (r) { 7358c2ecf20Sopenharmony_ci DMERR("Failed to commit superblock"); 7368c2ecf20Sopenharmony_ci return r; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* 7408c2ecf20Sopenharmony_ci * FIXME: Find a more efficient way to check if the hydration is done. 7418c2ecf20Sopenharmony_ci */ 7428c2ecf20Sopenharmony_ci if (bitmap_full(cmd->region_map, cmd->nr_regions)) 7438c2ecf20Sopenharmony_ci cmd->hydration_done = true; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci return 0; 7468c2ecf20Sopenharmony_ci} 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic int __flush_dmap(struct dm_clone_metadata *cmd, struct dirty_map *dmap) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci int r; 7518c2ecf20Sopenharmony_ci unsigned long word; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci word = 0; 7548c2ecf20Sopenharmony_ci do { 7558c2ecf20Sopenharmony_ci word = find_next_bit(dmap->dirty_words, cmd->nr_words, word); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (word == cmd->nr_words) 7588c2ecf20Sopenharmony_ci break; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci r = __update_metadata_word(cmd, dmap->dirty_regions, word); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (r) 7638c2ecf20Sopenharmony_ci return r; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci __clear_bit(word, dmap->dirty_words); 7668c2ecf20Sopenharmony_ci word++; 7678c2ecf20Sopenharmony_ci } while (word < cmd->nr_words); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci r = __metadata_commit(cmd); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (r) 7728c2ecf20Sopenharmony_ci return r; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci /* Update the changed flag */ 7758c2ecf20Sopenharmony_ci spin_lock_irq(&cmd->bitmap_lock); 7768c2ecf20Sopenharmony_ci dmap->changed = 0; 7778c2ecf20Sopenharmony_ci spin_unlock_irq(&cmd->bitmap_lock); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return 0; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ciint dm_clone_metadata_pre_commit(struct dm_clone_metadata *cmd) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci int r = 0; 7858c2ecf20Sopenharmony_ci struct dirty_map *dmap, *next_dmap; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci down_write(&cmd->lock); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { 7908c2ecf20Sopenharmony_ci r = -EPERM; 7918c2ecf20Sopenharmony_ci goto out; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci /* Get current dirty bitmap */ 7958c2ecf20Sopenharmony_ci dmap = cmd->current_dmap; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci /* Get next dirty bitmap */ 7988c2ecf20Sopenharmony_ci next_dmap = (dmap == &cmd->dmap[0]) ? &cmd->dmap[1] : &cmd->dmap[0]; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci /* 8018c2ecf20Sopenharmony_ci * The last commit failed, so we don't have a clean dirty-bitmap to 8028c2ecf20Sopenharmony_ci * use. 8038c2ecf20Sopenharmony_ci */ 8048c2ecf20Sopenharmony_ci if (WARN_ON(next_dmap->changed || cmd->committing_dmap)) { 8058c2ecf20Sopenharmony_ci r = -EINVAL; 8068c2ecf20Sopenharmony_ci goto out; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci /* Swap dirty bitmaps */ 8108c2ecf20Sopenharmony_ci spin_lock_irq(&cmd->bitmap_lock); 8118c2ecf20Sopenharmony_ci cmd->current_dmap = next_dmap; 8128c2ecf20Sopenharmony_ci spin_unlock_irq(&cmd->bitmap_lock); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci /* Set old dirty bitmap as currently committing */ 8158c2ecf20Sopenharmony_ci cmd->committing_dmap = dmap; 8168c2ecf20Sopenharmony_ciout: 8178c2ecf20Sopenharmony_ci up_write(&cmd->lock); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci return r; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ciint dm_clone_metadata_commit(struct dm_clone_metadata *cmd) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci int r = -EPERM; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci down_write(&cmd->lock); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) 8298c2ecf20Sopenharmony_ci goto out; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci if (WARN_ON(!cmd->committing_dmap)) { 8328c2ecf20Sopenharmony_ci r = -EINVAL; 8338c2ecf20Sopenharmony_ci goto out; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci r = __flush_dmap(cmd, cmd->committing_dmap); 8378c2ecf20Sopenharmony_ci if (!r) { 8388c2ecf20Sopenharmony_ci /* Clear committing dmap */ 8398c2ecf20Sopenharmony_ci cmd->committing_dmap = NULL; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ciout: 8428c2ecf20Sopenharmony_ci up_write(&cmd->lock); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci return r; 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ciint dm_clone_set_region_hydrated(struct dm_clone_metadata *cmd, unsigned long region_nr) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci int r = 0; 8508c2ecf20Sopenharmony_ci struct dirty_map *dmap; 8518c2ecf20Sopenharmony_ci unsigned long word, flags; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci if (unlikely(region_nr >= cmd->nr_regions)) { 8548c2ecf20Sopenharmony_ci DMERR("Region %lu out of range (total number of regions %lu)", 8558c2ecf20Sopenharmony_ci region_nr, cmd->nr_regions); 8568c2ecf20Sopenharmony_ci return -ERANGE; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci word = region_nr / BITS_PER_LONG; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci spin_lock_irqsave(&cmd->bitmap_lock, flags); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci if (cmd->read_only) { 8648c2ecf20Sopenharmony_ci r = -EPERM; 8658c2ecf20Sopenharmony_ci goto out; 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci dmap = cmd->current_dmap; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci __set_bit(word, dmap->dirty_words); 8718c2ecf20Sopenharmony_ci __set_bit(region_nr, dmap->dirty_regions); 8728c2ecf20Sopenharmony_ci __set_bit(region_nr, cmd->region_map); 8738c2ecf20Sopenharmony_ci dmap->changed = 1; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ciout: 8768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cmd->bitmap_lock, flags); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci return r; 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ciint dm_clone_cond_set_range(struct dm_clone_metadata *cmd, unsigned long start, 8828c2ecf20Sopenharmony_ci unsigned long nr_regions) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci int r = 0; 8858c2ecf20Sopenharmony_ci struct dirty_map *dmap; 8868c2ecf20Sopenharmony_ci unsigned long word, region_nr; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci if (unlikely(start >= cmd->nr_regions || (start + nr_regions) < start || 8898c2ecf20Sopenharmony_ci (start + nr_regions) > cmd->nr_regions)) { 8908c2ecf20Sopenharmony_ci DMERR("Invalid region range: start %lu, nr_regions %lu (total number of regions %lu)", 8918c2ecf20Sopenharmony_ci start, nr_regions, cmd->nr_regions); 8928c2ecf20Sopenharmony_ci return -ERANGE; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci spin_lock_irq(&cmd->bitmap_lock); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci if (cmd->read_only) { 8988c2ecf20Sopenharmony_ci r = -EPERM; 8998c2ecf20Sopenharmony_ci goto out; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci dmap = cmd->current_dmap; 9038c2ecf20Sopenharmony_ci for (region_nr = start; region_nr < (start + nr_regions); region_nr++) { 9048c2ecf20Sopenharmony_ci if (!test_bit(region_nr, cmd->region_map)) { 9058c2ecf20Sopenharmony_ci word = region_nr / BITS_PER_LONG; 9068c2ecf20Sopenharmony_ci __set_bit(word, dmap->dirty_words); 9078c2ecf20Sopenharmony_ci __set_bit(region_nr, dmap->dirty_regions); 9088c2ecf20Sopenharmony_ci __set_bit(region_nr, cmd->region_map); 9098c2ecf20Sopenharmony_ci dmap->changed = 1; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ciout: 9138c2ecf20Sopenharmony_ci spin_unlock_irq(&cmd->bitmap_lock); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci return r; 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci/* 9198c2ecf20Sopenharmony_ci * WARNING: This must not be called concurrently with either 9208c2ecf20Sopenharmony_ci * dm_clone_set_region_hydrated() or dm_clone_cond_set_range(), as it changes 9218c2ecf20Sopenharmony_ci * cmd->region_map without taking the cmd->bitmap_lock spinlock. The only 9228c2ecf20Sopenharmony_ci * exception is after setting the metadata to read-only mode, using 9238c2ecf20Sopenharmony_ci * dm_clone_metadata_set_read_only(). 9248c2ecf20Sopenharmony_ci * 9258c2ecf20Sopenharmony_ci * We don't take the spinlock because __load_bitset_in_core() does I/O, so it 9268c2ecf20Sopenharmony_ci * may block. 9278c2ecf20Sopenharmony_ci */ 9288c2ecf20Sopenharmony_ciint dm_clone_reload_in_core_bitset(struct dm_clone_metadata *cmd) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci int r = -EINVAL; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci down_write(&cmd->lock); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci if (cmd->fail_io) 9358c2ecf20Sopenharmony_ci goto out; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci r = __load_bitset_in_core(cmd); 9388c2ecf20Sopenharmony_ciout: 9398c2ecf20Sopenharmony_ci up_write(&cmd->lock); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci return r; 9428c2ecf20Sopenharmony_ci} 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_cibool dm_clone_changed_this_transaction(struct dm_clone_metadata *cmd) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci bool r; 9478c2ecf20Sopenharmony_ci unsigned long flags; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci spin_lock_irqsave(&cmd->bitmap_lock, flags); 9508c2ecf20Sopenharmony_ci r = cmd->dmap[0].changed || cmd->dmap[1].changed; 9518c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cmd->bitmap_lock, flags); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci return r; 9548c2ecf20Sopenharmony_ci} 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ciint dm_clone_metadata_abort(struct dm_clone_metadata *cmd) 9578c2ecf20Sopenharmony_ci{ 9588c2ecf20Sopenharmony_ci int r = -EPERM; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci down_write(&cmd->lock); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) 9638c2ecf20Sopenharmony_ci goto out; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci __destroy_persistent_data_structures(cmd); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci r = __create_persistent_data_structures(cmd, false); 9688c2ecf20Sopenharmony_ci if (r) { 9698c2ecf20Sopenharmony_ci /* If something went wrong we can neither write nor read the metadata */ 9708c2ecf20Sopenharmony_ci cmd->fail_io = true; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ciout: 9738c2ecf20Sopenharmony_ci up_write(&cmd->lock); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci return r; 9768c2ecf20Sopenharmony_ci} 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_civoid dm_clone_metadata_set_read_only(struct dm_clone_metadata *cmd) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci down_write(&cmd->lock); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci spin_lock_irq(&cmd->bitmap_lock); 9838c2ecf20Sopenharmony_ci cmd->read_only = 1; 9848c2ecf20Sopenharmony_ci spin_unlock_irq(&cmd->bitmap_lock); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (!cmd->fail_io) 9878c2ecf20Sopenharmony_ci dm_bm_set_read_only(cmd->bm); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci up_write(&cmd->lock); 9908c2ecf20Sopenharmony_ci} 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_civoid dm_clone_metadata_set_read_write(struct dm_clone_metadata *cmd) 9938c2ecf20Sopenharmony_ci{ 9948c2ecf20Sopenharmony_ci down_write(&cmd->lock); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci spin_lock_irq(&cmd->bitmap_lock); 9978c2ecf20Sopenharmony_ci cmd->read_only = 0; 9988c2ecf20Sopenharmony_ci spin_unlock_irq(&cmd->bitmap_lock); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (!cmd->fail_io) 10018c2ecf20Sopenharmony_ci dm_bm_set_read_write(cmd->bm); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci up_write(&cmd->lock); 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ciint dm_clone_get_free_metadata_block_count(struct dm_clone_metadata *cmd, 10078c2ecf20Sopenharmony_ci dm_block_t *result) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci int r = -EINVAL; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci down_read(&cmd->lock); 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci if (!cmd->fail_io) 10148c2ecf20Sopenharmony_ci r = dm_sm_get_nr_free(cmd->sm, result); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci up_read(&cmd->lock); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci return r; 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ciint dm_clone_get_metadata_dev_size(struct dm_clone_metadata *cmd, 10228c2ecf20Sopenharmony_ci dm_block_t *result) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci int r = -EINVAL; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci down_read(&cmd->lock); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (!cmd->fail_io) 10298c2ecf20Sopenharmony_ci r = dm_sm_get_nr_blocks(cmd->sm, result); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci up_read(&cmd->lock); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci return r; 10348c2ecf20Sopenharmony_ci} 1035