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