18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2001 Sistina Software (UK) Limited. 38c2ecf20Sopenharmony_ci * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file is released under the GPL. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "dm-core.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 128c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 138c2ecf20Sopenharmony_ci#include <linux/namei.h> 148c2ecf20Sopenharmony_ci#include <linux/ctype.h> 158c2ecf20Sopenharmony_ci#include <linux/string.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 188c2ecf20Sopenharmony_ci#include <linux/mutex.h> 198c2ecf20Sopenharmony_ci#include <linux/delay.h> 208c2ecf20Sopenharmony_ci#include <linux/atomic.h> 218c2ecf20Sopenharmony_ci#include <linux/blk-mq.h> 228c2ecf20Sopenharmony_ci#include <linux/mount.h> 238c2ecf20Sopenharmony_ci#include <linux/dax.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define DM_MSG_PREFIX "table" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define NODE_SIZE L1_CACHE_BYTES 288c2ecf20Sopenharmony_ci#define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t)) 298c2ecf20Sopenharmony_ci#define CHILDREN_PER_NODE (KEYS_PER_NODE + 1) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * Similar to ceiling(log_size(n)) 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_cistatic unsigned int int_log(unsigned int n, unsigned int base) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci int result = 0; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci while (n > 1) { 398c2ecf20Sopenharmony_ci n = dm_div_up(n, base); 408c2ecf20Sopenharmony_ci result++; 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci return result; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* 478c2ecf20Sopenharmony_ci * Calculate the index of the child node of the n'th node k'th key. 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_cistatic inline unsigned int get_child(unsigned int n, unsigned int k) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci return (n * CHILDREN_PER_NODE) + k; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* 558c2ecf20Sopenharmony_ci * Return the n'th node of level l from table t. 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_cistatic inline sector_t *get_node(struct dm_table *t, 588c2ecf20Sopenharmony_ci unsigned int l, unsigned int n) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci return t->index[l] + (n * KEYS_PER_NODE); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* 648c2ecf20Sopenharmony_ci * Return the highest key that you could lookup from the n'th 658c2ecf20Sopenharmony_ci * node on level l of the btree. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_cistatic sector_t high(struct dm_table *t, unsigned int l, unsigned int n) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci for (; l < t->depth - 1; l++) 708c2ecf20Sopenharmony_ci n = get_child(n, CHILDREN_PER_NODE - 1); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (n >= t->counts[l]) 738c2ecf20Sopenharmony_ci return (sector_t) - 1; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return get_node(t, l, n)[KEYS_PER_NODE - 1]; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* 798c2ecf20Sopenharmony_ci * Fills in a level of the btree based on the highs of the level 808c2ecf20Sopenharmony_ci * below it. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_cistatic int setup_btree_index(unsigned int l, struct dm_table *t) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci unsigned int n, k; 858c2ecf20Sopenharmony_ci sector_t *node; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci for (n = 0U; n < t->counts[l]; n++) { 888c2ecf20Sopenharmony_ci node = get_node(t, l, n); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci for (k = 0U; k < KEYS_PER_NODE; k++) 918c2ecf20Sopenharmony_ci node[k] = high(t, l + 1, get_child(n, k)); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return 0; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_civoid *dm_vcalloc(unsigned long nmemb, unsigned long elem_size) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci unsigned long size; 1008c2ecf20Sopenharmony_ci void *addr; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* 1038c2ecf20Sopenharmony_ci * Check that we're not going to overflow. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci if (nmemb > (ULONG_MAX / elem_size)) 1068c2ecf20Sopenharmony_ci return NULL; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci size = nmemb * elem_size; 1098c2ecf20Sopenharmony_ci addr = vzalloc(size); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return addr; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_vcalloc); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* 1168c2ecf20Sopenharmony_ci * highs, and targets are managed as dynamic arrays during a 1178c2ecf20Sopenharmony_ci * table load. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_cistatic int alloc_targets(struct dm_table *t, unsigned int num) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci sector_t *n_highs; 1228c2ecf20Sopenharmony_ci struct dm_target *n_targets; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* 1258c2ecf20Sopenharmony_ci * Allocate both the target array and offset array at once. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci n_highs = (sector_t *) dm_vcalloc(num, sizeof(struct dm_target) + 1288c2ecf20Sopenharmony_ci sizeof(sector_t)); 1298c2ecf20Sopenharmony_ci if (!n_highs) 1308c2ecf20Sopenharmony_ci return -ENOMEM; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci n_targets = (struct dm_target *) (n_highs + num); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci memset(n_highs, -1, sizeof(*n_highs) * num); 1358c2ecf20Sopenharmony_ci vfree(t->highs); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci t->num_allocated = num; 1388c2ecf20Sopenharmony_ci t->highs = n_highs; 1398c2ecf20Sopenharmony_ci t->targets = n_targets; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ciint dm_table_create(struct dm_table **result, fmode_t mode, 1458c2ecf20Sopenharmony_ci unsigned num_targets, struct mapped_device *md) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct dm_table *t; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (num_targets > DM_MAX_TARGETS) 1508c2ecf20Sopenharmony_ci return -EOVERFLOW; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci t = kzalloc(sizeof(*t), GFP_KERNEL); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (!t) 1558c2ecf20Sopenharmony_ci return -ENOMEM; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&t->devices); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (!num_targets) 1608c2ecf20Sopenharmony_ci num_targets = KEYS_PER_NODE; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci num_targets = dm_round_up(num_targets, KEYS_PER_NODE); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (!num_targets) { 1658c2ecf20Sopenharmony_ci kfree(t); 1668c2ecf20Sopenharmony_ci return -EOVERFLOW; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (alloc_targets(t, num_targets)) { 1708c2ecf20Sopenharmony_ci kfree(t); 1718c2ecf20Sopenharmony_ci return -ENOMEM; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci t->type = DM_TYPE_NONE; 1758c2ecf20Sopenharmony_ci t->mode = mode; 1768c2ecf20Sopenharmony_ci t->md = md; 1778c2ecf20Sopenharmony_ci *result = t; 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void free_devices(struct list_head *devices, struct mapped_device *md) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct list_head *tmp, *next; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci list_for_each_safe(tmp, next, devices) { 1868c2ecf20Sopenharmony_ci struct dm_dev_internal *dd = 1878c2ecf20Sopenharmony_ci list_entry(tmp, struct dm_dev_internal, list); 1888c2ecf20Sopenharmony_ci DMWARN("%s: dm_table_destroy: dm_put_device call missing for %s", 1898c2ecf20Sopenharmony_ci dm_device_name(md), dd->dm_dev->name); 1908c2ecf20Sopenharmony_ci dm_put_table_device(md, dd->dm_dev); 1918c2ecf20Sopenharmony_ci kfree(dd); 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_civoid dm_table_destroy(struct dm_table *t) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci unsigned int i; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (!t) 2008c2ecf20Sopenharmony_ci return; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* free the indexes */ 2038c2ecf20Sopenharmony_ci if (t->depth >= 2) 2048c2ecf20Sopenharmony_ci vfree(t->index[t->depth - 2]); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* free the targets */ 2078c2ecf20Sopenharmony_ci for (i = 0; i < t->num_targets; i++) { 2088c2ecf20Sopenharmony_ci struct dm_target *tgt = t->targets + i; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (tgt->type->dtr) 2118c2ecf20Sopenharmony_ci tgt->type->dtr(tgt); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci dm_put_target_type(tgt->type); 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci vfree(t->highs); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* free the device list */ 2198c2ecf20Sopenharmony_ci free_devices(&t->devices, t->md); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci dm_free_md_mempools(t->mempools); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci kfree(t); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci/* 2278c2ecf20Sopenharmony_ci * See if we've already got a device in the list. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_cistatic struct dm_dev_internal *find_device(struct list_head *l, dev_t dev) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct dm_dev_internal *dd; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci list_for_each_entry (dd, l, list) 2348c2ecf20Sopenharmony_ci if (dd->dm_dev->bdev->bd_dev == dev) 2358c2ecf20Sopenharmony_ci return dd; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return NULL; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci/* 2418c2ecf20Sopenharmony_ci * If possible, this checks an area of a destination device is invalid. 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_cistatic int device_area_is_invalid(struct dm_target *ti, struct dm_dev *dev, 2448c2ecf20Sopenharmony_ci sector_t start, sector_t len, void *data) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct queue_limits *limits = data; 2478c2ecf20Sopenharmony_ci struct block_device *bdev = dev->bdev; 2488c2ecf20Sopenharmony_ci sector_t dev_size = 2498c2ecf20Sopenharmony_ci i_size_read(bdev->bd_inode) >> SECTOR_SHIFT; 2508c2ecf20Sopenharmony_ci unsigned short logical_block_size_sectors = 2518c2ecf20Sopenharmony_ci limits->logical_block_size >> SECTOR_SHIFT; 2528c2ecf20Sopenharmony_ci char b[BDEVNAME_SIZE]; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (!dev_size) 2558c2ecf20Sopenharmony_ci return 0; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if ((start >= dev_size) || (start + len > dev_size)) { 2588c2ecf20Sopenharmony_ci DMWARN("%s: %s too small for target: " 2598c2ecf20Sopenharmony_ci "start=%llu, len=%llu, dev_size=%llu", 2608c2ecf20Sopenharmony_ci dm_device_name(ti->table->md), bdevname(bdev, b), 2618c2ecf20Sopenharmony_ci (unsigned long long)start, 2628c2ecf20Sopenharmony_ci (unsigned long long)len, 2638c2ecf20Sopenharmony_ci (unsigned long long)dev_size); 2648c2ecf20Sopenharmony_ci return 1; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* 2688c2ecf20Sopenharmony_ci * If the target is mapped to zoned block device(s), check 2698c2ecf20Sopenharmony_ci * that the zones are not partially mapped. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ci if (bdev_zoned_model(bdev) != BLK_ZONED_NONE) { 2728c2ecf20Sopenharmony_ci unsigned int zone_sectors = bdev_zone_sectors(bdev); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (start & (zone_sectors - 1)) { 2758c2ecf20Sopenharmony_ci DMWARN("%s: start=%llu not aligned to h/w zone size %u of %s", 2768c2ecf20Sopenharmony_ci dm_device_name(ti->table->md), 2778c2ecf20Sopenharmony_ci (unsigned long long)start, 2788c2ecf20Sopenharmony_ci zone_sectors, bdevname(bdev, b)); 2798c2ecf20Sopenharmony_ci return 1; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* 2838c2ecf20Sopenharmony_ci * Note: The last zone of a zoned block device may be smaller 2848c2ecf20Sopenharmony_ci * than other zones. So for a target mapping the end of a 2858c2ecf20Sopenharmony_ci * zoned block device with such a zone, len would not be zone 2868c2ecf20Sopenharmony_ci * aligned. We do not allow such last smaller zone to be part 2878c2ecf20Sopenharmony_ci * of the mapping here to ensure that mappings with multiple 2888c2ecf20Sopenharmony_ci * devices do not end up with a smaller zone in the middle of 2898c2ecf20Sopenharmony_ci * the sector range. 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_ci if (len & (zone_sectors - 1)) { 2928c2ecf20Sopenharmony_ci DMWARN("%s: len=%llu not aligned to h/w zone size %u of %s", 2938c2ecf20Sopenharmony_ci dm_device_name(ti->table->md), 2948c2ecf20Sopenharmony_ci (unsigned long long)len, 2958c2ecf20Sopenharmony_ci zone_sectors, bdevname(bdev, b)); 2968c2ecf20Sopenharmony_ci return 1; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (logical_block_size_sectors <= 1) 3018c2ecf20Sopenharmony_ci return 0; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (start & (logical_block_size_sectors - 1)) { 3048c2ecf20Sopenharmony_ci DMWARN("%s: start=%llu not aligned to h/w " 3058c2ecf20Sopenharmony_ci "logical block size %u of %s", 3068c2ecf20Sopenharmony_ci dm_device_name(ti->table->md), 3078c2ecf20Sopenharmony_ci (unsigned long long)start, 3088c2ecf20Sopenharmony_ci limits->logical_block_size, bdevname(bdev, b)); 3098c2ecf20Sopenharmony_ci return 1; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (len & (logical_block_size_sectors - 1)) { 3138c2ecf20Sopenharmony_ci DMWARN("%s: len=%llu not aligned to h/w " 3148c2ecf20Sopenharmony_ci "logical block size %u of %s", 3158c2ecf20Sopenharmony_ci dm_device_name(ti->table->md), 3168c2ecf20Sopenharmony_ci (unsigned long long)len, 3178c2ecf20Sopenharmony_ci limits->logical_block_size, bdevname(bdev, b)); 3188c2ecf20Sopenharmony_ci return 1; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return 0; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci/* 3258c2ecf20Sopenharmony_ci * This upgrades the mode on an already open dm_dev, being 3268c2ecf20Sopenharmony_ci * careful to leave things as they were if we fail to reopen the 3278c2ecf20Sopenharmony_ci * device and not to touch the existing bdev field in case 3288c2ecf20Sopenharmony_ci * it is accessed concurrently. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_cistatic int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode, 3318c2ecf20Sopenharmony_ci struct mapped_device *md) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci int r; 3348c2ecf20Sopenharmony_ci struct dm_dev *old_dev, *new_dev; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci old_dev = dd->dm_dev; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci r = dm_get_table_device(md, dd->dm_dev->bdev->bd_dev, 3398c2ecf20Sopenharmony_ci dd->dm_dev->mode | new_mode, &new_dev); 3408c2ecf20Sopenharmony_ci if (r) 3418c2ecf20Sopenharmony_ci return r; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci dd->dm_dev = new_dev; 3448c2ecf20Sopenharmony_ci dm_put_table_device(md, old_dev); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/* 3508c2ecf20Sopenharmony_ci * Convert the path to a device 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_cidev_t dm_get_dev_t(const char *path) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci dev_t dev; 3558c2ecf20Sopenharmony_ci struct block_device *bdev; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci bdev = lookup_bdev(path); 3588c2ecf20Sopenharmony_ci if (IS_ERR(bdev)) 3598c2ecf20Sopenharmony_ci dev = name_to_dev_t(path); 3608c2ecf20Sopenharmony_ci else { 3618c2ecf20Sopenharmony_ci dev = bdev->bd_dev; 3628c2ecf20Sopenharmony_ci bdput(bdev); 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return dev; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_get_dev_t); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci/* 3708c2ecf20Sopenharmony_ci * Add a device to the list, or just increment the usage count if 3718c2ecf20Sopenharmony_ci * it's already present. 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_ciint dm_get_device(struct dm_target *ti, const char *path, fmode_t mode, 3748c2ecf20Sopenharmony_ci struct dm_dev **result) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci int r; 3778c2ecf20Sopenharmony_ci dev_t dev; 3788c2ecf20Sopenharmony_ci unsigned int major, minor; 3798c2ecf20Sopenharmony_ci char dummy; 3808c2ecf20Sopenharmony_ci struct dm_dev_internal *dd; 3818c2ecf20Sopenharmony_ci struct dm_table *t = ti->table; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci BUG_ON(!t); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (sscanf(path, "%u:%u%c", &major, &minor, &dummy) == 2) { 3868c2ecf20Sopenharmony_ci /* Extract the major/minor numbers */ 3878c2ecf20Sopenharmony_ci dev = MKDEV(major, minor); 3888c2ecf20Sopenharmony_ci if (MAJOR(dev) != major || MINOR(dev) != minor) 3898c2ecf20Sopenharmony_ci return -EOVERFLOW; 3908c2ecf20Sopenharmony_ci } else { 3918c2ecf20Sopenharmony_ci dev = dm_get_dev_t(path); 3928c2ecf20Sopenharmony_ci if (!dev) 3938c2ecf20Sopenharmony_ci return -ENODEV; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci dd = find_device(&t->devices, dev); 3978c2ecf20Sopenharmony_ci if (!dd) { 3988c2ecf20Sopenharmony_ci dd = kmalloc(sizeof(*dd), GFP_KERNEL); 3998c2ecf20Sopenharmony_ci if (!dd) 4008c2ecf20Sopenharmony_ci return -ENOMEM; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if ((r = dm_get_table_device(t->md, dev, mode, &dd->dm_dev))) { 4038c2ecf20Sopenharmony_ci kfree(dd); 4048c2ecf20Sopenharmony_ci return r; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci refcount_set(&dd->count, 1); 4088c2ecf20Sopenharmony_ci list_add(&dd->list, &t->devices); 4098c2ecf20Sopenharmony_ci goto out; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci } else if (dd->dm_dev->mode != (mode | dd->dm_dev->mode)) { 4128c2ecf20Sopenharmony_ci r = upgrade_mode(dd, mode, t->md); 4138c2ecf20Sopenharmony_ci if (r) 4148c2ecf20Sopenharmony_ci return r; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci refcount_inc(&dd->count); 4178c2ecf20Sopenharmony_ciout: 4188c2ecf20Sopenharmony_ci *result = dd->dm_dev; 4198c2ecf20Sopenharmony_ci return 0; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_get_device); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev, 4248c2ecf20Sopenharmony_ci sector_t start, sector_t len, void *data) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct queue_limits *limits = data; 4278c2ecf20Sopenharmony_ci struct block_device *bdev = dev->bdev; 4288c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(bdev); 4298c2ecf20Sopenharmony_ci char b[BDEVNAME_SIZE]; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (unlikely(!q)) { 4328c2ecf20Sopenharmony_ci DMWARN("%s: Cannot set limits for nonexistent device %s", 4338c2ecf20Sopenharmony_ci dm_device_name(ti->table->md), bdevname(bdev, b)); 4348c2ecf20Sopenharmony_ci return 0; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (blk_stack_limits(limits, &q->limits, 4388c2ecf20Sopenharmony_ci get_start_sect(bdev) + start) < 0) 4398c2ecf20Sopenharmony_ci DMWARN("%s: adding target device %s caused an alignment inconsistency: " 4408c2ecf20Sopenharmony_ci "physical_block_size=%u, logical_block_size=%u, " 4418c2ecf20Sopenharmony_ci "alignment_offset=%u, start=%llu", 4428c2ecf20Sopenharmony_ci dm_device_name(ti->table->md), bdevname(bdev, b), 4438c2ecf20Sopenharmony_ci q->limits.physical_block_size, 4448c2ecf20Sopenharmony_ci q->limits.logical_block_size, 4458c2ecf20Sopenharmony_ci q->limits.alignment_offset, 4468c2ecf20Sopenharmony_ci (unsigned long long) start << SECTOR_SHIFT); 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci/* 4518c2ecf20Sopenharmony_ci * Decrement a device's use count and remove it if necessary. 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_civoid dm_put_device(struct dm_target *ti, struct dm_dev *d) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci int found = 0; 4568c2ecf20Sopenharmony_ci struct list_head *devices = &ti->table->devices; 4578c2ecf20Sopenharmony_ci struct dm_dev_internal *dd; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci list_for_each_entry(dd, devices, list) { 4608c2ecf20Sopenharmony_ci if (dd->dm_dev == d) { 4618c2ecf20Sopenharmony_ci found = 1; 4628c2ecf20Sopenharmony_ci break; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci if (!found) { 4668c2ecf20Sopenharmony_ci DMWARN("%s: device %s not in table devices list", 4678c2ecf20Sopenharmony_ci dm_device_name(ti->table->md), d->name); 4688c2ecf20Sopenharmony_ci return; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&dd->count)) { 4718c2ecf20Sopenharmony_ci dm_put_table_device(ti->table->md, d); 4728c2ecf20Sopenharmony_ci list_del(&dd->list); 4738c2ecf20Sopenharmony_ci kfree(dd); 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_put_device); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci/* 4798c2ecf20Sopenharmony_ci * Checks to see if the target joins onto the end of the table. 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_cistatic int adjoin(struct dm_table *table, struct dm_target *ti) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct dm_target *prev; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (!table->num_targets) 4868c2ecf20Sopenharmony_ci return !ti->begin; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci prev = &table->targets[table->num_targets - 1]; 4898c2ecf20Sopenharmony_ci return (ti->begin == (prev->begin + prev->len)); 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci/* 4938c2ecf20Sopenharmony_ci * Used to dynamically allocate the arg array. 4948c2ecf20Sopenharmony_ci * 4958c2ecf20Sopenharmony_ci * We do first allocation with GFP_NOIO because dm-mpath and dm-thin must 4968c2ecf20Sopenharmony_ci * process messages even if some device is suspended. These messages have a 4978c2ecf20Sopenharmony_ci * small fixed number of arguments. 4988c2ecf20Sopenharmony_ci * 4998c2ecf20Sopenharmony_ci * On the other hand, dm-switch needs to process bulk data using messages and 5008c2ecf20Sopenharmony_ci * excessive use of GFP_NOIO could cause trouble. 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_cistatic char **realloc_argv(unsigned *size, char **old_argv) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci char **argv; 5058c2ecf20Sopenharmony_ci unsigned new_size; 5068c2ecf20Sopenharmony_ci gfp_t gfp; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if (*size) { 5098c2ecf20Sopenharmony_ci new_size = *size * 2; 5108c2ecf20Sopenharmony_ci gfp = GFP_KERNEL; 5118c2ecf20Sopenharmony_ci } else { 5128c2ecf20Sopenharmony_ci new_size = 8; 5138c2ecf20Sopenharmony_ci gfp = GFP_NOIO; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci argv = kmalloc_array(new_size, sizeof(*argv), gfp); 5168c2ecf20Sopenharmony_ci if (argv && old_argv) { 5178c2ecf20Sopenharmony_ci memcpy(argv, old_argv, *size * sizeof(*argv)); 5188c2ecf20Sopenharmony_ci *size = new_size; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci kfree(old_argv); 5228c2ecf20Sopenharmony_ci return argv; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci/* 5268c2ecf20Sopenharmony_ci * Destructively splits up the argument list to pass to ctr. 5278c2ecf20Sopenharmony_ci */ 5288c2ecf20Sopenharmony_ciint dm_split_args(int *argc, char ***argvp, char *input) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci char *start, *end = input, *out, **argv = NULL; 5318c2ecf20Sopenharmony_ci unsigned array_size = 0; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci *argc = 0; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (!input) { 5368c2ecf20Sopenharmony_ci *argvp = NULL; 5378c2ecf20Sopenharmony_ci return 0; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci argv = realloc_argv(&array_size, argv); 5418c2ecf20Sopenharmony_ci if (!argv) 5428c2ecf20Sopenharmony_ci return -ENOMEM; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci while (1) { 5458c2ecf20Sopenharmony_ci /* Skip whitespace */ 5468c2ecf20Sopenharmony_ci start = skip_spaces(end); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (!*start) 5498c2ecf20Sopenharmony_ci break; /* success, we hit the end */ 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci /* 'out' is used to remove any back-quotes */ 5528c2ecf20Sopenharmony_ci end = out = start; 5538c2ecf20Sopenharmony_ci while (*end) { 5548c2ecf20Sopenharmony_ci /* Everything apart from '\0' can be quoted */ 5558c2ecf20Sopenharmony_ci if (*end == '\\' && *(end + 1)) { 5568c2ecf20Sopenharmony_ci *out++ = *(end + 1); 5578c2ecf20Sopenharmony_ci end += 2; 5588c2ecf20Sopenharmony_ci continue; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (isspace(*end)) 5628c2ecf20Sopenharmony_ci break; /* end of token */ 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci *out++ = *end++; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* have we already filled the array ? */ 5688c2ecf20Sopenharmony_ci if ((*argc + 1) > array_size) { 5698c2ecf20Sopenharmony_ci argv = realloc_argv(&array_size, argv); 5708c2ecf20Sopenharmony_ci if (!argv) 5718c2ecf20Sopenharmony_ci return -ENOMEM; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* we know this is whitespace */ 5758c2ecf20Sopenharmony_ci if (*end) 5768c2ecf20Sopenharmony_ci end++; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* terminate the string and put it in the array */ 5798c2ecf20Sopenharmony_ci *out = '\0'; 5808c2ecf20Sopenharmony_ci argv[*argc] = start; 5818c2ecf20Sopenharmony_ci (*argc)++; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci *argvp = argv; 5858c2ecf20Sopenharmony_ci return 0; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci/* 5898c2ecf20Sopenharmony_ci * Impose necessary and sufficient conditions on a devices's table such 5908c2ecf20Sopenharmony_ci * that any incoming bio which respects its logical_block_size can be 5918c2ecf20Sopenharmony_ci * processed successfully. If it falls across the boundary between 5928c2ecf20Sopenharmony_ci * two or more targets, the size of each piece it gets split into must 5938c2ecf20Sopenharmony_ci * be compatible with the logical_block_size of the target processing it. 5948c2ecf20Sopenharmony_ci */ 5958c2ecf20Sopenharmony_cistatic int validate_hardware_logical_block_alignment(struct dm_table *table, 5968c2ecf20Sopenharmony_ci struct queue_limits *limits) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci /* 5998c2ecf20Sopenharmony_ci * This function uses arithmetic modulo the logical_block_size 6008c2ecf20Sopenharmony_ci * (in units of 512-byte sectors). 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_ci unsigned short device_logical_block_size_sects = 6038c2ecf20Sopenharmony_ci limits->logical_block_size >> SECTOR_SHIFT; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* 6068c2ecf20Sopenharmony_ci * Offset of the start of the next table entry, mod logical_block_size. 6078c2ecf20Sopenharmony_ci */ 6088c2ecf20Sopenharmony_ci unsigned short next_target_start = 0; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* 6118c2ecf20Sopenharmony_ci * Given an aligned bio that extends beyond the end of a 6128c2ecf20Sopenharmony_ci * target, how many sectors must the next target handle? 6138c2ecf20Sopenharmony_ci */ 6148c2ecf20Sopenharmony_ci unsigned short remaining = 0; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci struct dm_target *ti; 6178c2ecf20Sopenharmony_ci struct queue_limits ti_limits; 6188c2ecf20Sopenharmony_ci unsigned i; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* 6218c2ecf20Sopenharmony_ci * Check each entry in the table in turn. 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_ci for (i = 0; i < dm_table_get_num_targets(table); i++) { 6248c2ecf20Sopenharmony_ci ti = dm_table_get_target(table, i); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci blk_set_stacking_limits(&ti_limits); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* combine all target devices' limits */ 6298c2ecf20Sopenharmony_ci if (ti->type->iterate_devices) 6308c2ecf20Sopenharmony_ci ti->type->iterate_devices(ti, dm_set_device_limits, 6318c2ecf20Sopenharmony_ci &ti_limits); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* 6348c2ecf20Sopenharmony_ci * If the remaining sectors fall entirely within this 6358c2ecf20Sopenharmony_ci * table entry are they compatible with its logical_block_size? 6368c2ecf20Sopenharmony_ci */ 6378c2ecf20Sopenharmony_ci if (remaining < ti->len && 6388c2ecf20Sopenharmony_ci remaining & ((ti_limits.logical_block_size >> 6398c2ecf20Sopenharmony_ci SECTOR_SHIFT) - 1)) 6408c2ecf20Sopenharmony_ci break; /* Error */ 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci next_target_start = 6438c2ecf20Sopenharmony_ci (unsigned short) ((next_target_start + ti->len) & 6448c2ecf20Sopenharmony_ci (device_logical_block_size_sects - 1)); 6458c2ecf20Sopenharmony_ci remaining = next_target_start ? 6468c2ecf20Sopenharmony_ci device_logical_block_size_sects - next_target_start : 0; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci if (remaining) { 6508c2ecf20Sopenharmony_ci DMWARN("%s: table line %u (start sect %llu len %llu) " 6518c2ecf20Sopenharmony_ci "not aligned to h/w logical block size %u", 6528c2ecf20Sopenharmony_ci dm_device_name(table->md), i, 6538c2ecf20Sopenharmony_ci (unsigned long long) ti->begin, 6548c2ecf20Sopenharmony_ci (unsigned long long) ti->len, 6558c2ecf20Sopenharmony_ci limits->logical_block_size); 6568c2ecf20Sopenharmony_ci return -EINVAL; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci return 0; 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ciint dm_table_add_target(struct dm_table *t, const char *type, 6638c2ecf20Sopenharmony_ci sector_t start, sector_t len, char *params) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci int r = -EINVAL, argc; 6668c2ecf20Sopenharmony_ci char **argv; 6678c2ecf20Sopenharmony_ci struct dm_target *tgt; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (t->singleton) { 6708c2ecf20Sopenharmony_ci DMERR("%s: target type %s must appear alone in table", 6718c2ecf20Sopenharmony_ci dm_device_name(t->md), t->targets->type->name); 6728c2ecf20Sopenharmony_ci return -EINVAL; 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci BUG_ON(t->num_targets >= t->num_allocated); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci tgt = t->targets + t->num_targets; 6788c2ecf20Sopenharmony_ci memset(tgt, 0, sizeof(*tgt)); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (!len) { 6818c2ecf20Sopenharmony_ci DMERR("%s: zero-length target", dm_device_name(t->md)); 6828c2ecf20Sopenharmony_ci return -EINVAL; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci tgt->type = dm_get_target_type(type); 6868c2ecf20Sopenharmony_ci if (!tgt->type) { 6878c2ecf20Sopenharmony_ci DMERR("%s: %s: unknown target type", dm_device_name(t->md), type); 6888c2ecf20Sopenharmony_ci return -EINVAL; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci if (dm_target_needs_singleton(tgt->type)) { 6928c2ecf20Sopenharmony_ci if (t->num_targets) { 6938c2ecf20Sopenharmony_ci tgt->error = "singleton target type must appear alone in table"; 6948c2ecf20Sopenharmony_ci goto bad; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci t->singleton = true; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci if (dm_target_always_writeable(tgt->type) && !(t->mode & FMODE_WRITE)) { 7008c2ecf20Sopenharmony_ci tgt->error = "target type may not be included in a read-only table"; 7018c2ecf20Sopenharmony_ci goto bad; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci if (t->immutable_target_type) { 7058c2ecf20Sopenharmony_ci if (t->immutable_target_type != tgt->type) { 7068c2ecf20Sopenharmony_ci tgt->error = "immutable target type cannot be mixed with other target types"; 7078c2ecf20Sopenharmony_ci goto bad; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci } else if (dm_target_is_immutable(tgt->type)) { 7108c2ecf20Sopenharmony_ci if (t->num_targets) { 7118c2ecf20Sopenharmony_ci tgt->error = "immutable target type cannot be mixed with other target types"; 7128c2ecf20Sopenharmony_ci goto bad; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci t->immutable_target_type = tgt->type; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (dm_target_has_integrity(tgt->type)) 7188c2ecf20Sopenharmony_ci t->integrity_added = 1; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci tgt->table = t; 7218c2ecf20Sopenharmony_ci tgt->begin = start; 7228c2ecf20Sopenharmony_ci tgt->len = len; 7238c2ecf20Sopenharmony_ci tgt->error = "Unknown error"; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci /* 7268c2ecf20Sopenharmony_ci * Does this target adjoin the previous one ? 7278c2ecf20Sopenharmony_ci */ 7288c2ecf20Sopenharmony_ci if (!adjoin(t, tgt)) { 7298c2ecf20Sopenharmony_ci tgt->error = "Gap in table"; 7308c2ecf20Sopenharmony_ci goto bad; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci r = dm_split_args(&argc, &argv, params); 7348c2ecf20Sopenharmony_ci if (r) { 7358c2ecf20Sopenharmony_ci tgt->error = "couldn't split parameters (insufficient memory)"; 7368c2ecf20Sopenharmony_ci goto bad; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci r = tgt->type->ctr(tgt, argc, argv); 7408c2ecf20Sopenharmony_ci kfree(argv); 7418c2ecf20Sopenharmony_ci if (r) 7428c2ecf20Sopenharmony_ci goto bad; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci t->highs[t->num_targets++] = tgt->begin + tgt->len - 1; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (!tgt->num_discard_bios && tgt->discards_supported) 7478c2ecf20Sopenharmony_ci DMWARN("%s: %s: ignoring discards_supported because num_discard_bios is zero.", 7488c2ecf20Sopenharmony_ci dm_device_name(t->md), type); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci return 0; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci bad: 7538c2ecf20Sopenharmony_ci DMERR("%s: %s: %s", dm_device_name(t->md), type, tgt->error); 7548c2ecf20Sopenharmony_ci dm_put_target_type(tgt->type); 7558c2ecf20Sopenharmony_ci return r; 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci/* 7598c2ecf20Sopenharmony_ci * Target argument parsing helpers. 7608c2ecf20Sopenharmony_ci */ 7618c2ecf20Sopenharmony_cistatic int validate_next_arg(const struct dm_arg *arg, 7628c2ecf20Sopenharmony_ci struct dm_arg_set *arg_set, 7638c2ecf20Sopenharmony_ci unsigned *value, char **error, unsigned grouped) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci const char *arg_str = dm_shift_arg(arg_set); 7668c2ecf20Sopenharmony_ci char dummy; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (!arg_str || 7698c2ecf20Sopenharmony_ci (sscanf(arg_str, "%u%c", value, &dummy) != 1) || 7708c2ecf20Sopenharmony_ci (*value < arg->min) || 7718c2ecf20Sopenharmony_ci (*value > arg->max) || 7728c2ecf20Sopenharmony_ci (grouped && arg_set->argc < *value)) { 7738c2ecf20Sopenharmony_ci *error = arg->error; 7748c2ecf20Sopenharmony_ci return -EINVAL; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci return 0; 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ciint dm_read_arg(const struct dm_arg *arg, struct dm_arg_set *arg_set, 7818c2ecf20Sopenharmony_ci unsigned *value, char **error) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci return validate_next_arg(arg, arg_set, value, error, 0); 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_read_arg); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ciint dm_read_arg_group(const struct dm_arg *arg, struct dm_arg_set *arg_set, 7888c2ecf20Sopenharmony_ci unsigned *value, char **error) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci return validate_next_arg(arg, arg_set, value, error, 1); 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_read_arg_group); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ciconst char *dm_shift_arg(struct dm_arg_set *as) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci char *r; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci if (as->argc) { 7998c2ecf20Sopenharmony_ci as->argc--; 8008c2ecf20Sopenharmony_ci r = *as->argv; 8018c2ecf20Sopenharmony_ci as->argv++; 8028c2ecf20Sopenharmony_ci return r; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return NULL; 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_shift_arg); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_civoid dm_consume_args(struct dm_arg_set *as, unsigned num_args) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci BUG_ON(as->argc < num_args); 8128c2ecf20Sopenharmony_ci as->argc -= num_args; 8138c2ecf20Sopenharmony_ci as->argv += num_args; 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_consume_args); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic bool __table_type_bio_based(enum dm_queue_mode table_type) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci return (table_type == DM_TYPE_BIO_BASED || 8208c2ecf20Sopenharmony_ci table_type == DM_TYPE_DAX_BIO_BASED); 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_cistatic bool __table_type_request_based(enum dm_queue_mode table_type) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci return table_type == DM_TYPE_REQUEST_BASED; 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_civoid dm_table_set_type(struct dm_table *t, enum dm_queue_mode type) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci t->type = type; 8318c2ecf20Sopenharmony_ci} 8328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_table_set_type); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci/* validate the dax capability of the target device span */ 8358c2ecf20Sopenharmony_ciint device_not_dax_capable(struct dm_target *ti, struct dm_dev *dev, 8368c2ecf20Sopenharmony_ci sector_t start, sector_t len, void *data) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci int blocksize = *(int *) data, id; 8398c2ecf20Sopenharmony_ci bool rc; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci id = dax_read_lock(); 8428c2ecf20Sopenharmony_ci rc = !dax_supported(dev->dax_dev, dev->bdev, blocksize, start, len); 8438c2ecf20Sopenharmony_ci dax_read_unlock(id); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci return rc; 8468c2ecf20Sopenharmony_ci} 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci/* Check devices support synchronous DAX */ 8498c2ecf20Sopenharmony_cistatic int device_not_dax_synchronous_capable(struct dm_target *ti, struct dm_dev *dev, 8508c2ecf20Sopenharmony_ci sector_t start, sector_t len, void *data) 8518c2ecf20Sopenharmony_ci{ 8528c2ecf20Sopenharmony_ci return !dev->dax_dev || !dax_synchronous(dev->dax_dev); 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_cibool dm_table_supports_dax(struct dm_table *t, 8568c2ecf20Sopenharmony_ci iterate_devices_callout_fn iterate_fn, int *blocksize) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci struct dm_target *ti; 8598c2ecf20Sopenharmony_ci unsigned i; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci /* Ensure that all targets support DAX. */ 8628c2ecf20Sopenharmony_ci for (i = 0; i < dm_table_get_num_targets(t); i++) { 8638c2ecf20Sopenharmony_ci ti = dm_table_get_target(t, i); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (!ti->type->direct_access) 8668c2ecf20Sopenharmony_ci return false; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (!ti->type->iterate_devices || 8698c2ecf20Sopenharmony_ci ti->type->iterate_devices(ti, iterate_fn, blocksize)) 8708c2ecf20Sopenharmony_ci return false; 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci return true; 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic int device_is_rq_stackable(struct dm_target *ti, struct dm_dev *dev, 8778c2ecf20Sopenharmony_ci sector_t start, sector_t len, void *data) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci struct block_device *bdev = dev->bdev; 8808c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(bdev); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* request-based cannot stack on partitions! */ 8838c2ecf20Sopenharmony_ci if (bdev_is_partition(bdev)) 8848c2ecf20Sopenharmony_ci return false; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci return queue_is_mq(q); 8878c2ecf20Sopenharmony_ci} 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_cistatic int dm_table_determine_type(struct dm_table *t) 8908c2ecf20Sopenharmony_ci{ 8918c2ecf20Sopenharmony_ci unsigned i; 8928c2ecf20Sopenharmony_ci unsigned bio_based = 0, request_based = 0, hybrid = 0; 8938c2ecf20Sopenharmony_ci struct dm_target *tgt; 8948c2ecf20Sopenharmony_ci struct list_head *devices = dm_table_get_devices(t); 8958c2ecf20Sopenharmony_ci enum dm_queue_mode live_md_type = dm_get_md_type(t->md); 8968c2ecf20Sopenharmony_ci int page_size = PAGE_SIZE; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (t->type != DM_TYPE_NONE) { 8998c2ecf20Sopenharmony_ci /* target already set the table's type */ 9008c2ecf20Sopenharmony_ci if (t->type == DM_TYPE_BIO_BASED) { 9018c2ecf20Sopenharmony_ci /* possibly upgrade to a variant of bio-based */ 9028c2ecf20Sopenharmony_ci goto verify_bio_based; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci BUG_ON(t->type == DM_TYPE_DAX_BIO_BASED); 9058c2ecf20Sopenharmony_ci goto verify_rq_based; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci for (i = 0; i < t->num_targets; i++) { 9098c2ecf20Sopenharmony_ci tgt = t->targets + i; 9108c2ecf20Sopenharmony_ci if (dm_target_hybrid(tgt)) 9118c2ecf20Sopenharmony_ci hybrid = 1; 9128c2ecf20Sopenharmony_ci else if (dm_target_request_based(tgt)) 9138c2ecf20Sopenharmony_ci request_based = 1; 9148c2ecf20Sopenharmony_ci else 9158c2ecf20Sopenharmony_ci bio_based = 1; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci if (bio_based && request_based) { 9188c2ecf20Sopenharmony_ci DMERR("Inconsistent table: different target types" 9198c2ecf20Sopenharmony_ci " can't be mixed up"); 9208c2ecf20Sopenharmony_ci return -EINVAL; 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci if (hybrid && !bio_based && !request_based) { 9258c2ecf20Sopenharmony_ci /* 9268c2ecf20Sopenharmony_ci * The targets can work either way. 9278c2ecf20Sopenharmony_ci * Determine the type from the live device. 9288c2ecf20Sopenharmony_ci * Default to bio-based if device is new. 9298c2ecf20Sopenharmony_ci */ 9308c2ecf20Sopenharmony_ci if (__table_type_request_based(live_md_type)) 9318c2ecf20Sopenharmony_ci request_based = 1; 9328c2ecf20Sopenharmony_ci else 9338c2ecf20Sopenharmony_ci bio_based = 1; 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (bio_based) { 9378c2ecf20Sopenharmony_civerify_bio_based: 9388c2ecf20Sopenharmony_ci /* We must use this table as bio-based */ 9398c2ecf20Sopenharmony_ci t->type = DM_TYPE_BIO_BASED; 9408c2ecf20Sopenharmony_ci if (dm_table_supports_dax(t, device_not_dax_capable, &page_size) || 9418c2ecf20Sopenharmony_ci (list_empty(devices) && live_md_type == DM_TYPE_DAX_BIO_BASED)) { 9428c2ecf20Sopenharmony_ci t->type = DM_TYPE_DAX_BIO_BASED; 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci return 0; 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci BUG_ON(!request_based); /* No targets in this table */ 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci t->type = DM_TYPE_REQUEST_BASED; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_civerify_rq_based: 9528c2ecf20Sopenharmony_ci /* 9538c2ecf20Sopenharmony_ci * Request-based dm supports only tables that have a single target now. 9548c2ecf20Sopenharmony_ci * To support multiple targets, request splitting support is needed, 9558c2ecf20Sopenharmony_ci * and that needs lots of changes in the block-layer. 9568c2ecf20Sopenharmony_ci * (e.g. request completion process for partial completion.) 9578c2ecf20Sopenharmony_ci */ 9588c2ecf20Sopenharmony_ci if (t->num_targets > 1) { 9598c2ecf20Sopenharmony_ci DMERR("request-based DM doesn't support multiple targets"); 9608c2ecf20Sopenharmony_ci return -EINVAL; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci if (list_empty(devices)) { 9648c2ecf20Sopenharmony_ci int srcu_idx; 9658c2ecf20Sopenharmony_ci struct dm_table *live_table = dm_get_live_table(t->md, &srcu_idx); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci /* inherit live table's type */ 9688c2ecf20Sopenharmony_ci if (live_table) 9698c2ecf20Sopenharmony_ci t->type = live_table->type; 9708c2ecf20Sopenharmony_ci dm_put_live_table(t->md, srcu_idx); 9718c2ecf20Sopenharmony_ci return 0; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci tgt = dm_table_get_immutable_target(t); 9758c2ecf20Sopenharmony_ci if (!tgt) { 9768c2ecf20Sopenharmony_ci DMERR("table load rejected: immutable target is required"); 9778c2ecf20Sopenharmony_ci return -EINVAL; 9788c2ecf20Sopenharmony_ci } else if (tgt->max_io_len) { 9798c2ecf20Sopenharmony_ci DMERR("table load rejected: immutable target that splits IO is not supported"); 9808c2ecf20Sopenharmony_ci return -EINVAL; 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci /* Non-request-stackable devices can't be used for request-based dm */ 9848c2ecf20Sopenharmony_ci if (!tgt->type->iterate_devices || 9858c2ecf20Sopenharmony_ci !tgt->type->iterate_devices(tgt, device_is_rq_stackable, NULL)) { 9868c2ecf20Sopenharmony_ci DMERR("table load rejected: including non-request-stackable devices"); 9878c2ecf20Sopenharmony_ci return -EINVAL; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci return 0; 9918c2ecf20Sopenharmony_ci} 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_cienum dm_queue_mode dm_table_get_type(struct dm_table *t) 9948c2ecf20Sopenharmony_ci{ 9958c2ecf20Sopenharmony_ci return t->type; 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistruct target_type *dm_table_get_immutable_target_type(struct dm_table *t) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci return t->immutable_target_type; 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_cistruct dm_target *dm_table_get_immutable_target(struct dm_table *t) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci /* Immutable target is implicitly a singleton */ 10068c2ecf20Sopenharmony_ci if (t->num_targets > 1 || 10078c2ecf20Sopenharmony_ci !dm_target_is_immutable(t->targets[0].type)) 10088c2ecf20Sopenharmony_ci return NULL; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci return t->targets; 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_cistruct dm_target *dm_table_get_wildcard_target(struct dm_table *t) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci struct dm_target *ti; 10168c2ecf20Sopenharmony_ci unsigned i; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci for (i = 0; i < dm_table_get_num_targets(t); i++) { 10198c2ecf20Sopenharmony_ci ti = dm_table_get_target(t, i); 10208c2ecf20Sopenharmony_ci if (dm_target_is_wildcard(ti->type)) 10218c2ecf20Sopenharmony_ci return ti; 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci return NULL; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_cibool dm_table_bio_based(struct dm_table *t) 10288c2ecf20Sopenharmony_ci{ 10298c2ecf20Sopenharmony_ci return __table_type_bio_based(dm_table_get_type(t)); 10308c2ecf20Sopenharmony_ci} 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_cibool dm_table_request_based(struct dm_table *t) 10338c2ecf20Sopenharmony_ci{ 10348c2ecf20Sopenharmony_ci return __table_type_request_based(dm_table_get_type(t)); 10358c2ecf20Sopenharmony_ci} 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_cistatic int dm_table_alloc_md_mempools(struct dm_table *t, struct mapped_device *md) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci enum dm_queue_mode type = dm_table_get_type(t); 10408c2ecf20Sopenharmony_ci unsigned per_io_data_size = 0; 10418c2ecf20Sopenharmony_ci unsigned min_pool_size = 0; 10428c2ecf20Sopenharmony_ci struct dm_target *ti; 10438c2ecf20Sopenharmony_ci unsigned i; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (unlikely(type == DM_TYPE_NONE)) { 10468c2ecf20Sopenharmony_ci DMWARN("no table type is set, can't allocate mempools"); 10478c2ecf20Sopenharmony_ci return -EINVAL; 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci if (__table_type_bio_based(type)) 10518c2ecf20Sopenharmony_ci for (i = 0; i < t->num_targets; i++) { 10528c2ecf20Sopenharmony_ci ti = t->targets + i; 10538c2ecf20Sopenharmony_ci per_io_data_size = max(per_io_data_size, ti->per_io_data_size); 10548c2ecf20Sopenharmony_ci min_pool_size = max(min_pool_size, ti->num_flush_bios); 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci t->mempools = dm_alloc_md_mempools(md, type, t->integrity_supported, 10588c2ecf20Sopenharmony_ci per_io_data_size, min_pool_size); 10598c2ecf20Sopenharmony_ci if (!t->mempools) 10608c2ecf20Sopenharmony_ci return -ENOMEM; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci return 0; 10638c2ecf20Sopenharmony_ci} 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_civoid dm_table_free_md_mempools(struct dm_table *t) 10668c2ecf20Sopenharmony_ci{ 10678c2ecf20Sopenharmony_ci dm_free_md_mempools(t->mempools); 10688c2ecf20Sopenharmony_ci t->mempools = NULL; 10698c2ecf20Sopenharmony_ci} 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_cistruct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t) 10728c2ecf20Sopenharmony_ci{ 10738c2ecf20Sopenharmony_ci return t->mempools; 10748c2ecf20Sopenharmony_ci} 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_cistatic int setup_indexes(struct dm_table *t) 10778c2ecf20Sopenharmony_ci{ 10788c2ecf20Sopenharmony_ci int i; 10798c2ecf20Sopenharmony_ci unsigned int total = 0; 10808c2ecf20Sopenharmony_ci sector_t *indexes; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci /* allocate the space for *all* the indexes */ 10838c2ecf20Sopenharmony_ci for (i = t->depth - 2; i >= 0; i--) { 10848c2ecf20Sopenharmony_ci t->counts[i] = dm_div_up(t->counts[i + 1], CHILDREN_PER_NODE); 10858c2ecf20Sopenharmony_ci total += t->counts[i]; 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci indexes = (sector_t *) dm_vcalloc(total, (unsigned long) NODE_SIZE); 10898c2ecf20Sopenharmony_ci if (!indexes) 10908c2ecf20Sopenharmony_ci return -ENOMEM; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci /* set up internal nodes, bottom-up */ 10938c2ecf20Sopenharmony_ci for (i = t->depth - 2; i >= 0; i--) { 10948c2ecf20Sopenharmony_ci t->index[i] = indexes; 10958c2ecf20Sopenharmony_ci indexes += (KEYS_PER_NODE * t->counts[i]); 10968c2ecf20Sopenharmony_ci setup_btree_index(i, t); 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci return 0; 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci/* 11038c2ecf20Sopenharmony_ci * Builds the btree to index the map. 11048c2ecf20Sopenharmony_ci */ 11058c2ecf20Sopenharmony_cistatic int dm_table_build_index(struct dm_table *t) 11068c2ecf20Sopenharmony_ci{ 11078c2ecf20Sopenharmony_ci int r = 0; 11088c2ecf20Sopenharmony_ci unsigned int leaf_nodes; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci /* how many indexes will the btree have ? */ 11118c2ecf20Sopenharmony_ci leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE); 11128c2ecf20Sopenharmony_ci t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci /* leaf layer has already been set up */ 11158c2ecf20Sopenharmony_ci t->counts[t->depth - 1] = leaf_nodes; 11168c2ecf20Sopenharmony_ci t->index[t->depth - 1] = t->highs; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci if (t->depth >= 2) 11198c2ecf20Sopenharmony_ci r = setup_indexes(t); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci return r; 11228c2ecf20Sopenharmony_ci} 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_cistatic bool integrity_profile_exists(struct gendisk *disk) 11258c2ecf20Sopenharmony_ci{ 11268c2ecf20Sopenharmony_ci return !!blk_get_integrity(disk); 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci/* 11308c2ecf20Sopenharmony_ci * Get a disk whose integrity profile reflects the table's profile. 11318c2ecf20Sopenharmony_ci * Returns NULL if integrity support was inconsistent or unavailable. 11328c2ecf20Sopenharmony_ci */ 11338c2ecf20Sopenharmony_cistatic struct gendisk * dm_table_get_integrity_disk(struct dm_table *t) 11348c2ecf20Sopenharmony_ci{ 11358c2ecf20Sopenharmony_ci struct list_head *devices = dm_table_get_devices(t); 11368c2ecf20Sopenharmony_ci struct dm_dev_internal *dd = NULL; 11378c2ecf20Sopenharmony_ci struct gendisk *prev_disk = NULL, *template_disk = NULL; 11388c2ecf20Sopenharmony_ci unsigned i; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci for (i = 0; i < dm_table_get_num_targets(t); i++) { 11418c2ecf20Sopenharmony_ci struct dm_target *ti = dm_table_get_target(t, i); 11428c2ecf20Sopenharmony_ci if (!dm_target_passes_integrity(ti->type)) 11438c2ecf20Sopenharmony_ci goto no_integrity; 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci list_for_each_entry(dd, devices, list) { 11478c2ecf20Sopenharmony_ci template_disk = dd->dm_dev->bdev->bd_disk; 11488c2ecf20Sopenharmony_ci if (!integrity_profile_exists(template_disk)) 11498c2ecf20Sopenharmony_ci goto no_integrity; 11508c2ecf20Sopenharmony_ci else if (prev_disk && 11518c2ecf20Sopenharmony_ci blk_integrity_compare(prev_disk, template_disk) < 0) 11528c2ecf20Sopenharmony_ci goto no_integrity; 11538c2ecf20Sopenharmony_ci prev_disk = template_disk; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci return template_disk; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cino_integrity: 11598c2ecf20Sopenharmony_ci if (prev_disk) 11608c2ecf20Sopenharmony_ci DMWARN("%s: integrity not set: %s and %s profile mismatch", 11618c2ecf20Sopenharmony_ci dm_device_name(t->md), 11628c2ecf20Sopenharmony_ci prev_disk->disk_name, 11638c2ecf20Sopenharmony_ci template_disk->disk_name); 11648c2ecf20Sopenharmony_ci return NULL; 11658c2ecf20Sopenharmony_ci} 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci/* 11688c2ecf20Sopenharmony_ci * Register the mapped device for blk_integrity support if the 11698c2ecf20Sopenharmony_ci * underlying devices have an integrity profile. But all devices may 11708c2ecf20Sopenharmony_ci * not have matching profiles (checking all devices isn't reliable 11718c2ecf20Sopenharmony_ci * during table load because this table may use other DM device(s) which 11728c2ecf20Sopenharmony_ci * must be resumed before they will have an initialized integity 11738c2ecf20Sopenharmony_ci * profile). Consequently, stacked DM devices force a 2 stage integrity 11748c2ecf20Sopenharmony_ci * profile validation: First pass during table load, final pass during 11758c2ecf20Sopenharmony_ci * resume. 11768c2ecf20Sopenharmony_ci */ 11778c2ecf20Sopenharmony_cistatic int dm_table_register_integrity(struct dm_table *t) 11788c2ecf20Sopenharmony_ci{ 11798c2ecf20Sopenharmony_ci struct mapped_device *md = t->md; 11808c2ecf20Sopenharmony_ci struct gendisk *template_disk = NULL; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci /* If target handles integrity itself do not register it here. */ 11838c2ecf20Sopenharmony_ci if (t->integrity_added) 11848c2ecf20Sopenharmony_ci return 0; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci template_disk = dm_table_get_integrity_disk(t); 11878c2ecf20Sopenharmony_ci if (!template_disk) 11888c2ecf20Sopenharmony_ci return 0; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci if (!integrity_profile_exists(dm_disk(md))) { 11918c2ecf20Sopenharmony_ci t->integrity_supported = true; 11928c2ecf20Sopenharmony_ci /* 11938c2ecf20Sopenharmony_ci * Register integrity profile during table load; we can do 11948c2ecf20Sopenharmony_ci * this because the final profile must match during resume. 11958c2ecf20Sopenharmony_ci */ 11968c2ecf20Sopenharmony_ci blk_integrity_register(dm_disk(md), 11978c2ecf20Sopenharmony_ci blk_get_integrity(template_disk)); 11988c2ecf20Sopenharmony_ci return 0; 11998c2ecf20Sopenharmony_ci } 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci /* 12028c2ecf20Sopenharmony_ci * If DM device already has an initialized integrity 12038c2ecf20Sopenharmony_ci * profile the new profile should not conflict. 12048c2ecf20Sopenharmony_ci */ 12058c2ecf20Sopenharmony_ci if (blk_integrity_compare(dm_disk(md), template_disk) < 0) { 12068c2ecf20Sopenharmony_ci DMWARN("%s: conflict with existing integrity profile: " 12078c2ecf20Sopenharmony_ci "%s profile mismatch", 12088c2ecf20Sopenharmony_ci dm_device_name(t->md), 12098c2ecf20Sopenharmony_ci template_disk->disk_name); 12108c2ecf20Sopenharmony_ci return 1; 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci /* Preserve existing integrity profile */ 12148c2ecf20Sopenharmony_ci t->integrity_supported = true; 12158c2ecf20Sopenharmony_ci return 0; 12168c2ecf20Sopenharmony_ci} 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci/* 12198c2ecf20Sopenharmony_ci * Prepares the table for use by building the indices, 12208c2ecf20Sopenharmony_ci * setting the type, and allocating mempools. 12218c2ecf20Sopenharmony_ci */ 12228c2ecf20Sopenharmony_ciint dm_table_complete(struct dm_table *t) 12238c2ecf20Sopenharmony_ci{ 12248c2ecf20Sopenharmony_ci int r; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci r = dm_table_determine_type(t); 12278c2ecf20Sopenharmony_ci if (r) { 12288c2ecf20Sopenharmony_ci DMERR("unable to determine table type"); 12298c2ecf20Sopenharmony_ci return r; 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci r = dm_table_build_index(t); 12338c2ecf20Sopenharmony_ci if (r) { 12348c2ecf20Sopenharmony_ci DMERR("unable to build btrees"); 12358c2ecf20Sopenharmony_ci return r; 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci r = dm_table_register_integrity(t); 12398c2ecf20Sopenharmony_ci if (r) { 12408c2ecf20Sopenharmony_ci DMERR("could not register integrity profile."); 12418c2ecf20Sopenharmony_ci return r; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci r = dm_table_alloc_md_mempools(t, t->md); 12458c2ecf20Sopenharmony_ci if (r) 12468c2ecf20Sopenharmony_ci DMERR("unable to allocate mempools"); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci return r; 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(_event_lock); 12528c2ecf20Sopenharmony_civoid dm_table_event_callback(struct dm_table *t, 12538c2ecf20Sopenharmony_ci void (*fn)(void *), void *context) 12548c2ecf20Sopenharmony_ci{ 12558c2ecf20Sopenharmony_ci mutex_lock(&_event_lock); 12568c2ecf20Sopenharmony_ci t->event_fn = fn; 12578c2ecf20Sopenharmony_ci t->event_context = context; 12588c2ecf20Sopenharmony_ci mutex_unlock(&_event_lock); 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_civoid dm_table_event(struct dm_table *t) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci mutex_lock(&_event_lock); 12648c2ecf20Sopenharmony_ci if (t->event_fn) 12658c2ecf20Sopenharmony_ci t->event_fn(t->event_context); 12668c2ecf20Sopenharmony_ci mutex_unlock(&_event_lock); 12678c2ecf20Sopenharmony_ci} 12688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_table_event); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ciinline sector_t dm_table_get_size(struct dm_table *t) 12718c2ecf20Sopenharmony_ci{ 12728c2ecf20Sopenharmony_ci return t->num_targets ? (t->highs[t->num_targets - 1] + 1) : 0; 12738c2ecf20Sopenharmony_ci} 12748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_table_get_size); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_cistruct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index) 12778c2ecf20Sopenharmony_ci{ 12788c2ecf20Sopenharmony_ci if (index >= t->num_targets) 12798c2ecf20Sopenharmony_ci return NULL; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci return t->targets + index; 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci/* 12858c2ecf20Sopenharmony_ci * Search the btree for the correct target. 12868c2ecf20Sopenharmony_ci * 12878c2ecf20Sopenharmony_ci * Caller should check returned pointer for NULL 12888c2ecf20Sopenharmony_ci * to trap I/O beyond end of device. 12898c2ecf20Sopenharmony_ci */ 12908c2ecf20Sopenharmony_cistruct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector) 12918c2ecf20Sopenharmony_ci{ 12928c2ecf20Sopenharmony_ci unsigned int l, n = 0, k = 0; 12938c2ecf20Sopenharmony_ci sector_t *node; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci if (unlikely(sector >= dm_table_get_size(t))) 12968c2ecf20Sopenharmony_ci return NULL; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci for (l = 0; l < t->depth; l++) { 12998c2ecf20Sopenharmony_ci n = get_child(n, k); 13008c2ecf20Sopenharmony_ci node = get_node(t, l, n); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci for (k = 0; k < KEYS_PER_NODE; k++) 13038c2ecf20Sopenharmony_ci if (node[k] >= sector) 13048c2ecf20Sopenharmony_ci break; 13058c2ecf20Sopenharmony_ci } 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci return &t->targets[(KEYS_PER_NODE * n) + k]; 13088c2ecf20Sopenharmony_ci} 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci/* 13118c2ecf20Sopenharmony_ci * type->iterate_devices() should be called when the sanity check needs to 13128c2ecf20Sopenharmony_ci * iterate and check all underlying data devices. iterate_devices() will 13138c2ecf20Sopenharmony_ci * iterate all underlying data devices until it encounters a non-zero return 13148c2ecf20Sopenharmony_ci * code, returned by whether the input iterate_devices_callout_fn, or 13158c2ecf20Sopenharmony_ci * iterate_devices() itself internally. 13168c2ecf20Sopenharmony_ci * 13178c2ecf20Sopenharmony_ci * For some target type (e.g. dm-stripe), one call of iterate_devices() may 13188c2ecf20Sopenharmony_ci * iterate multiple underlying devices internally, in which case a non-zero 13198c2ecf20Sopenharmony_ci * return code returned by iterate_devices_callout_fn will stop the iteration 13208c2ecf20Sopenharmony_ci * in advance. 13218c2ecf20Sopenharmony_ci * 13228c2ecf20Sopenharmony_ci * Cases requiring _any_ underlying device supporting some kind of attribute, 13238c2ecf20Sopenharmony_ci * should use the iteration structure like dm_table_any_dev_attr(), or call 13248c2ecf20Sopenharmony_ci * it directly. @func should handle semantics of positive examples, e.g. 13258c2ecf20Sopenharmony_ci * capable of something. 13268c2ecf20Sopenharmony_ci * 13278c2ecf20Sopenharmony_ci * Cases requiring _all_ underlying devices supporting some kind of attribute, 13288c2ecf20Sopenharmony_ci * should use the iteration structure like dm_table_supports_nowait() or 13298c2ecf20Sopenharmony_ci * dm_table_supports_discards(). Or introduce dm_table_all_devs_attr() that 13308c2ecf20Sopenharmony_ci * uses an @anti_func that handle semantics of counter examples, e.g. not 13318c2ecf20Sopenharmony_ci * capable of something. So: return !dm_table_any_dev_attr(t, anti_func, data); 13328c2ecf20Sopenharmony_ci */ 13338c2ecf20Sopenharmony_cistatic bool dm_table_any_dev_attr(struct dm_table *t, 13348c2ecf20Sopenharmony_ci iterate_devices_callout_fn func, void *data) 13358c2ecf20Sopenharmony_ci{ 13368c2ecf20Sopenharmony_ci struct dm_target *ti; 13378c2ecf20Sopenharmony_ci unsigned int i; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci for (i = 0; i < dm_table_get_num_targets(t); i++) { 13408c2ecf20Sopenharmony_ci ti = dm_table_get_target(t, i); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci if (ti->type->iterate_devices && 13438c2ecf20Sopenharmony_ci ti->type->iterate_devices(ti, func, data)) 13448c2ecf20Sopenharmony_ci return true; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci return false; 13488c2ecf20Sopenharmony_ci} 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_cistatic int count_device(struct dm_target *ti, struct dm_dev *dev, 13518c2ecf20Sopenharmony_ci sector_t start, sector_t len, void *data) 13528c2ecf20Sopenharmony_ci{ 13538c2ecf20Sopenharmony_ci unsigned *num_devices = data; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci (*num_devices)++; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci return 0; 13588c2ecf20Sopenharmony_ci} 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci/* 13618c2ecf20Sopenharmony_ci * Check whether a table has no data devices attached using each 13628c2ecf20Sopenharmony_ci * target's iterate_devices method. 13638c2ecf20Sopenharmony_ci * Returns false if the result is unknown because a target doesn't 13648c2ecf20Sopenharmony_ci * support iterate_devices. 13658c2ecf20Sopenharmony_ci */ 13668c2ecf20Sopenharmony_cibool dm_table_has_no_data_devices(struct dm_table *table) 13678c2ecf20Sopenharmony_ci{ 13688c2ecf20Sopenharmony_ci struct dm_target *ti; 13698c2ecf20Sopenharmony_ci unsigned i, num_devices; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci for (i = 0; i < dm_table_get_num_targets(table); i++) { 13728c2ecf20Sopenharmony_ci ti = dm_table_get_target(table, i); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci if (!ti->type->iterate_devices) 13758c2ecf20Sopenharmony_ci return false; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci num_devices = 0; 13788c2ecf20Sopenharmony_ci ti->type->iterate_devices(ti, count_device, &num_devices); 13798c2ecf20Sopenharmony_ci if (num_devices) 13808c2ecf20Sopenharmony_ci return false; 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci return true; 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cistatic int device_not_zoned_model(struct dm_target *ti, struct dm_dev *dev, 13878c2ecf20Sopenharmony_ci sector_t start, sector_t len, void *data) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(dev->bdev); 13908c2ecf20Sopenharmony_ci enum blk_zoned_model *zoned_model = data; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci return !q || blk_queue_zoned_model(q) != *zoned_model; 13938c2ecf20Sopenharmony_ci} 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci/* 13968c2ecf20Sopenharmony_ci * Check the device zoned model based on the target feature flag. If the target 13978c2ecf20Sopenharmony_ci * has the DM_TARGET_ZONED_HM feature flag set, host-managed zoned devices are 13988c2ecf20Sopenharmony_ci * also accepted but all devices must have the same zoned model. If the target 13998c2ecf20Sopenharmony_ci * has the DM_TARGET_MIXED_ZONED_MODEL feature set, the devices can have any 14008c2ecf20Sopenharmony_ci * zoned model with all zoned devices having the same zone size. 14018c2ecf20Sopenharmony_ci */ 14028c2ecf20Sopenharmony_cistatic bool dm_table_supports_zoned_model(struct dm_table *t, 14038c2ecf20Sopenharmony_ci enum blk_zoned_model zoned_model) 14048c2ecf20Sopenharmony_ci{ 14058c2ecf20Sopenharmony_ci struct dm_target *ti; 14068c2ecf20Sopenharmony_ci unsigned i; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci for (i = 0; i < dm_table_get_num_targets(t); i++) { 14098c2ecf20Sopenharmony_ci ti = dm_table_get_target(t, i); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci if (dm_target_supports_zoned_hm(ti->type)) { 14128c2ecf20Sopenharmony_ci if (!ti->type->iterate_devices || 14138c2ecf20Sopenharmony_ci ti->type->iterate_devices(ti, device_not_zoned_model, 14148c2ecf20Sopenharmony_ci &zoned_model)) 14158c2ecf20Sopenharmony_ci return false; 14168c2ecf20Sopenharmony_ci } else if (!dm_target_supports_mixed_zoned_model(ti->type)) { 14178c2ecf20Sopenharmony_ci if (zoned_model == BLK_ZONED_HM) 14188c2ecf20Sopenharmony_ci return false; 14198c2ecf20Sopenharmony_ci } 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci return true; 14238c2ecf20Sopenharmony_ci} 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_cistatic int device_not_matches_zone_sectors(struct dm_target *ti, struct dm_dev *dev, 14268c2ecf20Sopenharmony_ci sector_t start, sector_t len, void *data) 14278c2ecf20Sopenharmony_ci{ 14288c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(dev->bdev); 14298c2ecf20Sopenharmony_ci unsigned int *zone_sectors = data; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci if (!blk_queue_is_zoned(q)) 14328c2ecf20Sopenharmony_ci return 0; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci return !q || blk_queue_zone_sectors(q) != *zone_sectors; 14358c2ecf20Sopenharmony_ci} 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci/* 14388c2ecf20Sopenharmony_ci * Check consistency of zoned model and zone sectors across all targets. For 14398c2ecf20Sopenharmony_ci * zone sectors, if the destination device is a zoned block device, it shall 14408c2ecf20Sopenharmony_ci * have the specified zone_sectors. 14418c2ecf20Sopenharmony_ci */ 14428c2ecf20Sopenharmony_cistatic int validate_hardware_zoned_model(struct dm_table *table, 14438c2ecf20Sopenharmony_ci enum blk_zoned_model zoned_model, 14448c2ecf20Sopenharmony_ci unsigned int zone_sectors) 14458c2ecf20Sopenharmony_ci{ 14468c2ecf20Sopenharmony_ci if (zoned_model == BLK_ZONED_NONE) 14478c2ecf20Sopenharmony_ci return 0; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci if (!dm_table_supports_zoned_model(table, zoned_model)) { 14508c2ecf20Sopenharmony_ci DMERR("%s: zoned model is not consistent across all devices", 14518c2ecf20Sopenharmony_ci dm_device_name(table->md)); 14528c2ecf20Sopenharmony_ci return -EINVAL; 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci /* Check zone size validity and compatibility */ 14568c2ecf20Sopenharmony_ci if (!zone_sectors || !is_power_of_2(zone_sectors)) 14578c2ecf20Sopenharmony_ci return -EINVAL; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci if (dm_table_any_dev_attr(table, device_not_matches_zone_sectors, &zone_sectors)) { 14608c2ecf20Sopenharmony_ci DMERR("%s: zone sectors is not consistent across all zoned devices", 14618c2ecf20Sopenharmony_ci dm_device_name(table->md)); 14628c2ecf20Sopenharmony_ci return -EINVAL; 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci return 0; 14668c2ecf20Sopenharmony_ci} 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci/* 14698c2ecf20Sopenharmony_ci * Establish the new table's queue_limits and validate them. 14708c2ecf20Sopenharmony_ci */ 14718c2ecf20Sopenharmony_ciint dm_calculate_queue_limits(struct dm_table *table, 14728c2ecf20Sopenharmony_ci struct queue_limits *limits) 14738c2ecf20Sopenharmony_ci{ 14748c2ecf20Sopenharmony_ci struct dm_target *ti; 14758c2ecf20Sopenharmony_ci struct queue_limits ti_limits; 14768c2ecf20Sopenharmony_ci unsigned i; 14778c2ecf20Sopenharmony_ci enum blk_zoned_model zoned_model = BLK_ZONED_NONE; 14788c2ecf20Sopenharmony_ci unsigned int zone_sectors = 0; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci blk_set_stacking_limits(limits); 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci for (i = 0; i < dm_table_get_num_targets(table); i++) { 14838c2ecf20Sopenharmony_ci blk_set_stacking_limits(&ti_limits); 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci ti = dm_table_get_target(table, i); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci if (!ti->type->iterate_devices) 14888c2ecf20Sopenharmony_ci goto combine_limits; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci /* 14918c2ecf20Sopenharmony_ci * Combine queue limits of all the devices this target uses. 14928c2ecf20Sopenharmony_ci */ 14938c2ecf20Sopenharmony_ci ti->type->iterate_devices(ti, dm_set_device_limits, 14948c2ecf20Sopenharmony_ci &ti_limits); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci if (zoned_model == BLK_ZONED_NONE && ti_limits.zoned != BLK_ZONED_NONE) { 14978c2ecf20Sopenharmony_ci /* 14988c2ecf20Sopenharmony_ci * After stacking all limits, validate all devices 14998c2ecf20Sopenharmony_ci * in table support this zoned model and zone sectors. 15008c2ecf20Sopenharmony_ci */ 15018c2ecf20Sopenharmony_ci zoned_model = ti_limits.zoned; 15028c2ecf20Sopenharmony_ci zone_sectors = ti_limits.chunk_sectors; 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci /* Set I/O hints portion of queue limits */ 15068c2ecf20Sopenharmony_ci if (ti->type->io_hints) 15078c2ecf20Sopenharmony_ci ti->type->io_hints(ti, &ti_limits); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci /* 15108c2ecf20Sopenharmony_ci * Check each device area is consistent with the target's 15118c2ecf20Sopenharmony_ci * overall queue limits. 15128c2ecf20Sopenharmony_ci */ 15138c2ecf20Sopenharmony_ci if (ti->type->iterate_devices(ti, device_area_is_invalid, 15148c2ecf20Sopenharmony_ci &ti_limits)) 15158c2ecf20Sopenharmony_ci return -EINVAL; 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_cicombine_limits: 15188c2ecf20Sopenharmony_ci /* 15198c2ecf20Sopenharmony_ci * Merge this target's queue limits into the overall limits 15208c2ecf20Sopenharmony_ci * for the table. 15218c2ecf20Sopenharmony_ci */ 15228c2ecf20Sopenharmony_ci if (blk_stack_limits(limits, &ti_limits, 0) < 0) 15238c2ecf20Sopenharmony_ci DMWARN("%s: adding target device " 15248c2ecf20Sopenharmony_ci "(start sect %llu len %llu) " 15258c2ecf20Sopenharmony_ci "caused an alignment inconsistency", 15268c2ecf20Sopenharmony_ci dm_device_name(table->md), 15278c2ecf20Sopenharmony_ci (unsigned long long) ti->begin, 15288c2ecf20Sopenharmony_ci (unsigned long long) ti->len); 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci /* 15328c2ecf20Sopenharmony_ci * Verify that the zoned model and zone sectors, as determined before 15338c2ecf20Sopenharmony_ci * any .io_hints override, are the same across all devices in the table. 15348c2ecf20Sopenharmony_ci * - this is especially relevant if .io_hints is emulating a disk-managed 15358c2ecf20Sopenharmony_ci * zoned model (aka BLK_ZONED_NONE) on host-managed zoned block devices. 15368c2ecf20Sopenharmony_ci * BUT... 15378c2ecf20Sopenharmony_ci */ 15388c2ecf20Sopenharmony_ci if (limits->zoned != BLK_ZONED_NONE) { 15398c2ecf20Sopenharmony_ci /* 15408c2ecf20Sopenharmony_ci * ...IF the above limits stacking determined a zoned model 15418c2ecf20Sopenharmony_ci * validate that all of the table's devices conform to it. 15428c2ecf20Sopenharmony_ci */ 15438c2ecf20Sopenharmony_ci zoned_model = limits->zoned; 15448c2ecf20Sopenharmony_ci zone_sectors = limits->chunk_sectors; 15458c2ecf20Sopenharmony_ci } 15468c2ecf20Sopenharmony_ci if (validate_hardware_zoned_model(table, zoned_model, zone_sectors)) 15478c2ecf20Sopenharmony_ci return -EINVAL; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci return validate_hardware_logical_block_alignment(table, limits); 15508c2ecf20Sopenharmony_ci} 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci/* 15538c2ecf20Sopenharmony_ci * Verify that all devices have an integrity profile that matches the 15548c2ecf20Sopenharmony_ci * DM device's registered integrity profile. If the profiles don't 15558c2ecf20Sopenharmony_ci * match then unregister the DM device's integrity profile. 15568c2ecf20Sopenharmony_ci */ 15578c2ecf20Sopenharmony_cistatic void dm_table_verify_integrity(struct dm_table *t) 15588c2ecf20Sopenharmony_ci{ 15598c2ecf20Sopenharmony_ci struct gendisk *template_disk = NULL; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci if (t->integrity_added) 15628c2ecf20Sopenharmony_ci return; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci if (t->integrity_supported) { 15658c2ecf20Sopenharmony_ci /* 15668c2ecf20Sopenharmony_ci * Verify that the original integrity profile 15678c2ecf20Sopenharmony_ci * matches all the devices in this table. 15688c2ecf20Sopenharmony_ci */ 15698c2ecf20Sopenharmony_ci template_disk = dm_table_get_integrity_disk(t); 15708c2ecf20Sopenharmony_ci if (template_disk && 15718c2ecf20Sopenharmony_ci blk_integrity_compare(dm_disk(t->md), template_disk) >= 0) 15728c2ecf20Sopenharmony_ci return; 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci if (integrity_profile_exists(dm_disk(t->md))) { 15768c2ecf20Sopenharmony_ci DMWARN("%s: unable to establish an integrity profile", 15778c2ecf20Sopenharmony_ci dm_device_name(t->md)); 15788c2ecf20Sopenharmony_ci blk_integrity_unregister(dm_disk(t->md)); 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci} 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_cistatic int device_flush_capable(struct dm_target *ti, struct dm_dev *dev, 15838c2ecf20Sopenharmony_ci sector_t start, sector_t len, void *data) 15848c2ecf20Sopenharmony_ci{ 15858c2ecf20Sopenharmony_ci unsigned long flush = (unsigned long) data; 15868c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(dev->bdev); 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci return q && (q->queue_flags & flush); 15898c2ecf20Sopenharmony_ci} 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_cistatic bool dm_table_supports_flush(struct dm_table *t, unsigned long flush) 15928c2ecf20Sopenharmony_ci{ 15938c2ecf20Sopenharmony_ci struct dm_target *ti; 15948c2ecf20Sopenharmony_ci unsigned i; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci /* 15978c2ecf20Sopenharmony_ci * Require at least one underlying device to support flushes. 15988c2ecf20Sopenharmony_ci * t->devices includes internal dm devices such as mirror logs 15998c2ecf20Sopenharmony_ci * so we need to use iterate_devices here, which targets 16008c2ecf20Sopenharmony_ci * supporting flushes must provide. 16018c2ecf20Sopenharmony_ci */ 16028c2ecf20Sopenharmony_ci for (i = 0; i < dm_table_get_num_targets(t); i++) { 16038c2ecf20Sopenharmony_ci ti = dm_table_get_target(t, i); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci if (!ti->num_flush_bios) 16068c2ecf20Sopenharmony_ci continue; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci if (ti->flush_supported) 16098c2ecf20Sopenharmony_ci return true; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci if (ti->type->iterate_devices && 16128c2ecf20Sopenharmony_ci ti->type->iterate_devices(ti, device_flush_capable, (void *) flush)) 16138c2ecf20Sopenharmony_ci return true; 16148c2ecf20Sopenharmony_ci } 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci return false; 16178c2ecf20Sopenharmony_ci} 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_cistatic int device_dax_write_cache_enabled(struct dm_target *ti, 16208c2ecf20Sopenharmony_ci struct dm_dev *dev, sector_t start, 16218c2ecf20Sopenharmony_ci sector_t len, void *data) 16228c2ecf20Sopenharmony_ci{ 16238c2ecf20Sopenharmony_ci struct dax_device *dax_dev = dev->dax_dev; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci if (!dax_dev) 16268c2ecf20Sopenharmony_ci return false; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci if (dax_write_cache_enabled(dax_dev)) 16298c2ecf20Sopenharmony_ci return true; 16308c2ecf20Sopenharmony_ci return false; 16318c2ecf20Sopenharmony_ci} 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_cistatic int device_is_rotational(struct dm_target *ti, struct dm_dev *dev, 16348c2ecf20Sopenharmony_ci sector_t start, sector_t len, void *data) 16358c2ecf20Sopenharmony_ci{ 16368c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(dev->bdev); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci return q && !blk_queue_nonrot(q); 16398c2ecf20Sopenharmony_ci} 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_cistatic int device_is_not_random(struct dm_target *ti, struct dm_dev *dev, 16428c2ecf20Sopenharmony_ci sector_t start, sector_t len, void *data) 16438c2ecf20Sopenharmony_ci{ 16448c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(dev->bdev); 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci return q && !blk_queue_add_random(q); 16478c2ecf20Sopenharmony_ci} 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_cistatic int device_not_write_same_capable(struct dm_target *ti, struct dm_dev *dev, 16508c2ecf20Sopenharmony_ci sector_t start, sector_t len, void *data) 16518c2ecf20Sopenharmony_ci{ 16528c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(dev->bdev); 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci return q && !q->limits.max_write_same_sectors; 16558c2ecf20Sopenharmony_ci} 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_cistatic bool dm_table_supports_write_same(struct dm_table *t) 16588c2ecf20Sopenharmony_ci{ 16598c2ecf20Sopenharmony_ci struct dm_target *ti; 16608c2ecf20Sopenharmony_ci unsigned i; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci for (i = 0; i < dm_table_get_num_targets(t); i++) { 16638c2ecf20Sopenharmony_ci ti = dm_table_get_target(t, i); 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci if (!ti->num_write_same_bios) 16668c2ecf20Sopenharmony_ci return false; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci if (!ti->type->iterate_devices || 16698c2ecf20Sopenharmony_ci ti->type->iterate_devices(ti, device_not_write_same_capable, NULL)) 16708c2ecf20Sopenharmony_ci return false; 16718c2ecf20Sopenharmony_ci } 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci return true; 16748c2ecf20Sopenharmony_ci} 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_cistatic int device_not_write_zeroes_capable(struct dm_target *ti, struct dm_dev *dev, 16778c2ecf20Sopenharmony_ci sector_t start, sector_t len, void *data) 16788c2ecf20Sopenharmony_ci{ 16798c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(dev->bdev); 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci return q && !q->limits.max_write_zeroes_sectors; 16828c2ecf20Sopenharmony_ci} 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_cistatic bool dm_table_supports_write_zeroes(struct dm_table *t) 16858c2ecf20Sopenharmony_ci{ 16868c2ecf20Sopenharmony_ci struct dm_target *ti; 16878c2ecf20Sopenharmony_ci unsigned i = 0; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci while (i < dm_table_get_num_targets(t)) { 16908c2ecf20Sopenharmony_ci ti = dm_table_get_target(t, i++); 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci if (!ti->num_write_zeroes_bios) 16938c2ecf20Sopenharmony_ci return false; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci if (!ti->type->iterate_devices || 16968c2ecf20Sopenharmony_ci ti->type->iterate_devices(ti, device_not_write_zeroes_capable, NULL)) 16978c2ecf20Sopenharmony_ci return false; 16988c2ecf20Sopenharmony_ci } 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci return true; 17018c2ecf20Sopenharmony_ci} 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_cistatic int device_not_nowait_capable(struct dm_target *ti, struct dm_dev *dev, 17048c2ecf20Sopenharmony_ci sector_t start, sector_t len, void *data) 17058c2ecf20Sopenharmony_ci{ 17068c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(dev->bdev); 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci return q && !blk_queue_nowait(q); 17098c2ecf20Sopenharmony_ci} 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_cistatic bool dm_table_supports_nowait(struct dm_table *t) 17128c2ecf20Sopenharmony_ci{ 17138c2ecf20Sopenharmony_ci struct dm_target *ti; 17148c2ecf20Sopenharmony_ci unsigned i = 0; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci while (i < dm_table_get_num_targets(t)) { 17178c2ecf20Sopenharmony_ci ti = dm_table_get_target(t, i++); 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci if (!dm_target_supports_nowait(ti->type)) 17208c2ecf20Sopenharmony_ci return false; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci if (!ti->type->iterate_devices || 17238c2ecf20Sopenharmony_ci ti->type->iterate_devices(ti, device_not_nowait_capable, NULL)) 17248c2ecf20Sopenharmony_ci return false; 17258c2ecf20Sopenharmony_ci } 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci return true; 17288c2ecf20Sopenharmony_ci} 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_cistatic int device_not_discard_capable(struct dm_target *ti, struct dm_dev *dev, 17318c2ecf20Sopenharmony_ci sector_t start, sector_t len, void *data) 17328c2ecf20Sopenharmony_ci{ 17338c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(dev->bdev); 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci return q && !blk_queue_discard(q); 17368c2ecf20Sopenharmony_ci} 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_cistatic bool dm_table_supports_discards(struct dm_table *t) 17398c2ecf20Sopenharmony_ci{ 17408c2ecf20Sopenharmony_ci struct dm_target *ti; 17418c2ecf20Sopenharmony_ci unsigned i; 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci for (i = 0; i < dm_table_get_num_targets(t); i++) { 17448c2ecf20Sopenharmony_ci ti = dm_table_get_target(t, i); 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci if (!ti->num_discard_bios) 17478c2ecf20Sopenharmony_ci return false; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci /* 17508c2ecf20Sopenharmony_ci * Either the target provides discard support (as implied by setting 17518c2ecf20Sopenharmony_ci * 'discards_supported') or it relies on _all_ data devices having 17528c2ecf20Sopenharmony_ci * discard support. 17538c2ecf20Sopenharmony_ci */ 17548c2ecf20Sopenharmony_ci if (!ti->discards_supported && 17558c2ecf20Sopenharmony_ci (!ti->type->iterate_devices || 17568c2ecf20Sopenharmony_ci ti->type->iterate_devices(ti, device_not_discard_capable, NULL))) 17578c2ecf20Sopenharmony_ci return false; 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci return true; 17618c2ecf20Sopenharmony_ci} 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_cistatic int device_not_secure_erase_capable(struct dm_target *ti, 17648c2ecf20Sopenharmony_ci struct dm_dev *dev, sector_t start, 17658c2ecf20Sopenharmony_ci sector_t len, void *data) 17668c2ecf20Sopenharmony_ci{ 17678c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(dev->bdev); 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci return q && !blk_queue_secure_erase(q); 17708c2ecf20Sopenharmony_ci} 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_cistatic bool dm_table_supports_secure_erase(struct dm_table *t) 17738c2ecf20Sopenharmony_ci{ 17748c2ecf20Sopenharmony_ci struct dm_target *ti; 17758c2ecf20Sopenharmony_ci unsigned int i; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci for (i = 0; i < dm_table_get_num_targets(t); i++) { 17788c2ecf20Sopenharmony_ci ti = dm_table_get_target(t, i); 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci if (!ti->num_secure_erase_bios) 17818c2ecf20Sopenharmony_ci return false; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci if (!ti->type->iterate_devices || 17848c2ecf20Sopenharmony_ci ti->type->iterate_devices(ti, device_not_secure_erase_capable, NULL)) 17858c2ecf20Sopenharmony_ci return false; 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci return true; 17898c2ecf20Sopenharmony_ci} 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_cistatic int device_requires_stable_pages(struct dm_target *ti, 17928c2ecf20Sopenharmony_ci struct dm_dev *dev, sector_t start, 17938c2ecf20Sopenharmony_ci sector_t len, void *data) 17948c2ecf20Sopenharmony_ci{ 17958c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(dev->bdev); 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci return q && blk_queue_stable_writes(q); 17988c2ecf20Sopenharmony_ci} 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_civoid dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, 18018c2ecf20Sopenharmony_ci struct queue_limits *limits) 18028c2ecf20Sopenharmony_ci{ 18038c2ecf20Sopenharmony_ci bool wc = false, fua = false; 18048c2ecf20Sopenharmony_ci int page_size = PAGE_SIZE; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci /* 18078c2ecf20Sopenharmony_ci * Copy table's limits to the DM device's request_queue 18088c2ecf20Sopenharmony_ci */ 18098c2ecf20Sopenharmony_ci q->limits = *limits; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci if (dm_table_supports_nowait(t)) 18128c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_NOWAIT, q); 18138c2ecf20Sopenharmony_ci else 18148c2ecf20Sopenharmony_ci blk_queue_flag_clear(QUEUE_FLAG_NOWAIT, q); 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci if (!dm_table_supports_discards(t)) { 18178c2ecf20Sopenharmony_ci blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q); 18188c2ecf20Sopenharmony_ci /* Must also clear discard limits... */ 18198c2ecf20Sopenharmony_ci q->limits.max_discard_sectors = 0; 18208c2ecf20Sopenharmony_ci q->limits.max_hw_discard_sectors = 0; 18218c2ecf20Sopenharmony_ci q->limits.discard_granularity = 0; 18228c2ecf20Sopenharmony_ci q->limits.discard_alignment = 0; 18238c2ecf20Sopenharmony_ci q->limits.discard_misaligned = 0; 18248c2ecf20Sopenharmony_ci } else 18258c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_DISCARD, q); 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci if (dm_table_supports_secure_erase(t)) 18288c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_SECERASE, q); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci if (dm_table_supports_flush(t, (1UL << QUEUE_FLAG_WC))) { 18318c2ecf20Sopenharmony_ci wc = true; 18328c2ecf20Sopenharmony_ci if (dm_table_supports_flush(t, (1UL << QUEUE_FLAG_FUA))) 18338c2ecf20Sopenharmony_ci fua = true; 18348c2ecf20Sopenharmony_ci } 18358c2ecf20Sopenharmony_ci blk_queue_write_cache(q, wc, fua); 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci if (dm_table_supports_dax(t, device_not_dax_capable, &page_size)) { 18388c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_DAX, q); 18398c2ecf20Sopenharmony_ci if (dm_table_supports_dax(t, device_not_dax_synchronous_capable, NULL)) 18408c2ecf20Sopenharmony_ci set_dax_synchronous(t->md->dax_dev); 18418c2ecf20Sopenharmony_ci } 18428c2ecf20Sopenharmony_ci else 18438c2ecf20Sopenharmony_ci blk_queue_flag_clear(QUEUE_FLAG_DAX, q); 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci if (dm_table_any_dev_attr(t, device_dax_write_cache_enabled, NULL)) 18468c2ecf20Sopenharmony_ci dax_write_cache(t->md->dax_dev, true); 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci /* Ensure that all underlying devices are non-rotational. */ 18498c2ecf20Sopenharmony_ci if (dm_table_any_dev_attr(t, device_is_rotational, NULL)) 18508c2ecf20Sopenharmony_ci blk_queue_flag_clear(QUEUE_FLAG_NONROT, q); 18518c2ecf20Sopenharmony_ci else 18528c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_NONROT, q); 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci if (!dm_table_supports_write_same(t)) 18558c2ecf20Sopenharmony_ci q->limits.max_write_same_sectors = 0; 18568c2ecf20Sopenharmony_ci if (!dm_table_supports_write_zeroes(t)) 18578c2ecf20Sopenharmony_ci q->limits.max_write_zeroes_sectors = 0; 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci dm_table_verify_integrity(t); 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci /* 18628c2ecf20Sopenharmony_ci * Some devices don't use blk_integrity but still want stable pages 18638c2ecf20Sopenharmony_ci * because they do their own checksumming. 18648c2ecf20Sopenharmony_ci * If any underlying device requires stable pages, a table must require 18658c2ecf20Sopenharmony_ci * them as well. Only targets that support iterate_devices are considered: 18668c2ecf20Sopenharmony_ci * don't want error, zero, etc to require stable pages. 18678c2ecf20Sopenharmony_ci */ 18688c2ecf20Sopenharmony_ci if (dm_table_any_dev_attr(t, device_requires_stable_pages, NULL)) 18698c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, q); 18708c2ecf20Sopenharmony_ci else 18718c2ecf20Sopenharmony_ci blk_queue_flag_clear(QUEUE_FLAG_STABLE_WRITES, q); 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci /* 18748c2ecf20Sopenharmony_ci * Determine whether or not this queue's I/O timings contribute 18758c2ecf20Sopenharmony_ci * to the entropy pool, Only request-based targets use this. 18768c2ecf20Sopenharmony_ci * Clear QUEUE_FLAG_ADD_RANDOM if any underlying device does not 18778c2ecf20Sopenharmony_ci * have it set. 18788c2ecf20Sopenharmony_ci */ 18798c2ecf20Sopenharmony_ci if (blk_queue_add_random(q) && 18808c2ecf20Sopenharmony_ci dm_table_any_dev_attr(t, device_is_not_random, NULL)) 18818c2ecf20Sopenharmony_ci blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q); 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci /* 18848c2ecf20Sopenharmony_ci * For a zoned target, the number of zones should be updated for the 18858c2ecf20Sopenharmony_ci * correct value to be exposed in sysfs queue/nr_zones. For a BIO based 18868c2ecf20Sopenharmony_ci * target, this is all that is needed. 18878c2ecf20Sopenharmony_ci */ 18888c2ecf20Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED 18898c2ecf20Sopenharmony_ci if (blk_queue_is_zoned(q)) { 18908c2ecf20Sopenharmony_ci WARN_ON_ONCE(queue_is_mq(q)); 18918c2ecf20Sopenharmony_ci q->nr_zones = blkdev_nr_zones(t->md->disk); 18928c2ecf20Sopenharmony_ci } 18938c2ecf20Sopenharmony_ci#endif 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci blk_queue_update_readahead(q); 18968c2ecf20Sopenharmony_ci} 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ciunsigned int dm_table_get_num_targets(struct dm_table *t) 18998c2ecf20Sopenharmony_ci{ 19008c2ecf20Sopenharmony_ci return t->num_targets; 19018c2ecf20Sopenharmony_ci} 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_cistruct list_head *dm_table_get_devices(struct dm_table *t) 19048c2ecf20Sopenharmony_ci{ 19058c2ecf20Sopenharmony_ci return &t->devices; 19068c2ecf20Sopenharmony_ci} 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_cifmode_t dm_table_get_mode(struct dm_table *t) 19098c2ecf20Sopenharmony_ci{ 19108c2ecf20Sopenharmony_ci return t->mode; 19118c2ecf20Sopenharmony_ci} 19128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_table_get_mode); 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_cienum suspend_mode { 19158c2ecf20Sopenharmony_ci PRESUSPEND, 19168c2ecf20Sopenharmony_ci PRESUSPEND_UNDO, 19178c2ecf20Sopenharmony_ci POSTSUSPEND, 19188c2ecf20Sopenharmony_ci}; 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_cistatic void suspend_targets(struct dm_table *t, enum suspend_mode mode) 19218c2ecf20Sopenharmony_ci{ 19228c2ecf20Sopenharmony_ci int i = t->num_targets; 19238c2ecf20Sopenharmony_ci struct dm_target *ti = t->targets; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci lockdep_assert_held(&t->md->suspend_lock); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci while (i--) { 19288c2ecf20Sopenharmony_ci switch (mode) { 19298c2ecf20Sopenharmony_ci case PRESUSPEND: 19308c2ecf20Sopenharmony_ci if (ti->type->presuspend) 19318c2ecf20Sopenharmony_ci ti->type->presuspend(ti); 19328c2ecf20Sopenharmony_ci break; 19338c2ecf20Sopenharmony_ci case PRESUSPEND_UNDO: 19348c2ecf20Sopenharmony_ci if (ti->type->presuspend_undo) 19358c2ecf20Sopenharmony_ci ti->type->presuspend_undo(ti); 19368c2ecf20Sopenharmony_ci break; 19378c2ecf20Sopenharmony_ci case POSTSUSPEND: 19388c2ecf20Sopenharmony_ci if (ti->type->postsuspend) 19398c2ecf20Sopenharmony_ci ti->type->postsuspend(ti); 19408c2ecf20Sopenharmony_ci break; 19418c2ecf20Sopenharmony_ci } 19428c2ecf20Sopenharmony_ci ti++; 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci} 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_civoid dm_table_presuspend_targets(struct dm_table *t) 19478c2ecf20Sopenharmony_ci{ 19488c2ecf20Sopenharmony_ci if (!t) 19498c2ecf20Sopenharmony_ci return; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci suspend_targets(t, PRESUSPEND); 19528c2ecf20Sopenharmony_ci} 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_civoid dm_table_presuspend_undo_targets(struct dm_table *t) 19558c2ecf20Sopenharmony_ci{ 19568c2ecf20Sopenharmony_ci if (!t) 19578c2ecf20Sopenharmony_ci return; 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci suspend_targets(t, PRESUSPEND_UNDO); 19608c2ecf20Sopenharmony_ci} 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_civoid dm_table_postsuspend_targets(struct dm_table *t) 19638c2ecf20Sopenharmony_ci{ 19648c2ecf20Sopenharmony_ci if (!t) 19658c2ecf20Sopenharmony_ci return; 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci suspend_targets(t, POSTSUSPEND); 19688c2ecf20Sopenharmony_ci} 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ciint dm_table_resume_targets(struct dm_table *t) 19718c2ecf20Sopenharmony_ci{ 19728c2ecf20Sopenharmony_ci int i, r = 0; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci lockdep_assert_held(&t->md->suspend_lock); 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci for (i = 0; i < t->num_targets; i++) { 19778c2ecf20Sopenharmony_ci struct dm_target *ti = t->targets + i; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci if (!ti->type->preresume) 19808c2ecf20Sopenharmony_ci continue; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci r = ti->type->preresume(ti); 19838c2ecf20Sopenharmony_ci if (r) { 19848c2ecf20Sopenharmony_ci DMERR("%s: %s: preresume failed, error = %d", 19858c2ecf20Sopenharmony_ci dm_device_name(t->md), ti->type->name, r); 19868c2ecf20Sopenharmony_ci return r; 19878c2ecf20Sopenharmony_ci } 19888c2ecf20Sopenharmony_ci } 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci for (i = 0; i < t->num_targets; i++) { 19918c2ecf20Sopenharmony_ci struct dm_target *ti = t->targets + i; 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci if (ti->type->resume) 19948c2ecf20Sopenharmony_ci ti->type->resume(ti); 19958c2ecf20Sopenharmony_ci } 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci return 0; 19988c2ecf20Sopenharmony_ci} 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_cistruct mapped_device *dm_table_get_md(struct dm_table *t) 20018c2ecf20Sopenharmony_ci{ 20028c2ecf20Sopenharmony_ci return t->md; 20038c2ecf20Sopenharmony_ci} 20048c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_table_get_md); 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ciconst char *dm_table_device_name(struct dm_table *t) 20078c2ecf20Sopenharmony_ci{ 20088c2ecf20Sopenharmony_ci return dm_device_name(t->md); 20098c2ecf20Sopenharmony_ci} 20108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_table_device_name); 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_civoid dm_table_run_md_queue_async(struct dm_table *t) 20138c2ecf20Sopenharmony_ci{ 20148c2ecf20Sopenharmony_ci if (!dm_table_request_based(t)) 20158c2ecf20Sopenharmony_ci return; 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci if (t->md->queue) 20188c2ecf20Sopenharmony_ci blk_mq_run_hw_queues(t->md->queue, true); 20198c2ecf20Sopenharmony_ci} 20208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_table_run_md_queue_async); 20218c2ecf20Sopenharmony_ci 2022