162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Add configfs and memory store: Kyungchan Koh <kkc6196@fb.com> and
462306a36Sopenharmony_ci * Shaohua Li <shli@fb.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include <linux/module.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/moduleparam.h>
962306a36Sopenharmony_ci#include <linux/sched.h>
1062306a36Sopenharmony_ci#include <linux/fs.h>
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include "null_blk.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#undef pr_fmt
1562306a36Sopenharmony_ci#define pr_fmt(fmt)	"null_blk: " fmt
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define FREE_BATCH		16
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define TICKS_PER_SEC		50ULL
2062306a36Sopenharmony_ci#define TIMER_INTERVAL		(NSEC_PER_SEC / TICKS_PER_SEC)
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION
2362306a36Sopenharmony_cistatic DECLARE_FAULT_ATTR(null_timeout_attr);
2462306a36Sopenharmony_cistatic DECLARE_FAULT_ATTR(null_requeue_attr);
2562306a36Sopenharmony_cistatic DECLARE_FAULT_ATTR(null_init_hctx_attr);
2662306a36Sopenharmony_ci#endif
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic inline u64 mb_per_tick(int mbps)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	return (1 << 20) / TICKS_PER_SEC * ((u64) mbps);
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/*
3462306a36Sopenharmony_ci * Status flags for nullb_device.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * CONFIGURED:	Device has been configured and turned on. Cannot reconfigure.
3762306a36Sopenharmony_ci * UP:		Device is currently on and visible in userspace.
3862306a36Sopenharmony_ci * THROTTLED:	Device is being throttled.
3962306a36Sopenharmony_ci * CACHE:	Device is using a write-back cache.
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_cienum nullb_device_flags {
4262306a36Sopenharmony_ci	NULLB_DEV_FL_CONFIGURED	= 0,
4362306a36Sopenharmony_ci	NULLB_DEV_FL_UP		= 1,
4462306a36Sopenharmony_ci	NULLB_DEV_FL_THROTTLED	= 2,
4562306a36Sopenharmony_ci	NULLB_DEV_FL_CACHE	= 3,
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define MAP_SZ		((PAGE_SIZE >> SECTOR_SHIFT) + 2)
4962306a36Sopenharmony_ci/*
5062306a36Sopenharmony_ci * nullb_page is a page in memory for nullb devices.
5162306a36Sopenharmony_ci *
5262306a36Sopenharmony_ci * @page:	The page holding the data.
5362306a36Sopenharmony_ci * @bitmap:	The bitmap represents which sector in the page has data.
5462306a36Sopenharmony_ci *		Each bit represents one block size. For example, sector 8
5562306a36Sopenharmony_ci *		will use the 7th bit
5662306a36Sopenharmony_ci * The highest 2 bits of bitmap are for special purpose. LOCK means the cache
5762306a36Sopenharmony_ci * page is being flushing to storage. FREE means the cache page is freed and
5862306a36Sopenharmony_ci * should be skipped from flushing to storage. Please see
5962306a36Sopenharmony_ci * null_make_cache_space
6062306a36Sopenharmony_ci */
6162306a36Sopenharmony_cistruct nullb_page {
6262306a36Sopenharmony_ci	struct page *page;
6362306a36Sopenharmony_ci	DECLARE_BITMAP(bitmap, MAP_SZ);
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci#define NULLB_PAGE_LOCK (MAP_SZ - 1)
6662306a36Sopenharmony_ci#define NULLB_PAGE_FREE (MAP_SZ - 2)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic LIST_HEAD(nullb_list);
6962306a36Sopenharmony_cistatic struct mutex lock;
7062306a36Sopenharmony_cistatic int null_major;
7162306a36Sopenharmony_cistatic DEFINE_IDA(nullb_indexes);
7262306a36Sopenharmony_cistatic struct blk_mq_tag_set tag_set;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cienum {
7562306a36Sopenharmony_ci	NULL_IRQ_NONE		= 0,
7662306a36Sopenharmony_ci	NULL_IRQ_SOFTIRQ	= 1,
7762306a36Sopenharmony_ci	NULL_IRQ_TIMER		= 2,
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic bool g_virt_boundary = false;
8162306a36Sopenharmony_cimodule_param_named(virt_boundary, g_virt_boundary, bool, 0444);
8262306a36Sopenharmony_ciMODULE_PARM_DESC(virt_boundary, "Require a virtual boundary for the device. Default: False");
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic int g_no_sched;
8562306a36Sopenharmony_cimodule_param_named(no_sched, g_no_sched, int, 0444);
8662306a36Sopenharmony_ciMODULE_PARM_DESC(no_sched, "No io scheduler");
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic int g_submit_queues = 1;
8962306a36Sopenharmony_cimodule_param_named(submit_queues, g_submit_queues, int, 0444);
9062306a36Sopenharmony_ciMODULE_PARM_DESC(submit_queues, "Number of submission queues");
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic int g_poll_queues = 1;
9362306a36Sopenharmony_cimodule_param_named(poll_queues, g_poll_queues, int, 0444);
9462306a36Sopenharmony_ciMODULE_PARM_DESC(poll_queues, "Number of IOPOLL submission queues");
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic int g_home_node = NUMA_NO_NODE;
9762306a36Sopenharmony_cimodule_param_named(home_node, g_home_node, int, 0444);
9862306a36Sopenharmony_ciMODULE_PARM_DESC(home_node, "Home node for the device");
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION
10162306a36Sopenharmony_ci/*
10262306a36Sopenharmony_ci * For more details about fault injection, please refer to
10362306a36Sopenharmony_ci * Documentation/fault-injection/fault-injection.rst.
10462306a36Sopenharmony_ci */
10562306a36Sopenharmony_cistatic char g_timeout_str[80];
10662306a36Sopenharmony_cimodule_param_string(timeout, g_timeout_str, sizeof(g_timeout_str), 0444);
10762306a36Sopenharmony_ciMODULE_PARM_DESC(timeout, "Fault injection. timeout=<interval>,<probability>,<space>,<times>");
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic char g_requeue_str[80];
11062306a36Sopenharmony_cimodule_param_string(requeue, g_requeue_str, sizeof(g_requeue_str), 0444);
11162306a36Sopenharmony_ciMODULE_PARM_DESC(requeue, "Fault injection. requeue=<interval>,<probability>,<space>,<times>");
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic char g_init_hctx_str[80];
11462306a36Sopenharmony_cimodule_param_string(init_hctx, g_init_hctx_str, sizeof(g_init_hctx_str), 0444);
11562306a36Sopenharmony_ciMODULE_PARM_DESC(init_hctx, "Fault injection to fail hctx init. init_hctx=<interval>,<probability>,<space>,<times>");
11662306a36Sopenharmony_ci#endif
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic int g_queue_mode = NULL_Q_MQ;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic int null_param_store_val(const char *str, int *val, int min, int max)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	int ret, new_val;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	ret = kstrtoint(str, 10, &new_val);
12562306a36Sopenharmony_ci	if (ret)
12662306a36Sopenharmony_ci		return -EINVAL;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	if (new_val < min || new_val > max)
12962306a36Sopenharmony_ci		return -EINVAL;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	*val = new_val;
13262306a36Sopenharmony_ci	return 0;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic int null_set_queue_mode(const char *str, const struct kernel_param *kp)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	return null_param_store_val(str, &g_queue_mode, NULL_Q_BIO, NULL_Q_MQ);
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic const struct kernel_param_ops null_queue_mode_param_ops = {
14162306a36Sopenharmony_ci	.set	= null_set_queue_mode,
14262306a36Sopenharmony_ci	.get	= param_get_int,
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cidevice_param_cb(queue_mode, &null_queue_mode_param_ops, &g_queue_mode, 0444);
14662306a36Sopenharmony_ciMODULE_PARM_DESC(queue_mode, "Block interface to use (0=bio,1=rq,2=multiqueue)");
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic int g_gb = 250;
14962306a36Sopenharmony_cimodule_param_named(gb, g_gb, int, 0444);
15062306a36Sopenharmony_ciMODULE_PARM_DESC(gb, "Size in GB");
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic int g_bs = 512;
15362306a36Sopenharmony_cimodule_param_named(bs, g_bs, int, 0444);
15462306a36Sopenharmony_ciMODULE_PARM_DESC(bs, "Block size (in bytes)");
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic int g_max_sectors;
15762306a36Sopenharmony_cimodule_param_named(max_sectors, g_max_sectors, int, 0444);
15862306a36Sopenharmony_ciMODULE_PARM_DESC(max_sectors, "Maximum size of a command (in 512B sectors)");
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic unsigned int nr_devices = 1;
16162306a36Sopenharmony_cimodule_param(nr_devices, uint, 0444);
16262306a36Sopenharmony_ciMODULE_PARM_DESC(nr_devices, "Number of devices to register");
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic bool g_blocking;
16562306a36Sopenharmony_cimodule_param_named(blocking, g_blocking, bool, 0444);
16662306a36Sopenharmony_ciMODULE_PARM_DESC(blocking, "Register as a blocking blk-mq driver device");
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic bool shared_tags;
16962306a36Sopenharmony_cimodule_param(shared_tags, bool, 0444);
17062306a36Sopenharmony_ciMODULE_PARM_DESC(shared_tags, "Share tag set between devices for blk-mq");
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic bool g_shared_tag_bitmap;
17362306a36Sopenharmony_cimodule_param_named(shared_tag_bitmap, g_shared_tag_bitmap, bool, 0444);
17462306a36Sopenharmony_ciMODULE_PARM_DESC(shared_tag_bitmap, "Use shared tag bitmap for all submission queues for blk-mq");
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic int g_irqmode = NULL_IRQ_SOFTIRQ;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic int null_set_irqmode(const char *str, const struct kernel_param *kp)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	return null_param_store_val(str, &g_irqmode, NULL_IRQ_NONE,
18162306a36Sopenharmony_ci					NULL_IRQ_TIMER);
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic const struct kernel_param_ops null_irqmode_param_ops = {
18562306a36Sopenharmony_ci	.set	= null_set_irqmode,
18662306a36Sopenharmony_ci	.get	= param_get_int,
18762306a36Sopenharmony_ci};
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cidevice_param_cb(irqmode, &null_irqmode_param_ops, &g_irqmode, 0444);
19062306a36Sopenharmony_ciMODULE_PARM_DESC(irqmode, "IRQ completion handler. 0-none, 1-softirq, 2-timer");
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic unsigned long g_completion_nsec = 10000;
19362306a36Sopenharmony_cimodule_param_named(completion_nsec, g_completion_nsec, ulong, 0444);
19462306a36Sopenharmony_ciMODULE_PARM_DESC(completion_nsec, "Time in ns to complete a request in hardware. Default: 10,000ns");
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic int g_hw_queue_depth = 64;
19762306a36Sopenharmony_cimodule_param_named(hw_queue_depth, g_hw_queue_depth, int, 0444);
19862306a36Sopenharmony_ciMODULE_PARM_DESC(hw_queue_depth, "Queue depth for each hardware queue. Default: 64");
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic bool g_use_per_node_hctx;
20162306a36Sopenharmony_cimodule_param_named(use_per_node_hctx, g_use_per_node_hctx, bool, 0444);
20262306a36Sopenharmony_ciMODULE_PARM_DESC(use_per_node_hctx, "Use per-node allocation for hardware context queues. Default: false");
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic bool g_memory_backed;
20562306a36Sopenharmony_cimodule_param_named(memory_backed, g_memory_backed, bool, 0444);
20662306a36Sopenharmony_ciMODULE_PARM_DESC(memory_backed, "Create a memory-backed block device. Default: false");
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic bool g_discard;
20962306a36Sopenharmony_cimodule_param_named(discard, g_discard, bool, 0444);
21062306a36Sopenharmony_ciMODULE_PARM_DESC(discard, "Support discard operations (requires memory-backed null_blk device). Default: false");
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic unsigned long g_cache_size;
21362306a36Sopenharmony_cimodule_param_named(cache_size, g_cache_size, ulong, 0444);
21462306a36Sopenharmony_ciMODULE_PARM_DESC(mbps, "Cache size in MiB for memory-backed device. Default: 0 (none)");
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic unsigned int g_mbps;
21762306a36Sopenharmony_cimodule_param_named(mbps, g_mbps, uint, 0444);
21862306a36Sopenharmony_ciMODULE_PARM_DESC(mbps, "Limit maximum bandwidth (in MiB/s). Default: 0 (no limit)");
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic bool g_zoned;
22162306a36Sopenharmony_cimodule_param_named(zoned, g_zoned, bool, S_IRUGO);
22262306a36Sopenharmony_ciMODULE_PARM_DESC(zoned, "Make device as a host-managed zoned block device. Default: false");
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic unsigned long g_zone_size = 256;
22562306a36Sopenharmony_cimodule_param_named(zone_size, g_zone_size, ulong, S_IRUGO);
22662306a36Sopenharmony_ciMODULE_PARM_DESC(zone_size, "Zone size in MB when block device is zoned. Must be power-of-two: Default: 256");
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic unsigned long g_zone_capacity;
22962306a36Sopenharmony_cimodule_param_named(zone_capacity, g_zone_capacity, ulong, 0444);
23062306a36Sopenharmony_ciMODULE_PARM_DESC(zone_capacity, "Zone capacity in MB when block device is zoned. Can be less than or equal to zone size. Default: Zone size");
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic unsigned int g_zone_nr_conv;
23362306a36Sopenharmony_cimodule_param_named(zone_nr_conv, g_zone_nr_conv, uint, 0444);
23462306a36Sopenharmony_ciMODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones when block device is zoned. Default: 0");
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic unsigned int g_zone_max_open;
23762306a36Sopenharmony_cimodule_param_named(zone_max_open, g_zone_max_open, uint, 0444);
23862306a36Sopenharmony_ciMODULE_PARM_DESC(zone_max_open, "Maximum number of open zones when block device is zoned. Default: 0 (no limit)");
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic unsigned int g_zone_max_active;
24162306a36Sopenharmony_cimodule_param_named(zone_max_active, g_zone_max_active, uint, 0444);
24262306a36Sopenharmony_ciMODULE_PARM_DESC(zone_max_active, "Maximum number of active zones when block device is zoned. Default: 0 (no limit)");
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic struct nullb_device *null_alloc_dev(void);
24562306a36Sopenharmony_cistatic void null_free_dev(struct nullb_device *dev);
24662306a36Sopenharmony_cistatic void null_del_dev(struct nullb *nullb);
24762306a36Sopenharmony_cistatic int null_add_dev(struct nullb_device *dev);
24862306a36Sopenharmony_cistatic struct nullb *null_find_dev_by_name(const char *name);
24962306a36Sopenharmony_cistatic void null_free_device_storage(struct nullb_device *dev, bool is_cache);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic inline struct nullb_device *to_nullb_device(struct config_item *item)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	return item ? container_of(to_config_group(item), struct nullb_device, group) : NULL;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic inline ssize_t nullb_device_uint_attr_show(unsigned int val, char *page)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	return snprintf(page, PAGE_SIZE, "%u\n", val);
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic inline ssize_t nullb_device_ulong_attr_show(unsigned long val,
26262306a36Sopenharmony_ci	char *page)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	return snprintf(page, PAGE_SIZE, "%lu\n", val);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic inline ssize_t nullb_device_bool_attr_show(bool val, char *page)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	return snprintf(page, PAGE_SIZE, "%u\n", val);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic ssize_t nullb_device_uint_attr_store(unsigned int *val,
27362306a36Sopenharmony_ci	const char *page, size_t count)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	unsigned int tmp;
27662306a36Sopenharmony_ci	int result;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	result = kstrtouint(page, 0, &tmp);
27962306a36Sopenharmony_ci	if (result < 0)
28062306a36Sopenharmony_ci		return result;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	*val = tmp;
28362306a36Sopenharmony_ci	return count;
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic ssize_t nullb_device_ulong_attr_store(unsigned long *val,
28762306a36Sopenharmony_ci	const char *page, size_t count)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	int result;
29062306a36Sopenharmony_ci	unsigned long tmp;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	result = kstrtoul(page, 0, &tmp);
29362306a36Sopenharmony_ci	if (result < 0)
29462306a36Sopenharmony_ci		return result;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	*val = tmp;
29762306a36Sopenharmony_ci	return count;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic ssize_t nullb_device_bool_attr_store(bool *val, const char *page,
30162306a36Sopenharmony_ci	size_t count)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	bool tmp;
30462306a36Sopenharmony_ci	int result;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	result = kstrtobool(page,  &tmp);
30762306a36Sopenharmony_ci	if (result < 0)
30862306a36Sopenharmony_ci		return result;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	*val = tmp;
31162306a36Sopenharmony_ci	return count;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci/* The following macro should only be used with TYPE = {uint, ulong, bool}. */
31562306a36Sopenharmony_ci#define NULLB_DEVICE_ATTR(NAME, TYPE, APPLY)				\
31662306a36Sopenharmony_cistatic ssize_t								\
31762306a36Sopenharmony_cinullb_device_##NAME##_show(struct config_item *item, char *page)	\
31862306a36Sopenharmony_ci{									\
31962306a36Sopenharmony_ci	return nullb_device_##TYPE##_attr_show(				\
32062306a36Sopenharmony_ci				to_nullb_device(item)->NAME, page);	\
32162306a36Sopenharmony_ci}									\
32262306a36Sopenharmony_cistatic ssize_t								\
32362306a36Sopenharmony_cinullb_device_##NAME##_store(struct config_item *item, const char *page,	\
32462306a36Sopenharmony_ci			    size_t count)				\
32562306a36Sopenharmony_ci{									\
32662306a36Sopenharmony_ci	int (*apply_fn)(struct nullb_device *dev, TYPE new_value) = APPLY;\
32762306a36Sopenharmony_ci	struct nullb_device *dev = to_nullb_device(item);		\
32862306a36Sopenharmony_ci	TYPE new_value = 0;						\
32962306a36Sopenharmony_ci	int ret;							\
33062306a36Sopenharmony_ci									\
33162306a36Sopenharmony_ci	ret = nullb_device_##TYPE##_attr_store(&new_value, page, count);\
33262306a36Sopenharmony_ci	if (ret < 0)							\
33362306a36Sopenharmony_ci		return ret;						\
33462306a36Sopenharmony_ci	if (apply_fn)							\
33562306a36Sopenharmony_ci		ret = apply_fn(dev, new_value);				\
33662306a36Sopenharmony_ci	else if (test_bit(NULLB_DEV_FL_CONFIGURED, &dev->flags)) 	\
33762306a36Sopenharmony_ci		ret = -EBUSY;						\
33862306a36Sopenharmony_ci	if (ret < 0)							\
33962306a36Sopenharmony_ci		return ret;						\
34062306a36Sopenharmony_ci	dev->NAME = new_value;						\
34162306a36Sopenharmony_ci	return count;							\
34262306a36Sopenharmony_ci}									\
34362306a36Sopenharmony_ciCONFIGFS_ATTR(nullb_device_, NAME);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic int nullb_update_nr_hw_queues(struct nullb_device *dev,
34662306a36Sopenharmony_ci				     unsigned int submit_queues,
34762306a36Sopenharmony_ci				     unsigned int poll_queues)
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	struct blk_mq_tag_set *set;
35162306a36Sopenharmony_ci	int ret, nr_hw_queues;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (!dev->nullb)
35462306a36Sopenharmony_ci		return 0;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	/*
35762306a36Sopenharmony_ci	 * Make sure at least one submit queue exists.
35862306a36Sopenharmony_ci	 */
35962306a36Sopenharmony_ci	if (!submit_queues)
36062306a36Sopenharmony_ci		return -EINVAL;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	/*
36362306a36Sopenharmony_ci	 * Make sure that null_init_hctx() does not access nullb->queues[] past
36462306a36Sopenharmony_ci	 * the end of that array.
36562306a36Sopenharmony_ci	 */
36662306a36Sopenharmony_ci	if (submit_queues > nr_cpu_ids || poll_queues > g_poll_queues)
36762306a36Sopenharmony_ci		return -EINVAL;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	/*
37062306a36Sopenharmony_ci	 * Keep previous and new queue numbers in nullb_device for reference in
37162306a36Sopenharmony_ci	 * the call back function null_map_queues().
37262306a36Sopenharmony_ci	 */
37362306a36Sopenharmony_ci	dev->prev_submit_queues = dev->submit_queues;
37462306a36Sopenharmony_ci	dev->prev_poll_queues = dev->poll_queues;
37562306a36Sopenharmony_ci	dev->submit_queues = submit_queues;
37662306a36Sopenharmony_ci	dev->poll_queues = poll_queues;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	set = dev->nullb->tag_set;
37962306a36Sopenharmony_ci	nr_hw_queues = submit_queues + poll_queues;
38062306a36Sopenharmony_ci	blk_mq_update_nr_hw_queues(set, nr_hw_queues);
38162306a36Sopenharmony_ci	ret = set->nr_hw_queues == nr_hw_queues ? 0 : -ENOMEM;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	if (ret) {
38462306a36Sopenharmony_ci		/* on error, revert the queue numbers */
38562306a36Sopenharmony_ci		dev->submit_queues = dev->prev_submit_queues;
38662306a36Sopenharmony_ci		dev->poll_queues = dev->prev_poll_queues;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	return ret;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic int nullb_apply_submit_queues(struct nullb_device *dev,
39362306a36Sopenharmony_ci				     unsigned int submit_queues)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	return nullb_update_nr_hw_queues(dev, submit_queues, dev->poll_queues);
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic int nullb_apply_poll_queues(struct nullb_device *dev,
39962306a36Sopenharmony_ci				   unsigned int poll_queues)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	return nullb_update_nr_hw_queues(dev, dev->submit_queues, poll_queues);
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ciNULLB_DEVICE_ATTR(size, ulong, NULL);
40562306a36Sopenharmony_ciNULLB_DEVICE_ATTR(completion_nsec, ulong, NULL);
40662306a36Sopenharmony_ciNULLB_DEVICE_ATTR(submit_queues, uint, nullb_apply_submit_queues);
40762306a36Sopenharmony_ciNULLB_DEVICE_ATTR(poll_queues, uint, nullb_apply_poll_queues);
40862306a36Sopenharmony_ciNULLB_DEVICE_ATTR(home_node, uint, NULL);
40962306a36Sopenharmony_ciNULLB_DEVICE_ATTR(queue_mode, uint, NULL);
41062306a36Sopenharmony_ciNULLB_DEVICE_ATTR(blocksize, uint, NULL);
41162306a36Sopenharmony_ciNULLB_DEVICE_ATTR(max_sectors, uint, NULL);
41262306a36Sopenharmony_ciNULLB_DEVICE_ATTR(irqmode, uint, NULL);
41362306a36Sopenharmony_ciNULLB_DEVICE_ATTR(hw_queue_depth, uint, NULL);
41462306a36Sopenharmony_ciNULLB_DEVICE_ATTR(index, uint, NULL);
41562306a36Sopenharmony_ciNULLB_DEVICE_ATTR(blocking, bool, NULL);
41662306a36Sopenharmony_ciNULLB_DEVICE_ATTR(use_per_node_hctx, bool, NULL);
41762306a36Sopenharmony_ciNULLB_DEVICE_ATTR(memory_backed, bool, NULL);
41862306a36Sopenharmony_ciNULLB_DEVICE_ATTR(discard, bool, NULL);
41962306a36Sopenharmony_ciNULLB_DEVICE_ATTR(mbps, uint, NULL);
42062306a36Sopenharmony_ciNULLB_DEVICE_ATTR(cache_size, ulong, NULL);
42162306a36Sopenharmony_ciNULLB_DEVICE_ATTR(zoned, bool, NULL);
42262306a36Sopenharmony_ciNULLB_DEVICE_ATTR(zone_size, ulong, NULL);
42362306a36Sopenharmony_ciNULLB_DEVICE_ATTR(zone_capacity, ulong, NULL);
42462306a36Sopenharmony_ciNULLB_DEVICE_ATTR(zone_nr_conv, uint, NULL);
42562306a36Sopenharmony_ciNULLB_DEVICE_ATTR(zone_max_open, uint, NULL);
42662306a36Sopenharmony_ciNULLB_DEVICE_ATTR(zone_max_active, uint, NULL);
42762306a36Sopenharmony_ciNULLB_DEVICE_ATTR(virt_boundary, bool, NULL);
42862306a36Sopenharmony_ciNULLB_DEVICE_ATTR(no_sched, bool, NULL);
42962306a36Sopenharmony_ciNULLB_DEVICE_ATTR(shared_tag_bitmap, bool, NULL);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic ssize_t nullb_device_power_show(struct config_item *item, char *page)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	return nullb_device_bool_attr_show(to_nullb_device(item)->power, page);
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic ssize_t nullb_device_power_store(struct config_item *item,
43762306a36Sopenharmony_ci				     const char *page, size_t count)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct nullb_device *dev = to_nullb_device(item);
44062306a36Sopenharmony_ci	bool newp = false;
44162306a36Sopenharmony_ci	ssize_t ret;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	ret = nullb_device_bool_attr_store(&newp, page, count);
44462306a36Sopenharmony_ci	if (ret < 0)
44562306a36Sopenharmony_ci		return ret;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	if (!dev->power && newp) {
44862306a36Sopenharmony_ci		if (test_and_set_bit(NULLB_DEV_FL_UP, &dev->flags))
44962306a36Sopenharmony_ci			return count;
45062306a36Sopenharmony_ci		ret = null_add_dev(dev);
45162306a36Sopenharmony_ci		if (ret) {
45262306a36Sopenharmony_ci			clear_bit(NULLB_DEV_FL_UP, &dev->flags);
45362306a36Sopenharmony_ci			return ret;
45462306a36Sopenharmony_ci		}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci		set_bit(NULLB_DEV_FL_CONFIGURED, &dev->flags);
45762306a36Sopenharmony_ci		dev->power = newp;
45862306a36Sopenharmony_ci	} else if (dev->power && !newp) {
45962306a36Sopenharmony_ci		if (test_and_clear_bit(NULLB_DEV_FL_UP, &dev->flags)) {
46062306a36Sopenharmony_ci			mutex_lock(&lock);
46162306a36Sopenharmony_ci			dev->power = newp;
46262306a36Sopenharmony_ci			null_del_dev(dev->nullb);
46362306a36Sopenharmony_ci			mutex_unlock(&lock);
46462306a36Sopenharmony_ci		}
46562306a36Sopenharmony_ci		clear_bit(NULLB_DEV_FL_CONFIGURED, &dev->flags);
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	return count;
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ciCONFIGFS_ATTR(nullb_device_, power);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic ssize_t nullb_device_badblocks_show(struct config_item *item, char *page)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	struct nullb_device *t_dev = to_nullb_device(item);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	return badblocks_show(&t_dev->badblocks, page, 0);
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic ssize_t nullb_device_badblocks_store(struct config_item *item,
48162306a36Sopenharmony_ci				     const char *page, size_t count)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	struct nullb_device *t_dev = to_nullb_device(item);
48462306a36Sopenharmony_ci	char *orig, *buf, *tmp;
48562306a36Sopenharmony_ci	u64 start, end;
48662306a36Sopenharmony_ci	int ret;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	orig = kstrndup(page, count, GFP_KERNEL);
48962306a36Sopenharmony_ci	if (!orig)
49062306a36Sopenharmony_ci		return -ENOMEM;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	buf = strstrip(orig);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	ret = -EINVAL;
49562306a36Sopenharmony_ci	if (buf[0] != '+' && buf[0] != '-')
49662306a36Sopenharmony_ci		goto out;
49762306a36Sopenharmony_ci	tmp = strchr(&buf[1], '-');
49862306a36Sopenharmony_ci	if (!tmp)
49962306a36Sopenharmony_ci		goto out;
50062306a36Sopenharmony_ci	*tmp = '\0';
50162306a36Sopenharmony_ci	ret = kstrtoull(buf + 1, 0, &start);
50262306a36Sopenharmony_ci	if (ret)
50362306a36Sopenharmony_ci		goto out;
50462306a36Sopenharmony_ci	ret = kstrtoull(tmp + 1, 0, &end);
50562306a36Sopenharmony_ci	if (ret)
50662306a36Sopenharmony_ci		goto out;
50762306a36Sopenharmony_ci	ret = -EINVAL;
50862306a36Sopenharmony_ci	if (start > end)
50962306a36Sopenharmony_ci		goto out;
51062306a36Sopenharmony_ci	/* enable badblocks */
51162306a36Sopenharmony_ci	cmpxchg(&t_dev->badblocks.shift, -1, 0);
51262306a36Sopenharmony_ci	if (buf[0] == '+')
51362306a36Sopenharmony_ci		ret = badblocks_set(&t_dev->badblocks, start,
51462306a36Sopenharmony_ci			end - start + 1, 1);
51562306a36Sopenharmony_ci	else
51662306a36Sopenharmony_ci		ret = badblocks_clear(&t_dev->badblocks, start,
51762306a36Sopenharmony_ci			end - start + 1);
51862306a36Sopenharmony_ci	if (ret == 0)
51962306a36Sopenharmony_ci		ret = count;
52062306a36Sopenharmony_ciout:
52162306a36Sopenharmony_ci	kfree(orig);
52262306a36Sopenharmony_ci	return ret;
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ciCONFIGFS_ATTR(nullb_device_, badblocks);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic ssize_t nullb_device_zone_readonly_store(struct config_item *item,
52762306a36Sopenharmony_ci						const char *page, size_t count)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct nullb_device *dev = to_nullb_device(item);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	return zone_cond_store(dev, page, count, BLK_ZONE_COND_READONLY);
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ciCONFIGFS_ATTR_WO(nullb_device_, zone_readonly);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic ssize_t nullb_device_zone_offline_store(struct config_item *item,
53662306a36Sopenharmony_ci					       const char *page, size_t count)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	struct nullb_device *dev = to_nullb_device(item);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	return zone_cond_store(dev, page, count, BLK_ZONE_COND_OFFLINE);
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ciCONFIGFS_ATTR_WO(nullb_device_, zone_offline);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_cistatic struct configfs_attribute *nullb_device_attrs[] = {
54562306a36Sopenharmony_ci	&nullb_device_attr_size,
54662306a36Sopenharmony_ci	&nullb_device_attr_completion_nsec,
54762306a36Sopenharmony_ci	&nullb_device_attr_submit_queues,
54862306a36Sopenharmony_ci	&nullb_device_attr_poll_queues,
54962306a36Sopenharmony_ci	&nullb_device_attr_home_node,
55062306a36Sopenharmony_ci	&nullb_device_attr_queue_mode,
55162306a36Sopenharmony_ci	&nullb_device_attr_blocksize,
55262306a36Sopenharmony_ci	&nullb_device_attr_max_sectors,
55362306a36Sopenharmony_ci	&nullb_device_attr_irqmode,
55462306a36Sopenharmony_ci	&nullb_device_attr_hw_queue_depth,
55562306a36Sopenharmony_ci	&nullb_device_attr_index,
55662306a36Sopenharmony_ci	&nullb_device_attr_blocking,
55762306a36Sopenharmony_ci	&nullb_device_attr_use_per_node_hctx,
55862306a36Sopenharmony_ci	&nullb_device_attr_power,
55962306a36Sopenharmony_ci	&nullb_device_attr_memory_backed,
56062306a36Sopenharmony_ci	&nullb_device_attr_discard,
56162306a36Sopenharmony_ci	&nullb_device_attr_mbps,
56262306a36Sopenharmony_ci	&nullb_device_attr_cache_size,
56362306a36Sopenharmony_ci	&nullb_device_attr_badblocks,
56462306a36Sopenharmony_ci	&nullb_device_attr_zoned,
56562306a36Sopenharmony_ci	&nullb_device_attr_zone_size,
56662306a36Sopenharmony_ci	&nullb_device_attr_zone_capacity,
56762306a36Sopenharmony_ci	&nullb_device_attr_zone_nr_conv,
56862306a36Sopenharmony_ci	&nullb_device_attr_zone_max_open,
56962306a36Sopenharmony_ci	&nullb_device_attr_zone_max_active,
57062306a36Sopenharmony_ci	&nullb_device_attr_zone_readonly,
57162306a36Sopenharmony_ci	&nullb_device_attr_zone_offline,
57262306a36Sopenharmony_ci	&nullb_device_attr_virt_boundary,
57362306a36Sopenharmony_ci	&nullb_device_attr_no_sched,
57462306a36Sopenharmony_ci	&nullb_device_attr_shared_tag_bitmap,
57562306a36Sopenharmony_ci	NULL,
57662306a36Sopenharmony_ci};
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cistatic void nullb_device_release(struct config_item *item)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	struct nullb_device *dev = to_nullb_device(item);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	null_free_device_storage(dev, false);
58362306a36Sopenharmony_ci	null_free_dev(dev);
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic struct configfs_item_operations nullb_device_ops = {
58762306a36Sopenharmony_ci	.release	= nullb_device_release,
58862306a36Sopenharmony_ci};
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistatic const struct config_item_type nullb_device_type = {
59162306a36Sopenharmony_ci	.ct_item_ops	= &nullb_device_ops,
59262306a36Sopenharmony_ci	.ct_attrs	= nullb_device_attrs,
59362306a36Sopenharmony_ci	.ct_owner	= THIS_MODULE,
59462306a36Sopenharmony_ci};
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic void nullb_add_fault_config(struct nullb_device *dev)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	fault_config_init(&dev->timeout_config, "timeout_inject");
60162306a36Sopenharmony_ci	fault_config_init(&dev->requeue_config, "requeue_inject");
60262306a36Sopenharmony_ci	fault_config_init(&dev->init_hctx_fault_config, "init_hctx_fault_inject");
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	configfs_add_default_group(&dev->timeout_config.group, &dev->group);
60562306a36Sopenharmony_ci	configfs_add_default_group(&dev->requeue_config.group, &dev->group);
60662306a36Sopenharmony_ci	configfs_add_default_group(&dev->init_hctx_fault_config.group, &dev->group);
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci#else
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cistatic void nullb_add_fault_config(struct nullb_device *dev)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci#endif
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_cistatic struct
61862306a36Sopenharmony_ciconfig_group *nullb_group_make_group(struct config_group *group, const char *name)
61962306a36Sopenharmony_ci{
62062306a36Sopenharmony_ci	struct nullb_device *dev;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	if (null_find_dev_by_name(name))
62362306a36Sopenharmony_ci		return ERR_PTR(-EEXIST);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	dev = null_alloc_dev();
62662306a36Sopenharmony_ci	if (!dev)
62762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	config_group_init_type_name(&dev->group, name, &nullb_device_type);
63062306a36Sopenharmony_ci	nullb_add_fault_config(dev);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	return &dev->group;
63362306a36Sopenharmony_ci}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cistatic void
63662306a36Sopenharmony_cinullb_group_drop_item(struct config_group *group, struct config_item *item)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	struct nullb_device *dev = to_nullb_device(item);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	if (test_and_clear_bit(NULLB_DEV_FL_UP, &dev->flags)) {
64162306a36Sopenharmony_ci		mutex_lock(&lock);
64262306a36Sopenharmony_ci		dev->power = false;
64362306a36Sopenharmony_ci		null_del_dev(dev->nullb);
64462306a36Sopenharmony_ci		mutex_unlock(&lock);
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	config_item_put(item);
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_cistatic ssize_t memb_group_features_show(struct config_item *item, char *page)
65162306a36Sopenharmony_ci{
65262306a36Sopenharmony_ci	return snprintf(page, PAGE_SIZE,
65362306a36Sopenharmony_ci			"badblocks,blocking,blocksize,cache_size,"
65462306a36Sopenharmony_ci			"completion_nsec,discard,home_node,hw_queue_depth,"
65562306a36Sopenharmony_ci			"irqmode,max_sectors,mbps,memory_backed,no_sched,"
65662306a36Sopenharmony_ci			"poll_queues,power,queue_mode,shared_tag_bitmap,size,"
65762306a36Sopenharmony_ci			"submit_queues,use_per_node_hctx,virt_boundary,zoned,"
65862306a36Sopenharmony_ci			"zone_capacity,zone_max_active,zone_max_open,"
65962306a36Sopenharmony_ci			"zone_nr_conv,zone_offline,zone_readonly,zone_size\n");
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ciCONFIGFS_ATTR_RO(memb_group_, features);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_cistatic struct configfs_attribute *nullb_group_attrs[] = {
66562306a36Sopenharmony_ci	&memb_group_attr_features,
66662306a36Sopenharmony_ci	NULL,
66762306a36Sopenharmony_ci};
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_cistatic struct configfs_group_operations nullb_group_ops = {
67062306a36Sopenharmony_ci	.make_group	= nullb_group_make_group,
67162306a36Sopenharmony_ci	.drop_item	= nullb_group_drop_item,
67262306a36Sopenharmony_ci};
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic const struct config_item_type nullb_group_type = {
67562306a36Sopenharmony_ci	.ct_group_ops	= &nullb_group_ops,
67662306a36Sopenharmony_ci	.ct_attrs	= nullb_group_attrs,
67762306a36Sopenharmony_ci	.ct_owner	= THIS_MODULE,
67862306a36Sopenharmony_ci};
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic struct configfs_subsystem nullb_subsys = {
68162306a36Sopenharmony_ci	.su_group = {
68262306a36Sopenharmony_ci		.cg_item = {
68362306a36Sopenharmony_ci			.ci_namebuf = "nullb",
68462306a36Sopenharmony_ci			.ci_type = &nullb_group_type,
68562306a36Sopenharmony_ci		},
68662306a36Sopenharmony_ci	},
68762306a36Sopenharmony_ci};
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_cistatic inline int null_cache_active(struct nullb *nullb)
69062306a36Sopenharmony_ci{
69162306a36Sopenharmony_ci	return test_bit(NULLB_DEV_FL_CACHE, &nullb->dev->flags);
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_cistatic struct nullb_device *null_alloc_dev(void)
69562306a36Sopenharmony_ci{
69662306a36Sopenharmony_ci	struct nullb_device *dev;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
69962306a36Sopenharmony_ci	if (!dev)
70062306a36Sopenharmony_ci		return NULL;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION
70362306a36Sopenharmony_ci	dev->timeout_config.attr = null_timeout_attr;
70462306a36Sopenharmony_ci	dev->requeue_config.attr = null_requeue_attr;
70562306a36Sopenharmony_ci	dev->init_hctx_fault_config.attr = null_init_hctx_attr;
70662306a36Sopenharmony_ci#endif
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	INIT_RADIX_TREE(&dev->data, GFP_ATOMIC);
70962306a36Sopenharmony_ci	INIT_RADIX_TREE(&dev->cache, GFP_ATOMIC);
71062306a36Sopenharmony_ci	if (badblocks_init(&dev->badblocks, 0)) {
71162306a36Sopenharmony_ci		kfree(dev);
71262306a36Sopenharmony_ci		return NULL;
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	dev->size = g_gb * 1024;
71662306a36Sopenharmony_ci	dev->completion_nsec = g_completion_nsec;
71762306a36Sopenharmony_ci	dev->submit_queues = g_submit_queues;
71862306a36Sopenharmony_ci	dev->prev_submit_queues = g_submit_queues;
71962306a36Sopenharmony_ci	dev->poll_queues = g_poll_queues;
72062306a36Sopenharmony_ci	dev->prev_poll_queues = g_poll_queues;
72162306a36Sopenharmony_ci	dev->home_node = g_home_node;
72262306a36Sopenharmony_ci	dev->queue_mode = g_queue_mode;
72362306a36Sopenharmony_ci	dev->blocksize = g_bs;
72462306a36Sopenharmony_ci	dev->max_sectors = g_max_sectors;
72562306a36Sopenharmony_ci	dev->irqmode = g_irqmode;
72662306a36Sopenharmony_ci	dev->hw_queue_depth = g_hw_queue_depth;
72762306a36Sopenharmony_ci	dev->blocking = g_blocking;
72862306a36Sopenharmony_ci	dev->memory_backed = g_memory_backed;
72962306a36Sopenharmony_ci	dev->discard = g_discard;
73062306a36Sopenharmony_ci	dev->cache_size = g_cache_size;
73162306a36Sopenharmony_ci	dev->mbps = g_mbps;
73262306a36Sopenharmony_ci	dev->use_per_node_hctx = g_use_per_node_hctx;
73362306a36Sopenharmony_ci	dev->zoned = g_zoned;
73462306a36Sopenharmony_ci	dev->zone_size = g_zone_size;
73562306a36Sopenharmony_ci	dev->zone_capacity = g_zone_capacity;
73662306a36Sopenharmony_ci	dev->zone_nr_conv = g_zone_nr_conv;
73762306a36Sopenharmony_ci	dev->zone_max_open = g_zone_max_open;
73862306a36Sopenharmony_ci	dev->zone_max_active = g_zone_max_active;
73962306a36Sopenharmony_ci	dev->virt_boundary = g_virt_boundary;
74062306a36Sopenharmony_ci	dev->no_sched = g_no_sched;
74162306a36Sopenharmony_ci	dev->shared_tag_bitmap = g_shared_tag_bitmap;
74262306a36Sopenharmony_ci	return dev;
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic void null_free_dev(struct nullb_device *dev)
74662306a36Sopenharmony_ci{
74762306a36Sopenharmony_ci	if (!dev)
74862306a36Sopenharmony_ci		return;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	null_free_zoned_dev(dev);
75162306a36Sopenharmony_ci	badblocks_exit(&dev->badblocks);
75262306a36Sopenharmony_ci	kfree(dev);
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic void put_tag(struct nullb_queue *nq, unsigned int tag)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	clear_bit_unlock(tag, nq->tag_map);
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	if (waitqueue_active(&nq->wait))
76062306a36Sopenharmony_ci		wake_up(&nq->wait);
76162306a36Sopenharmony_ci}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_cistatic unsigned int get_tag(struct nullb_queue *nq)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	unsigned int tag;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	do {
76862306a36Sopenharmony_ci		tag = find_first_zero_bit(nq->tag_map, nq->queue_depth);
76962306a36Sopenharmony_ci		if (tag >= nq->queue_depth)
77062306a36Sopenharmony_ci			return -1U;
77162306a36Sopenharmony_ci	} while (test_and_set_bit_lock(tag, nq->tag_map));
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	return tag;
77462306a36Sopenharmony_ci}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_cistatic void free_cmd(struct nullb_cmd *cmd)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	put_tag(cmd->nq, cmd->tag);
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_cistatic struct nullb_cmd *__alloc_cmd(struct nullb_queue *nq)
78462306a36Sopenharmony_ci{
78562306a36Sopenharmony_ci	struct nullb_cmd *cmd;
78662306a36Sopenharmony_ci	unsigned int tag;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	tag = get_tag(nq);
78962306a36Sopenharmony_ci	if (tag != -1U) {
79062306a36Sopenharmony_ci		cmd = &nq->cmds[tag];
79162306a36Sopenharmony_ci		cmd->tag = tag;
79262306a36Sopenharmony_ci		cmd->error = BLK_STS_OK;
79362306a36Sopenharmony_ci		cmd->nq = nq;
79462306a36Sopenharmony_ci		if (nq->dev->irqmode == NULL_IRQ_TIMER) {
79562306a36Sopenharmony_ci			hrtimer_init(&cmd->timer, CLOCK_MONOTONIC,
79662306a36Sopenharmony_ci				     HRTIMER_MODE_REL);
79762306a36Sopenharmony_ci			cmd->timer.function = null_cmd_timer_expired;
79862306a36Sopenharmony_ci		}
79962306a36Sopenharmony_ci		return cmd;
80062306a36Sopenharmony_ci	}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	return NULL;
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_cistatic struct nullb_cmd *alloc_cmd(struct nullb_queue *nq, struct bio *bio)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	struct nullb_cmd *cmd;
80862306a36Sopenharmony_ci	DEFINE_WAIT(wait);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	do {
81162306a36Sopenharmony_ci		/*
81262306a36Sopenharmony_ci		 * This avoids multiple return statements, multiple calls to
81362306a36Sopenharmony_ci		 * __alloc_cmd() and a fast path call to prepare_to_wait().
81462306a36Sopenharmony_ci		 */
81562306a36Sopenharmony_ci		cmd = __alloc_cmd(nq);
81662306a36Sopenharmony_ci		if (cmd) {
81762306a36Sopenharmony_ci			cmd->bio = bio;
81862306a36Sopenharmony_ci			return cmd;
81962306a36Sopenharmony_ci		}
82062306a36Sopenharmony_ci		prepare_to_wait(&nq->wait, &wait, TASK_UNINTERRUPTIBLE);
82162306a36Sopenharmony_ci		io_schedule();
82262306a36Sopenharmony_ci		finish_wait(&nq->wait, &wait);
82362306a36Sopenharmony_ci	} while (1);
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_cistatic void end_cmd(struct nullb_cmd *cmd)
82762306a36Sopenharmony_ci{
82862306a36Sopenharmony_ci	int queue_mode = cmd->nq->dev->queue_mode;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	switch (queue_mode)  {
83162306a36Sopenharmony_ci	case NULL_Q_MQ:
83262306a36Sopenharmony_ci		blk_mq_end_request(cmd->rq, cmd->error);
83362306a36Sopenharmony_ci		return;
83462306a36Sopenharmony_ci	case NULL_Q_BIO:
83562306a36Sopenharmony_ci		cmd->bio->bi_status = cmd->error;
83662306a36Sopenharmony_ci		bio_endio(cmd->bio);
83762306a36Sopenharmony_ci		break;
83862306a36Sopenharmony_ci	}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	free_cmd(cmd);
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_cistatic enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
84462306a36Sopenharmony_ci{
84562306a36Sopenharmony_ci	end_cmd(container_of(timer, struct nullb_cmd, timer));
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	return HRTIMER_NORESTART;
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_cistatic void null_cmd_end_timer(struct nullb_cmd *cmd)
85162306a36Sopenharmony_ci{
85262306a36Sopenharmony_ci	ktime_t kt = cmd->nq->dev->completion_nsec;
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	hrtimer_start(&cmd->timer, kt, HRTIMER_MODE_REL);
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_cistatic void null_complete_rq(struct request *rq)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	end_cmd(blk_mq_rq_to_pdu(rq));
86062306a36Sopenharmony_ci}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_cistatic struct nullb_page *null_alloc_page(void)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	struct nullb_page *t_page;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	t_page = kmalloc(sizeof(struct nullb_page), GFP_NOIO);
86762306a36Sopenharmony_ci	if (!t_page)
86862306a36Sopenharmony_ci		return NULL;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	t_page->page = alloc_pages(GFP_NOIO, 0);
87162306a36Sopenharmony_ci	if (!t_page->page) {
87262306a36Sopenharmony_ci		kfree(t_page);
87362306a36Sopenharmony_ci		return NULL;
87462306a36Sopenharmony_ci	}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	memset(t_page->bitmap, 0, sizeof(t_page->bitmap));
87762306a36Sopenharmony_ci	return t_page;
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic void null_free_page(struct nullb_page *t_page)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	__set_bit(NULLB_PAGE_FREE, t_page->bitmap);
88362306a36Sopenharmony_ci	if (test_bit(NULLB_PAGE_LOCK, t_page->bitmap))
88462306a36Sopenharmony_ci		return;
88562306a36Sopenharmony_ci	__free_page(t_page->page);
88662306a36Sopenharmony_ci	kfree(t_page);
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_cistatic bool null_page_empty(struct nullb_page *page)
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci	int size = MAP_SZ - 2;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	return find_first_bit(page->bitmap, size) == size;
89462306a36Sopenharmony_ci}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_cistatic void null_free_sector(struct nullb *nullb, sector_t sector,
89762306a36Sopenharmony_ci	bool is_cache)
89862306a36Sopenharmony_ci{
89962306a36Sopenharmony_ci	unsigned int sector_bit;
90062306a36Sopenharmony_ci	u64 idx;
90162306a36Sopenharmony_ci	struct nullb_page *t_page, *ret;
90262306a36Sopenharmony_ci	struct radix_tree_root *root;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	root = is_cache ? &nullb->dev->cache : &nullb->dev->data;
90562306a36Sopenharmony_ci	idx = sector >> PAGE_SECTORS_SHIFT;
90662306a36Sopenharmony_ci	sector_bit = (sector & SECTOR_MASK);
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	t_page = radix_tree_lookup(root, idx);
90962306a36Sopenharmony_ci	if (t_page) {
91062306a36Sopenharmony_ci		__clear_bit(sector_bit, t_page->bitmap);
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci		if (null_page_empty(t_page)) {
91362306a36Sopenharmony_ci			ret = radix_tree_delete_item(root, idx, t_page);
91462306a36Sopenharmony_ci			WARN_ON(ret != t_page);
91562306a36Sopenharmony_ci			null_free_page(ret);
91662306a36Sopenharmony_ci			if (is_cache)
91762306a36Sopenharmony_ci				nullb->dev->curr_cache -= PAGE_SIZE;
91862306a36Sopenharmony_ci		}
91962306a36Sopenharmony_ci	}
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic struct nullb_page *null_radix_tree_insert(struct nullb *nullb, u64 idx,
92362306a36Sopenharmony_ci	struct nullb_page *t_page, bool is_cache)
92462306a36Sopenharmony_ci{
92562306a36Sopenharmony_ci	struct radix_tree_root *root;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	root = is_cache ? &nullb->dev->cache : &nullb->dev->data;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	if (radix_tree_insert(root, idx, t_page)) {
93062306a36Sopenharmony_ci		null_free_page(t_page);
93162306a36Sopenharmony_ci		t_page = radix_tree_lookup(root, idx);
93262306a36Sopenharmony_ci		WARN_ON(!t_page || t_page->page->index != idx);
93362306a36Sopenharmony_ci	} else if (is_cache)
93462306a36Sopenharmony_ci		nullb->dev->curr_cache += PAGE_SIZE;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	return t_page;
93762306a36Sopenharmony_ci}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_cistatic void null_free_device_storage(struct nullb_device *dev, bool is_cache)
94062306a36Sopenharmony_ci{
94162306a36Sopenharmony_ci	unsigned long pos = 0;
94262306a36Sopenharmony_ci	int nr_pages;
94362306a36Sopenharmony_ci	struct nullb_page *ret, *t_pages[FREE_BATCH];
94462306a36Sopenharmony_ci	struct radix_tree_root *root;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	root = is_cache ? &dev->cache : &dev->data;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	do {
94962306a36Sopenharmony_ci		int i;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci		nr_pages = radix_tree_gang_lookup(root,
95262306a36Sopenharmony_ci				(void **)t_pages, pos, FREE_BATCH);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci		for (i = 0; i < nr_pages; i++) {
95562306a36Sopenharmony_ci			pos = t_pages[i]->page->index;
95662306a36Sopenharmony_ci			ret = radix_tree_delete_item(root, pos, t_pages[i]);
95762306a36Sopenharmony_ci			WARN_ON(ret != t_pages[i]);
95862306a36Sopenharmony_ci			null_free_page(ret);
95962306a36Sopenharmony_ci		}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci		pos++;
96262306a36Sopenharmony_ci	} while (nr_pages == FREE_BATCH);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	if (is_cache)
96562306a36Sopenharmony_ci		dev->curr_cache = 0;
96662306a36Sopenharmony_ci}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_cistatic struct nullb_page *__null_lookup_page(struct nullb *nullb,
96962306a36Sopenharmony_ci	sector_t sector, bool for_write, bool is_cache)
97062306a36Sopenharmony_ci{
97162306a36Sopenharmony_ci	unsigned int sector_bit;
97262306a36Sopenharmony_ci	u64 idx;
97362306a36Sopenharmony_ci	struct nullb_page *t_page;
97462306a36Sopenharmony_ci	struct radix_tree_root *root;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	idx = sector >> PAGE_SECTORS_SHIFT;
97762306a36Sopenharmony_ci	sector_bit = (sector & SECTOR_MASK);
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	root = is_cache ? &nullb->dev->cache : &nullb->dev->data;
98062306a36Sopenharmony_ci	t_page = radix_tree_lookup(root, idx);
98162306a36Sopenharmony_ci	WARN_ON(t_page && t_page->page->index != idx);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	if (t_page && (for_write || test_bit(sector_bit, t_page->bitmap)))
98462306a36Sopenharmony_ci		return t_page;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	return NULL;
98762306a36Sopenharmony_ci}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_cistatic struct nullb_page *null_lookup_page(struct nullb *nullb,
99062306a36Sopenharmony_ci	sector_t sector, bool for_write, bool ignore_cache)
99162306a36Sopenharmony_ci{
99262306a36Sopenharmony_ci	struct nullb_page *page = NULL;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	if (!ignore_cache)
99562306a36Sopenharmony_ci		page = __null_lookup_page(nullb, sector, for_write, true);
99662306a36Sopenharmony_ci	if (page)
99762306a36Sopenharmony_ci		return page;
99862306a36Sopenharmony_ci	return __null_lookup_page(nullb, sector, for_write, false);
99962306a36Sopenharmony_ci}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_cistatic struct nullb_page *null_insert_page(struct nullb *nullb,
100262306a36Sopenharmony_ci					   sector_t sector, bool ignore_cache)
100362306a36Sopenharmony_ci	__releases(&nullb->lock)
100462306a36Sopenharmony_ci	__acquires(&nullb->lock)
100562306a36Sopenharmony_ci{
100662306a36Sopenharmony_ci	u64 idx;
100762306a36Sopenharmony_ci	struct nullb_page *t_page;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	t_page = null_lookup_page(nullb, sector, true, ignore_cache);
101062306a36Sopenharmony_ci	if (t_page)
101162306a36Sopenharmony_ci		return t_page;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	spin_unlock_irq(&nullb->lock);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	t_page = null_alloc_page();
101662306a36Sopenharmony_ci	if (!t_page)
101762306a36Sopenharmony_ci		goto out_lock;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	if (radix_tree_preload(GFP_NOIO))
102062306a36Sopenharmony_ci		goto out_freepage;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	spin_lock_irq(&nullb->lock);
102362306a36Sopenharmony_ci	idx = sector >> PAGE_SECTORS_SHIFT;
102462306a36Sopenharmony_ci	t_page->page->index = idx;
102562306a36Sopenharmony_ci	t_page = null_radix_tree_insert(nullb, idx, t_page, !ignore_cache);
102662306a36Sopenharmony_ci	radix_tree_preload_end();
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	return t_page;
102962306a36Sopenharmony_ciout_freepage:
103062306a36Sopenharmony_ci	null_free_page(t_page);
103162306a36Sopenharmony_ciout_lock:
103262306a36Sopenharmony_ci	spin_lock_irq(&nullb->lock);
103362306a36Sopenharmony_ci	return null_lookup_page(nullb, sector, true, ignore_cache);
103462306a36Sopenharmony_ci}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_cistatic int null_flush_cache_page(struct nullb *nullb, struct nullb_page *c_page)
103762306a36Sopenharmony_ci{
103862306a36Sopenharmony_ci	int i;
103962306a36Sopenharmony_ci	unsigned int offset;
104062306a36Sopenharmony_ci	u64 idx;
104162306a36Sopenharmony_ci	struct nullb_page *t_page, *ret;
104262306a36Sopenharmony_ci	void *dst, *src;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	idx = c_page->page->index;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	t_page = null_insert_page(nullb, idx << PAGE_SECTORS_SHIFT, true);
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	__clear_bit(NULLB_PAGE_LOCK, c_page->bitmap);
104962306a36Sopenharmony_ci	if (test_bit(NULLB_PAGE_FREE, c_page->bitmap)) {
105062306a36Sopenharmony_ci		null_free_page(c_page);
105162306a36Sopenharmony_ci		if (t_page && null_page_empty(t_page)) {
105262306a36Sopenharmony_ci			ret = radix_tree_delete_item(&nullb->dev->data,
105362306a36Sopenharmony_ci				idx, t_page);
105462306a36Sopenharmony_ci			null_free_page(t_page);
105562306a36Sopenharmony_ci		}
105662306a36Sopenharmony_ci		return 0;
105762306a36Sopenharmony_ci	}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	if (!t_page)
106062306a36Sopenharmony_ci		return -ENOMEM;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	src = kmap_local_page(c_page->page);
106362306a36Sopenharmony_ci	dst = kmap_local_page(t_page->page);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	for (i = 0; i < PAGE_SECTORS;
106662306a36Sopenharmony_ci			i += (nullb->dev->blocksize >> SECTOR_SHIFT)) {
106762306a36Sopenharmony_ci		if (test_bit(i, c_page->bitmap)) {
106862306a36Sopenharmony_ci			offset = (i << SECTOR_SHIFT);
106962306a36Sopenharmony_ci			memcpy(dst + offset, src + offset,
107062306a36Sopenharmony_ci				nullb->dev->blocksize);
107162306a36Sopenharmony_ci			__set_bit(i, t_page->bitmap);
107262306a36Sopenharmony_ci		}
107362306a36Sopenharmony_ci	}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	kunmap_local(dst);
107662306a36Sopenharmony_ci	kunmap_local(src);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	ret = radix_tree_delete_item(&nullb->dev->cache, idx, c_page);
107962306a36Sopenharmony_ci	null_free_page(ret);
108062306a36Sopenharmony_ci	nullb->dev->curr_cache -= PAGE_SIZE;
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	return 0;
108362306a36Sopenharmony_ci}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_cistatic int null_make_cache_space(struct nullb *nullb, unsigned long n)
108662306a36Sopenharmony_ci{
108762306a36Sopenharmony_ci	int i, err, nr_pages;
108862306a36Sopenharmony_ci	struct nullb_page *c_pages[FREE_BATCH];
108962306a36Sopenharmony_ci	unsigned long flushed = 0, one_round;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ciagain:
109262306a36Sopenharmony_ci	if ((nullb->dev->cache_size * 1024 * 1024) >
109362306a36Sopenharmony_ci	     nullb->dev->curr_cache + n || nullb->dev->curr_cache == 0)
109462306a36Sopenharmony_ci		return 0;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	nr_pages = radix_tree_gang_lookup(&nullb->dev->cache,
109762306a36Sopenharmony_ci			(void **)c_pages, nullb->cache_flush_pos, FREE_BATCH);
109862306a36Sopenharmony_ci	/*
109962306a36Sopenharmony_ci	 * nullb_flush_cache_page could unlock before using the c_pages. To
110062306a36Sopenharmony_ci	 * avoid race, we don't allow page free
110162306a36Sopenharmony_ci	 */
110262306a36Sopenharmony_ci	for (i = 0; i < nr_pages; i++) {
110362306a36Sopenharmony_ci		nullb->cache_flush_pos = c_pages[i]->page->index;
110462306a36Sopenharmony_ci		/*
110562306a36Sopenharmony_ci		 * We found the page which is being flushed to disk by other
110662306a36Sopenharmony_ci		 * threads
110762306a36Sopenharmony_ci		 */
110862306a36Sopenharmony_ci		if (test_bit(NULLB_PAGE_LOCK, c_pages[i]->bitmap))
110962306a36Sopenharmony_ci			c_pages[i] = NULL;
111062306a36Sopenharmony_ci		else
111162306a36Sopenharmony_ci			__set_bit(NULLB_PAGE_LOCK, c_pages[i]->bitmap);
111262306a36Sopenharmony_ci	}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	one_round = 0;
111562306a36Sopenharmony_ci	for (i = 0; i < nr_pages; i++) {
111662306a36Sopenharmony_ci		if (c_pages[i] == NULL)
111762306a36Sopenharmony_ci			continue;
111862306a36Sopenharmony_ci		err = null_flush_cache_page(nullb, c_pages[i]);
111962306a36Sopenharmony_ci		if (err)
112062306a36Sopenharmony_ci			return err;
112162306a36Sopenharmony_ci		one_round++;
112262306a36Sopenharmony_ci	}
112362306a36Sopenharmony_ci	flushed += one_round << PAGE_SHIFT;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	if (n > flushed) {
112662306a36Sopenharmony_ci		if (nr_pages == 0)
112762306a36Sopenharmony_ci			nullb->cache_flush_pos = 0;
112862306a36Sopenharmony_ci		if (one_round == 0) {
112962306a36Sopenharmony_ci			/* give other threads a chance */
113062306a36Sopenharmony_ci			spin_unlock_irq(&nullb->lock);
113162306a36Sopenharmony_ci			spin_lock_irq(&nullb->lock);
113262306a36Sopenharmony_ci		}
113362306a36Sopenharmony_ci		goto again;
113462306a36Sopenharmony_ci	}
113562306a36Sopenharmony_ci	return 0;
113662306a36Sopenharmony_ci}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_cistatic int copy_to_nullb(struct nullb *nullb, struct page *source,
113962306a36Sopenharmony_ci	unsigned int off, sector_t sector, size_t n, bool is_fua)
114062306a36Sopenharmony_ci{
114162306a36Sopenharmony_ci	size_t temp, count = 0;
114262306a36Sopenharmony_ci	unsigned int offset;
114362306a36Sopenharmony_ci	struct nullb_page *t_page;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	while (count < n) {
114662306a36Sopenharmony_ci		temp = min_t(size_t, nullb->dev->blocksize, n - count);
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci		if (null_cache_active(nullb) && !is_fua)
114962306a36Sopenharmony_ci			null_make_cache_space(nullb, PAGE_SIZE);
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci		offset = (sector & SECTOR_MASK) << SECTOR_SHIFT;
115262306a36Sopenharmony_ci		t_page = null_insert_page(nullb, sector,
115362306a36Sopenharmony_ci			!null_cache_active(nullb) || is_fua);
115462306a36Sopenharmony_ci		if (!t_page)
115562306a36Sopenharmony_ci			return -ENOSPC;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci		memcpy_page(t_page->page, offset, source, off + count, temp);
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci		__set_bit(sector & SECTOR_MASK, t_page->bitmap);
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci		if (is_fua)
116262306a36Sopenharmony_ci			null_free_sector(nullb, sector, true);
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci		count += temp;
116562306a36Sopenharmony_ci		sector += temp >> SECTOR_SHIFT;
116662306a36Sopenharmony_ci	}
116762306a36Sopenharmony_ci	return 0;
116862306a36Sopenharmony_ci}
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_cistatic int copy_from_nullb(struct nullb *nullb, struct page *dest,
117162306a36Sopenharmony_ci	unsigned int off, sector_t sector, size_t n)
117262306a36Sopenharmony_ci{
117362306a36Sopenharmony_ci	size_t temp, count = 0;
117462306a36Sopenharmony_ci	unsigned int offset;
117562306a36Sopenharmony_ci	struct nullb_page *t_page;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	while (count < n) {
117862306a36Sopenharmony_ci		temp = min_t(size_t, nullb->dev->blocksize, n - count);
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci		offset = (sector & SECTOR_MASK) << SECTOR_SHIFT;
118162306a36Sopenharmony_ci		t_page = null_lookup_page(nullb, sector, false,
118262306a36Sopenharmony_ci			!null_cache_active(nullb));
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci		if (t_page)
118562306a36Sopenharmony_ci			memcpy_page(dest, off + count, t_page->page, offset,
118662306a36Sopenharmony_ci				    temp);
118762306a36Sopenharmony_ci		else
118862306a36Sopenharmony_ci			zero_user(dest, off + count, temp);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci		count += temp;
119162306a36Sopenharmony_ci		sector += temp >> SECTOR_SHIFT;
119262306a36Sopenharmony_ci	}
119362306a36Sopenharmony_ci	return 0;
119462306a36Sopenharmony_ci}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_cistatic void nullb_fill_pattern(struct nullb *nullb, struct page *page,
119762306a36Sopenharmony_ci			       unsigned int len, unsigned int off)
119862306a36Sopenharmony_ci{
119962306a36Sopenharmony_ci	memset_page(page, off, 0xff, len);
120062306a36Sopenharmony_ci}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ciblk_status_t null_handle_discard(struct nullb_device *dev,
120362306a36Sopenharmony_ci				 sector_t sector, sector_t nr_sectors)
120462306a36Sopenharmony_ci{
120562306a36Sopenharmony_ci	struct nullb *nullb = dev->nullb;
120662306a36Sopenharmony_ci	size_t n = nr_sectors << SECTOR_SHIFT;
120762306a36Sopenharmony_ci	size_t temp;
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	spin_lock_irq(&nullb->lock);
121062306a36Sopenharmony_ci	while (n > 0) {
121162306a36Sopenharmony_ci		temp = min_t(size_t, n, dev->blocksize);
121262306a36Sopenharmony_ci		null_free_sector(nullb, sector, false);
121362306a36Sopenharmony_ci		if (null_cache_active(nullb))
121462306a36Sopenharmony_ci			null_free_sector(nullb, sector, true);
121562306a36Sopenharmony_ci		sector += temp >> SECTOR_SHIFT;
121662306a36Sopenharmony_ci		n -= temp;
121762306a36Sopenharmony_ci	}
121862306a36Sopenharmony_ci	spin_unlock_irq(&nullb->lock);
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	return BLK_STS_OK;
122162306a36Sopenharmony_ci}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_cistatic int null_handle_flush(struct nullb *nullb)
122462306a36Sopenharmony_ci{
122562306a36Sopenharmony_ci	int err;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	if (!null_cache_active(nullb))
122862306a36Sopenharmony_ci		return 0;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	spin_lock_irq(&nullb->lock);
123162306a36Sopenharmony_ci	while (true) {
123262306a36Sopenharmony_ci		err = null_make_cache_space(nullb,
123362306a36Sopenharmony_ci			nullb->dev->cache_size * 1024 * 1024);
123462306a36Sopenharmony_ci		if (err || nullb->dev->curr_cache == 0)
123562306a36Sopenharmony_ci			break;
123662306a36Sopenharmony_ci	}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	WARN_ON(!radix_tree_empty(&nullb->dev->cache));
123962306a36Sopenharmony_ci	spin_unlock_irq(&nullb->lock);
124062306a36Sopenharmony_ci	return err;
124162306a36Sopenharmony_ci}
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_cistatic int null_transfer(struct nullb *nullb, struct page *page,
124462306a36Sopenharmony_ci	unsigned int len, unsigned int off, bool is_write, sector_t sector,
124562306a36Sopenharmony_ci	bool is_fua)
124662306a36Sopenharmony_ci{
124762306a36Sopenharmony_ci	struct nullb_device *dev = nullb->dev;
124862306a36Sopenharmony_ci	unsigned int valid_len = len;
124962306a36Sopenharmony_ci	int err = 0;
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	if (!is_write) {
125262306a36Sopenharmony_ci		if (dev->zoned)
125362306a36Sopenharmony_ci			valid_len = null_zone_valid_read_len(nullb,
125462306a36Sopenharmony_ci				sector, len);
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci		if (valid_len) {
125762306a36Sopenharmony_ci			err = copy_from_nullb(nullb, page, off,
125862306a36Sopenharmony_ci				sector, valid_len);
125962306a36Sopenharmony_ci			off += valid_len;
126062306a36Sopenharmony_ci			len -= valid_len;
126162306a36Sopenharmony_ci		}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci		if (len)
126462306a36Sopenharmony_ci			nullb_fill_pattern(nullb, page, len, off);
126562306a36Sopenharmony_ci		flush_dcache_page(page);
126662306a36Sopenharmony_ci	} else {
126762306a36Sopenharmony_ci		flush_dcache_page(page);
126862306a36Sopenharmony_ci		err = copy_to_nullb(nullb, page, off, sector, len, is_fua);
126962306a36Sopenharmony_ci	}
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	return err;
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cistatic int null_handle_rq(struct nullb_cmd *cmd)
127562306a36Sopenharmony_ci{
127662306a36Sopenharmony_ci	struct request *rq = cmd->rq;
127762306a36Sopenharmony_ci	struct nullb *nullb = cmd->nq->dev->nullb;
127862306a36Sopenharmony_ci	int err;
127962306a36Sopenharmony_ci	unsigned int len;
128062306a36Sopenharmony_ci	sector_t sector = blk_rq_pos(rq);
128162306a36Sopenharmony_ci	struct req_iterator iter;
128262306a36Sopenharmony_ci	struct bio_vec bvec;
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	spin_lock_irq(&nullb->lock);
128562306a36Sopenharmony_ci	rq_for_each_segment(bvec, rq, iter) {
128662306a36Sopenharmony_ci		len = bvec.bv_len;
128762306a36Sopenharmony_ci		err = null_transfer(nullb, bvec.bv_page, len, bvec.bv_offset,
128862306a36Sopenharmony_ci				     op_is_write(req_op(rq)), sector,
128962306a36Sopenharmony_ci				     rq->cmd_flags & REQ_FUA);
129062306a36Sopenharmony_ci		if (err) {
129162306a36Sopenharmony_ci			spin_unlock_irq(&nullb->lock);
129262306a36Sopenharmony_ci			return err;
129362306a36Sopenharmony_ci		}
129462306a36Sopenharmony_ci		sector += len >> SECTOR_SHIFT;
129562306a36Sopenharmony_ci	}
129662306a36Sopenharmony_ci	spin_unlock_irq(&nullb->lock);
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	return 0;
129962306a36Sopenharmony_ci}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_cistatic int null_handle_bio(struct nullb_cmd *cmd)
130262306a36Sopenharmony_ci{
130362306a36Sopenharmony_ci	struct bio *bio = cmd->bio;
130462306a36Sopenharmony_ci	struct nullb *nullb = cmd->nq->dev->nullb;
130562306a36Sopenharmony_ci	int err;
130662306a36Sopenharmony_ci	unsigned int len;
130762306a36Sopenharmony_ci	sector_t sector = bio->bi_iter.bi_sector;
130862306a36Sopenharmony_ci	struct bio_vec bvec;
130962306a36Sopenharmony_ci	struct bvec_iter iter;
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	spin_lock_irq(&nullb->lock);
131262306a36Sopenharmony_ci	bio_for_each_segment(bvec, bio, iter) {
131362306a36Sopenharmony_ci		len = bvec.bv_len;
131462306a36Sopenharmony_ci		err = null_transfer(nullb, bvec.bv_page, len, bvec.bv_offset,
131562306a36Sopenharmony_ci				     op_is_write(bio_op(bio)), sector,
131662306a36Sopenharmony_ci				     bio->bi_opf & REQ_FUA);
131762306a36Sopenharmony_ci		if (err) {
131862306a36Sopenharmony_ci			spin_unlock_irq(&nullb->lock);
131962306a36Sopenharmony_ci			return err;
132062306a36Sopenharmony_ci		}
132162306a36Sopenharmony_ci		sector += len >> SECTOR_SHIFT;
132262306a36Sopenharmony_ci	}
132362306a36Sopenharmony_ci	spin_unlock_irq(&nullb->lock);
132462306a36Sopenharmony_ci	return 0;
132562306a36Sopenharmony_ci}
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_cistatic void null_stop_queue(struct nullb *nullb)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci	struct request_queue *q = nullb->q;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	if (nullb->dev->queue_mode == NULL_Q_MQ)
133262306a36Sopenharmony_ci		blk_mq_stop_hw_queues(q);
133362306a36Sopenharmony_ci}
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_cistatic void null_restart_queue_async(struct nullb *nullb)
133662306a36Sopenharmony_ci{
133762306a36Sopenharmony_ci	struct request_queue *q = nullb->q;
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	if (nullb->dev->queue_mode == NULL_Q_MQ)
134062306a36Sopenharmony_ci		blk_mq_start_stopped_hw_queues(q, true);
134162306a36Sopenharmony_ci}
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_cistatic inline blk_status_t null_handle_throttled(struct nullb_cmd *cmd)
134462306a36Sopenharmony_ci{
134562306a36Sopenharmony_ci	struct nullb_device *dev = cmd->nq->dev;
134662306a36Sopenharmony_ci	struct nullb *nullb = dev->nullb;
134762306a36Sopenharmony_ci	blk_status_t sts = BLK_STS_OK;
134862306a36Sopenharmony_ci	struct request *rq = cmd->rq;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	if (!hrtimer_active(&nullb->bw_timer))
135162306a36Sopenharmony_ci		hrtimer_restart(&nullb->bw_timer);
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	if (atomic_long_sub_return(blk_rq_bytes(rq), &nullb->cur_bytes) < 0) {
135462306a36Sopenharmony_ci		null_stop_queue(nullb);
135562306a36Sopenharmony_ci		/* race with timer */
135662306a36Sopenharmony_ci		if (atomic_long_read(&nullb->cur_bytes) > 0)
135762306a36Sopenharmony_ci			null_restart_queue_async(nullb);
135862306a36Sopenharmony_ci		/* requeue request */
135962306a36Sopenharmony_ci		sts = BLK_STS_DEV_RESOURCE;
136062306a36Sopenharmony_ci	}
136162306a36Sopenharmony_ci	return sts;
136262306a36Sopenharmony_ci}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_cistatic inline blk_status_t null_handle_badblocks(struct nullb_cmd *cmd,
136562306a36Sopenharmony_ci						 sector_t sector,
136662306a36Sopenharmony_ci						 sector_t nr_sectors)
136762306a36Sopenharmony_ci{
136862306a36Sopenharmony_ci	struct badblocks *bb = &cmd->nq->dev->badblocks;
136962306a36Sopenharmony_ci	sector_t first_bad;
137062306a36Sopenharmony_ci	int bad_sectors;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	if (badblocks_check(bb, sector, nr_sectors, &first_bad, &bad_sectors))
137362306a36Sopenharmony_ci		return BLK_STS_IOERR;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	return BLK_STS_OK;
137662306a36Sopenharmony_ci}
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_cistatic inline blk_status_t null_handle_memory_backed(struct nullb_cmd *cmd,
137962306a36Sopenharmony_ci						     enum req_op op,
138062306a36Sopenharmony_ci						     sector_t sector,
138162306a36Sopenharmony_ci						     sector_t nr_sectors)
138262306a36Sopenharmony_ci{
138362306a36Sopenharmony_ci	struct nullb_device *dev = cmd->nq->dev;
138462306a36Sopenharmony_ci	int err;
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	if (op == REQ_OP_DISCARD)
138762306a36Sopenharmony_ci		return null_handle_discard(dev, sector, nr_sectors);
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	if (dev->queue_mode == NULL_Q_BIO)
139062306a36Sopenharmony_ci		err = null_handle_bio(cmd);
139162306a36Sopenharmony_ci	else
139262306a36Sopenharmony_ci		err = null_handle_rq(cmd);
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	return errno_to_blk_status(err);
139562306a36Sopenharmony_ci}
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_cistatic void nullb_zero_read_cmd_buffer(struct nullb_cmd *cmd)
139862306a36Sopenharmony_ci{
139962306a36Sopenharmony_ci	struct nullb_device *dev = cmd->nq->dev;
140062306a36Sopenharmony_ci	struct bio *bio;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	if (dev->memory_backed)
140362306a36Sopenharmony_ci		return;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	if (dev->queue_mode == NULL_Q_BIO && bio_op(cmd->bio) == REQ_OP_READ) {
140662306a36Sopenharmony_ci		zero_fill_bio(cmd->bio);
140762306a36Sopenharmony_ci	} else if (req_op(cmd->rq) == REQ_OP_READ) {
140862306a36Sopenharmony_ci		__rq_for_each_bio(bio, cmd->rq)
140962306a36Sopenharmony_ci			zero_fill_bio(bio);
141062306a36Sopenharmony_ci	}
141162306a36Sopenharmony_ci}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_cistatic inline void nullb_complete_cmd(struct nullb_cmd *cmd)
141462306a36Sopenharmony_ci{
141562306a36Sopenharmony_ci	/*
141662306a36Sopenharmony_ci	 * Since root privileges are required to configure the null_blk
141762306a36Sopenharmony_ci	 * driver, it is fine that this driver does not initialize the
141862306a36Sopenharmony_ci	 * data buffers of read commands. Zero-initialize these buffers
141962306a36Sopenharmony_ci	 * anyway if KMSAN is enabled to prevent that KMSAN complains
142062306a36Sopenharmony_ci	 * about null_blk not initializing read data buffers.
142162306a36Sopenharmony_ci	 */
142262306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_KMSAN))
142362306a36Sopenharmony_ci		nullb_zero_read_cmd_buffer(cmd);
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	/* Complete IO by inline, softirq or timer */
142662306a36Sopenharmony_ci	switch (cmd->nq->dev->irqmode) {
142762306a36Sopenharmony_ci	case NULL_IRQ_SOFTIRQ:
142862306a36Sopenharmony_ci		switch (cmd->nq->dev->queue_mode) {
142962306a36Sopenharmony_ci		case NULL_Q_MQ:
143062306a36Sopenharmony_ci			blk_mq_complete_request(cmd->rq);
143162306a36Sopenharmony_ci			break;
143262306a36Sopenharmony_ci		case NULL_Q_BIO:
143362306a36Sopenharmony_ci			/*
143462306a36Sopenharmony_ci			 * XXX: no proper submitting cpu information available.
143562306a36Sopenharmony_ci			 */
143662306a36Sopenharmony_ci			end_cmd(cmd);
143762306a36Sopenharmony_ci			break;
143862306a36Sopenharmony_ci		}
143962306a36Sopenharmony_ci		break;
144062306a36Sopenharmony_ci	case NULL_IRQ_NONE:
144162306a36Sopenharmony_ci		end_cmd(cmd);
144262306a36Sopenharmony_ci		break;
144362306a36Sopenharmony_ci	case NULL_IRQ_TIMER:
144462306a36Sopenharmony_ci		null_cmd_end_timer(cmd);
144562306a36Sopenharmony_ci		break;
144662306a36Sopenharmony_ci	}
144762306a36Sopenharmony_ci}
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ciblk_status_t null_process_cmd(struct nullb_cmd *cmd, enum req_op op,
145062306a36Sopenharmony_ci			      sector_t sector, unsigned int nr_sectors)
145162306a36Sopenharmony_ci{
145262306a36Sopenharmony_ci	struct nullb_device *dev = cmd->nq->dev;
145362306a36Sopenharmony_ci	blk_status_t ret;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	if (dev->badblocks.shift != -1) {
145662306a36Sopenharmony_ci		ret = null_handle_badblocks(cmd, sector, nr_sectors);
145762306a36Sopenharmony_ci		if (ret != BLK_STS_OK)
145862306a36Sopenharmony_ci			return ret;
145962306a36Sopenharmony_ci	}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	if (dev->memory_backed)
146262306a36Sopenharmony_ci		return null_handle_memory_backed(cmd, op, sector, nr_sectors);
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	return BLK_STS_OK;
146562306a36Sopenharmony_ci}
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_cistatic blk_status_t null_handle_cmd(struct nullb_cmd *cmd, sector_t sector,
146862306a36Sopenharmony_ci				    sector_t nr_sectors, enum req_op op)
146962306a36Sopenharmony_ci{
147062306a36Sopenharmony_ci	struct nullb_device *dev = cmd->nq->dev;
147162306a36Sopenharmony_ci	struct nullb *nullb = dev->nullb;
147262306a36Sopenharmony_ci	blk_status_t sts;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	if (test_bit(NULLB_DEV_FL_THROTTLED, &dev->flags)) {
147562306a36Sopenharmony_ci		sts = null_handle_throttled(cmd);
147662306a36Sopenharmony_ci		if (sts != BLK_STS_OK)
147762306a36Sopenharmony_ci			return sts;
147862306a36Sopenharmony_ci	}
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	if (op == REQ_OP_FLUSH) {
148162306a36Sopenharmony_ci		cmd->error = errno_to_blk_status(null_handle_flush(nullb));
148262306a36Sopenharmony_ci		goto out;
148362306a36Sopenharmony_ci	}
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	if (dev->zoned)
148662306a36Sopenharmony_ci		sts = null_process_zoned_cmd(cmd, op, sector, nr_sectors);
148762306a36Sopenharmony_ci	else
148862306a36Sopenharmony_ci		sts = null_process_cmd(cmd, op, sector, nr_sectors);
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	/* Do not overwrite errors (e.g. timeout errors) */
149162306a36Sopenharmony_ci	if (cmd->error == BLK_STS_OK)
149262306a36Sopenharmony_ci		cmd->error = sts;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ciout:
149562306a36Sopenharmony_ci	nullb_complete_cmd(cmd);
149662306a36Sopenharmony_ci	return BLK_STS_OK;
149762306a36Sopenharmony_ci}
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_cistatic enum hrtimer_restart nullb_bwtimer_fn(struct hrtimer *timer)
150062306a36Sopenharmony_ci{
150162306a36Sopenharmony_ci	struct nullb *nullb = container_of(timer, struct nullb, bw_timer);
150262306a36Sopenharmony_ci	ktime_t timer_interval = ktime_set(0, TIMER_INTERVAL);
150362306a36Sopenharmony_ci	unsigned int mbps = nullb->dev->mbps;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	if (atomic_long_read(&nullb->cur_bytes) == mb_per_tick(mbps))
150662306a36Sopenharmony_ci		return HRTIMER_NORESTART;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	atomic_long_set(&nullb->cur_bytes, mb_per_tick(mbps));
150962306a36Sopenharmony_ci	null_restart_queue_async(nullb);
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	hrtimer_forward_now(&nullb->bw_timer, timer_interval);
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	return HRTIMER_RESTART;
151462306a36Sopenharmony_ci}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_cistatic void nullb_setup_bwtimer(struct nullb *nullb)
151762306a36Sopenharmony_ci{
151862306a36Sopenharmony_ci	ktime_t timer_interval = ktime_set(0, TIMER_INTERVAL);
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	hrtimer_init(&nullb->bw_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
152162306a36Sopenharmony_ci	nullb->bw_timer.function = nullb_bwtimer_fn;
152262306a36Sopenharmony_ci	atomic_long_set(&nullb->cur_bytes, mb_per_tick(nullb->dev->mbps));
152362306a36Sopenharmony_ci	hrtimer_start(&nullb->bw_timer, timer_interval, HRTIMER_MODE_REL);
152462306a36Sopenharmony_ci}
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_cistatic struct nullb_queue *nullb_to_queue(struct nullb *nullb)
152762306a36Sopenharmony_ci{
152862306a36Sopenharmony_ci	int index = 0;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	if (nullb->nr_queues != 1)
153162306a36Sopenharmony_ci		index = raw_smp_processor_id() / ((nr_cpu_ids + nullb->nr_queues - 1) / nullb->nr_queues);
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	return &nullb->queues[index];
153462306a36Sopenharmony_ci}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_cistatic void null_submit_bio(struct bio *bio)
153762306a36Sopenharmony_ci{
153862306a36Sopenharmony_ci	sector_t sector = bio->bi_iter.bi_sector;
153962306a36Sopenharmony_ci	sector_t nr_sectors = bio_sectors(bio);
154062306a36Sopenharmony_ci	struct nullb *nullb = bio->bi_bdev->bd_disk->private_data;
154162306a36Sopenharmony_ci	struct nullb_queue *nq = nullb_to_queue(nullb);
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	null_handle_cmd(alloc_cmd(nq, bio), sector, nr_sectors, bio_op(bio));
154462306a36Sopenharmony_ci}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_cistatic bool should_timeout_request(struct request *rq)
154962306a36Sopenharmony_ci{
155062306a36Sopenharmony_ci	struct nullb_cmd *cmd = blk_mq_rq_to_pdu(rq);
155162306a36Sopenharmony_ci	struct nullb_device *dev = cmd->nq->dev;
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	return should_fail(&dev->timeout_config.attr, 1);
155462306a36Sopenharmony_ci}
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_cistatic bool should_requeue_request(struct request *rq)
155762306a36Sopenharmony_ci{
155862306a36Sopenharmony_ci	struct nullb_cmd *cmd = blk_mq_rq_to_pdu(rq);
155962306a36Sopenharmony_ci	struct nullb_device *dev = cmd->nq->dev;
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	return should_fail(&dev->requeue_config.attr, 1);
156262306a36Sopenharmony_ci}
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_cistatic bool should_init_hctx_fail(struct nullb_device *dev)
156562306a36Sopenharmony_ci{
156662306a36Sopenharmony_ci	return should_fail(&dev->init_hctx_fault_config.attr, 1);
156762306a36Sopenharmony_ci}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci#else
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_cistatic bool should_timeout_request(struct request *rq)
157262306a36Sopenharmony_ci{
157362306a36Sopenharmony_ci	return false;
157462306a36Sopenharmony_ci}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_cistatic bool should_requeue_request(struct request *rq)
157762306a36Sopenharmony_ci{
157862306a36Sopenharmony_ci	return false;
157962306a36Sopenharmony_ci}
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_cistatic bool should_init_hctx_fail(struct nullb_device *dev)
158262306a36Sopenharmony_ci{
158362306a36Sopenharmony_ci	return false;
158462306a36Sopenharmony_ci}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci#endif
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_cistatic void null_map_queues(struct blk_mq_tag_set *set)
158962306a36Sopenharmony_ci{
159062306a36Sopenharmony_ci	struct nullb *nullb = set->driver_data;
159162306a36Sopenharmony_ci	int i, qoff;
159262306a36Sopenharmony_ci	unsigned int submit_queues = g_submit_queues;
159362306a36Sopenharmony_ci	unsigned int poll_queues = g_poll_queues;
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	if (nullb) {
159662306a36Sopenharmony_ci		struct nullb_device *dev = nullb->dev;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci		/*
159962306a36Sopenharmony_ci		 * Refer nr_hw_queues of the tag set to check if the expected
160062306a36Sopenharmony_ci		 * number of hardware queues are prepared. If block layer failed
160162306a36Sopenharmony_ci		 * to prepare them, use previous numbers of submit queues and
160262306a36Sopenharmony_ci		 * poll queues to map queues.
160362306a36Sopenharmony_ci		 */
160462306a36Sopenharmony_ci		if (set->nr_hw_queues ==
160562306a36Sopenharmony_ci		    dev->submit_queues + dev->poll_queues) {
160662306a36Sopenharmony_ci			submit_queues = dev->submit_queues;
160762306a36Sopenharmony_ci			poll_queues = dev->poll_queues;
160862306a36Sopenharmony_ci		} else if (set->nr_hw_queues ==
160962306a36Sopenharmony_ci			   dev->prev_submit_queues + dev->prev_poll_queues) {
161062306a36Sopenharmony_ci			submit_queues = dev->prev_submit_queues;
161162306a36Sopenharmony_ci			poll_queues = dev->prev_poll_queues;
161262306a36Sopenharmony_ci		} else {
161362306a36Sopenharmony_ci			pr_warn("tag set has unexpected nr_hw_queues: %d\n",
161462306a36Sopenharmony_ci				set->nr_hw_queues);
161562306a36Sopenharmony_ci			WARN_ON_ONCE(true);
161662306a36Sopenharmony_ci			submit_queues = 1;
161762306a36Sopenharmony_ci			poll_queues = 0;
161862306a36Sopenharmony_ci		}
161962306a36Sopenharmony_ci	}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	for (i = 0, qoff = 0; i < set->nr_maps; i++) {
162262306a36Sopenharmony_ci		struct blk_mq_queue_map *map = &set->map[i];
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci		switch (i) {
162562306a36Sopenharmony_ci		case HCTX_TYPE_DEFAULT:
162662306a36Sopenharmony_ci			map->nr_queues = submit_queues;
162762306a36Sopenharmony_ci			break;
162862306a36Sopenharmony_ci		case HCTX_TYPE_READ:
162962306a36Sopenharmony_ci			map->nr_queues = 0;
163062306a36Sopenharmony_ci			continue;
163162306a36Sopenharmony_ci		case HCTX_TYPE_POLL:
163262306a36Sopenharmony_ci			map->nr_queues = poll_queues;
163362306a36Sopenharmony_ci			break;
163462306a36Sopenharmony_ci		}
163562306a36Sopenharmony_ci		map->queue_offset = qoff;
163662306a36Sopenharmony_ci		qoff += map->nr_queues;
163762306a36Sopenharmony_ci		blk_mq_map_queues(map);
163862306a36Sopenharmony_ci	}
163962306a36Sopenharmony_ci}
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_cistatic int null_poll(struct blk_mq_hw_ctx *hctx, struct io_comp_batch *iob)
164262306a36Sopenharmony_ci{
164362306a36Sopenharmony_ci	struct nullb_queue *nq = hctx->driver_data;
164462306a36Sopenharmony_ci	LIST_HEAD(list);
164562306a36Sopenharmony_ci	int nr = 0;
164662306a36Sopenharmony_ci	struct request *rq;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	spin_lock(&nq->poll_lock);
164962306a36Sopenharmony_ci	list_splice_init(&nq->poll_list, &list);
165062306a36Sopenharmony_ci	list_for_each_entry(rq, &list, queuelist)
165162306a36Sopenharmony_ci		blk_mq_set_request_complete(rq);
165262306a36Sopenharmony_ci	spin_unlock(&nq->poll_lock);
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	while (!list_empty(&list)) {
165562306a36Sopenharmony_ci		struct nullb_cmd *cmd;
165662306a36Sopenharmony_ci		struct request *req;
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci		req = list_first_entry(&list, struct request, queuelist);
165962306a36Sopenharmony_ci		list_del_init(&req->queuelist);
166062306a36Sopenharmony_ci		cmd = blk_mq_rq_to_pdu(req);
166162306a36Sopenharmony_ci		cmd->error = null_process_cmd(cmd, req_op(req), blk_rq_pos(req),
166262306a36Sopenharmony_ci						blk_rq_sectors(req));
166362306a36Sopenharmony_ci		if (!blk_mq_add_to_batch(req, iob, (__force int) cmd->error,
166462306a36Sopenharmony_ci					blk_mq_end_request_batch))
166562306a36Sopenharmony_ci			end_cmd(cmd);
166662306a36Sopenharmony_ci		nr++;
166762306a36Sopenharmony_ci	}
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	return nr;
167062306a36Sopenharmony_ci}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_cistatic enum blk_eh_timer_return null_timeout_rq(struct request *rq)
167362306a36Sopenharmony_ci{
167462306a36Sopenharmony_ci	struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
167562306a36Sopenharmony_ci	struct nullb_cmd *cmd = blk_mq_rq_to_pdu(rq);
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	if (hctx->type == HCTX_TYPE_POLL) {
167862306a36Sopenharmony_ci		struct nullb_queue *nq = hctx->driver_data;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci		spin_lock(&nq->poll_lock);
168162306a36Sopenharmony_ci		/* The request may have completed meanwhile. */
168262306a36Sopenharmony_ci		if (blk_mq_request_completed(rq)) {
168362306a36Sopenharmony_ci			spin_unlock(&nq->poll_lock);
168462306a36Sopenharmony_ci			return BLK_EH_DONE;
168562306a36Sopenharmony_ci		}
168662306a36Sopenharmony_ci		list_del_init(&rq->queuelist);
168762306a36Sopenharmony_ci		spin_unlock(&nq->poll_lock);
168862306a36Sopenharmony_ci	}
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	pr_info("rq %p timed out\n", rq);
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	/*
169362306a36Sopenharmony_ci	 * If the device is marked as blocking (i.e. memory backed or zoned
169462306a36Sopenharmony_ci	 * device), the submission path may be blocked waiting for resources
169562306a36Sopenharmony_ci	 * and cause real timeouts. For these real timeouts, the submission
169662306a36Sopenharmony_ci	 * path will complete the request using blk_mq_complete_request().
169762306a36Sopenharmony_ci	 * Only fake timeouts need to execute blk_mq_complete_request() here.
169862306a36Sopenharmony_ci	 */
169962306a36Sopenharmony_ci	cmd->error = BLK_STS_TIMEOUT;
170062306a36Sopenharmony_ci	if (cmd->fake_timeout || hctx->type == HCTX_TYPE_POLL)
170162306a36Sopenharmony_ci		blk_mq_complete_request(rq);
170262306a36Sopenharmony_ci	return BLK_EH_DONE;
170362306a36Sopenharmony_ci}
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_cistatic blk_status_t null_queue_rq(struct blk_mq_hw_ctx *hctx,
170662306a36Sopenharmony_ci				  const struct blk_mq_queue_data *bd)
170762306a36Sopenharmony_ci{
170862306a36Sopenharmony_ci	struct request *rq = bd->rq;
170962306a36Sopenharmony_ci	struct nullb_cmd *cmd = blk_mq_rq_to_pdu(rq);
171062306a36Sopenharmony_ci	struct nullb_queue *nq = hctx->driver_data;
171162306a36Sopenharmony_ci	sector_t nr_sectors = blk_rq_sectors(rq);
171262306a36Sopenharmony_ci	sector_t sector = blk_rq_pos(rq);
171362306a36Sopenharmony_ci	const bool is_poll = hctx->type == HCTX_TYPE_POLL;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	might_sleep_if(hctx->flags & BLK_MQ_F_BLOCKING);
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	if (!is_poll && nq->dev->irqmode == NULL_IRQ_TIMER) {
171862306a36Sopenharmony_ci		hrtimer_init(&cmd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
171962306a36Sopenharmony_ci		cmd->timer.function = null_cmd_timer_expired;
172062306a36Sopenharmony_ci	}
172162306a36Sopenharmony_ci	cmd->rq = rq;
172262306a36Sopenharmony_ci	cmd->error = BLK_STS_OK;
172362306a36Sopenharmony_ci	cmd->nq = nq;
172462306a36Sopenharmony_ci	cmd->fake_timeout = should_timeout_request(rq) ||
172562306a36Sopenharmony_ci		blk_should_fake_timeout(rq->q);
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	blk_mq_start_request(rq);
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	if (should_requeue_request(rq)) {
173062306a36Sopenharmony_ci		/*
173162306a36Sopenharmony_ci		 * Alternate between hitting the core BUSY path, and the
173262306a36Sopenharmony_ci		 * driver driven requeue path
173362306a36Sopenharmony_ci		 */
173462306a36Sopenharmony_ci		nq->requeue_selection++;
173562306a36Sopenharmony_ci		if (nq->requeue_selection & 1)
173662306a36Sopenharmony_ci			return BLK_STS_RESOURCE;
173762306a36Sopenharmony_ci		blk_mq_requeue_request(rq, true);
173862306a36Sopenharmony_ci		return BLK_STS_OK;
173962306a36Sopenharmony_ci	}
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	if (is_poll) {
174262306a36Sopenharmony_ci		spin_lock(&nq->poll_lock);
174362306a36Sopenharmony_ci		list_add_tail(&rq->queuelist, &nq->poll_list);
174462306a36Sopenharmony_ci		spin_unlock(&nq->poll_lock);
174562306a36Sopenharmony_ci		return BLK_STS_OK;
174662306a36Sopenharmony_ci	}
174762306a36Sopenharmony_ci	if (cmd->fake_timeout)
174862306a36Sopenharmony_ci		return BLK_STS_OK;
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	return null_handle_cmd(cmd, sector, nr_sectors, req_op(rq));
175162306a36Sopenharmony_ci}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_cistatic void cleanup_queue(struct nullb_queue *nq)
175462306a36Sopenharmony_ci{
175562306a36Sopenharmony_ci	bitmap_free(nq->tag_map);
175662306a36Sopenharmony_ci	kfree(nq->cmds);
175762306a36Sopenharmony_ci}
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_cistatic void cleanup_queues(struct nullb *nullb)
176062306a36Sopenharmony_ci{
176162306a36Sopenharmony_ci	int i;
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	for (i = 0; i < nullb->nr_queues; i++)
176462306a36Sopenharmony_ci		cleanup_queue(&nullb->queues[i]);
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	kfree(nullb->queues);
176762306a36Sopenharmony_ci}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_cistatic void null_exit_hctx(struct blk_mq_hw_ctx *hctx, unsigned int hctx_idx)
177062306a36Sopenharmony_ci{
177162306a36Sopenharmony_ci	struct nullb_queue *nq = hctx->driver_data;
177262306a36Sopenharmony_ci	struct nullb *nullb = nq->dev->nullb;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	nullb->nr_queues--;
177562306a36Sopenharmony_ci}
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_cistatic void null_init_queue(struct nullb *nullb, struct nullb_queue *nq)
177862306a36Sopenharmony_ci{
177962306a36Sopenharmony_ci	init_waitqueue_head(&nq->wait);
178062306a36Sopenharmony_ci	nq->queue_depth = nullb->queue_depth;
178162306a36Sopenharmony_ci	nq->dev = nullb->dev;
178262306a36Sopenharmony_ci	INIT_LIST_HEAD(&nq->poll_list);
178362306a36Sopenharmony_ci	spin_lock_init(&nq->poll_lock);
178462306a36Sopenharmony_ci}
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_cistatic int null_init_hctx(struct blk_mq_hw_ctx *hctx, void *driver_data,
178762306a36Sopenharmony_ci			  unsigned int hctx_idx)
178862306a36Sopenharmony_ci{
178962306a36Sopenharmony_ci	struct nullb *nullb = hctx->queue->queuedata;
179062306a36Sopenharmony_ci	struct nullb_queue *nq;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	if (should_init_hctx_fail(nullb->dev))
179362306a36Sopenharmony_ci		return -EFAULT;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	nq = &nullb->queues[hctx_idx];
179662306a36Sopenharmony_ci	hctx->driver_data = nq;
179762306a36Sopenharmony_ci	null_init_queue(nullb, nq);
179862306a36Sopenharmony_ci	nullb->nr_queues++;
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	return 0;
180162306a36Sopenharmony_ci}
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_cistatic const struct blk_mq_ops null_mq_ops = {
180462306a36Sopenharmony_ci	.queue_rq       = null_queue_rq,
180562306a36Sopenharmony_ci	.complete	= null_complete_rq,
180662306a36Sopenharmony_ci	.timeout	= null_timeout_rq,
180762306a36Sopenharmony_ci	.poll		= null_poll,
180862306a36Sopenharmony_ci	.map_queues	= null_map_queues,
180962306a36Sopenharmony_ci	.init_hctx	= null_init_hctx,
181062306a36Sopenharmony_ci	.exit_hctx	= null_exit_hctx,
181162306a36Sopenharmony_ci};
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_cistatic void null_del_dev(struct nullb *nullb)
181462306a36Sopenharmony_ci{
181562306a36Sopenharmony_ci	struct nullb_device *dev;
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	if (!nullb)
181862306a36Sopenharmony_ci		return;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	dev = nullb->dev;
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	ida_simple_remove(&nullb_indexes, nullb->index);
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	list_del_init(&nullb->list);
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	del_gendisk(nullb->disk);
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	if (test_bit(NULLB_DEV_FL_THROTTLED, &nullb->dev->flags)) {
182962306a36Sopenharmony_ci		hrtimer_cancel(&nullb->bw_timer);
183062306a36Sopenharmony_ci		atomic_long_set(&nullb->cur_bytes, LONG_MAX);
183162306a36Sopenharmony_ci		null_restart_queue_async(nullb);
183262306a36Sopenharmony_ci	}
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	put_disk(nullb->disk);
183562306a36Sopenharmony_ci	if (dev->queue_mode == NULL_Q_MQ &&
183662306a36Sopenharmony_ci	    nullb->tag_set == &nullb->__tag_set)
183762306a36Sopenharmony_ci		blk_mq_free_tag_set(nullb->tag_set);
183862306a36Sopenharmony_ci	cleanup_queues(nullb);
183962306a36Sopenharmony_ci	if (null_cache_active(nullb))
184062306a36Sopenharmony_ci		null_free_device_storage(nullb->dev, true);
184162306a36Sopenharmony_ci	kfree(nullb);
184262306a36Sopenharmony_ci	dev->nullb = NULL;
184362306a36Sopenharmony_ci}
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_cistatic void null_config_discard(struct nullb *nullb)
184662306a36Sopenharmony_ci{
184762306a36Sopenharmony_ci	if (nullb->dev->discard == false)
184862306a36Sopenharmony_ci		return;
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	if (!nullb->dev->memory_backed) {
185162306a36Sopenharmony_ci		nullb->dev->discard = false;
185262306a36Sopenharmony_ci		pr_info("discard option is ignored without memory backing\n");
185362306a36Sopenharmony_ci		return;
185462306a36Sopenharmony_ci	}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	if (nullb->dev->zoned) {
185762306a36Sopenharmony_ci		nullb->dev->discard = false;
185862306a36Sopenharmony_ci		pr_info("discard option is ignored in zoned mode\n");
185962306a36Sopenharmony_ci		return;
186062306a36Sopenharmony_ci	}
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	nullb->q->limits.discard_granularity = nullb->dev->blocksize;
186362306a36Sopenharmony_ci	blk_queue_max_discard_sectors(nullb->q, UINT_MAX >> 9);
186462306a36Sopenharmony_ci}
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_cistatic const struct block_device_operations null_bio_ops = {
186762306a36Sopenharmony_ci	.owner		= THIS_MODULE,
186862306a36Sopenharmony_ci	.submit_bio	= null_submit_bio,
186962306a36Sopenharmony_ci	.report_zones	= null_report_zones,
187062306a36Sopenharmony_ci};
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_cistatic const struct block_device_operations null_rq_ops = {
187362306a36Sopenharmony_ci	.owner		= THIS_MODULE,
187462306a36Sopenharmony_ci	.report_zones	= null_report_zones,
187562306a36Sopenharmony_ci};
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_cistatic int setup_commands(struct nullb_queue *nq)
187862306a36Sopenharmony_ci{
187962306a36Sopenharmony_ci	struct nullb_cmd *cmd;
188062306a36Sopenharmony_ci	int i;
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	nq->cmds = kcalloc(nq->queue_depth, sizeof(*cmd), GFP_KERNEL);
188362306a36Sopenharmony_ci	if (!nq->cmds)
188462306a36Sopenharmony_ci		return -ENOMEM;
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	nq->tag_map = bitmap_zalloc(nq->queue_depth, GFP_KERNEL);
188762306a36Sopenharmony_ci	if (!nq->tag_map) {
188862306a36Sopenharmony_ci		kfree(nq->cmds);
188962306a36Sopenharmony_ci		return -ENOMEM;
189062306a36Sopenharmony_ci	}
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	for (i = 0; i < nq->queue_depth; i++) {
189362306a36Sopenharmony_ci		cmd = &nq->cmds[i];
189462306a36Sopenharmony_ci		cmd->tag = -1U;
189562306a36Sopenharmony_ci	}
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	return 0;
189862306a36Sopenharmony_ci}
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_cistatic int setup_queues(struct nullb *nullb)
190162306a36Sopenharmony_ci{
190262306a36Sopenharmony_ci	int nqueues = nr_cpu_ids;
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	if (g_poll_queues)
190562306a36Sopenharmony_ci		nqueues += g_poll_queues;
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	nullb->queues = kcalloc(nqueues, sizeof(struct nullb_queue),
190862306a36Sopenharmony_ci				GFP_KERNEL);
190962306a36Sopenharmony_ci	if (!nullb->queues)
191062306a36Sopenharmony_ci		return -ENOMEM;
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	nullb->queue_depth = nullb->dev->hw_queue_depth;
191362306a36Sopenharmony_ci	return 0;
191462306a36Sopenharmony_ci}
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_cistatic int init_driver_queues(struct nullb *nullb)
191762306a36Sopenharmony_ci{
191862306a36Sopenharmony_ci	struct nullb_queue *nq;
191962306a36Sopenharmony_ci	int i, ret = 0;
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	for (i = 0; i < nullb->dev->submit_queues; i++) {
192262306a36Sopenharmony_ci		nq = &nullb->queues[i];
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci		null_init_queue(nullb, nq);
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci		ret = setup_commands(nq);
192762306a36Sopenharmony_ci		if (ret)
192862306a36Sopenharmony_ci			return ret;
192962306a36Sopenharmony_ci		nullb->nr_queues++;
193062306a36Sopenharmony_ci	}
193162306a36Sopenharmony_ci	return 0;
193262306a36Sopenharmony_ci}
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_cistatic int null_gendisk_register(struct nullb *nullb)
193562306a36Sopenharmony_ci{
193662306a36Sopenharmony_ci	sector_t size = ((sector_t)nullb->dev->size * SZ_1M) >> SECTOR_SHIFT;
193762306a36Sopenharmony_ci	struct gendisk *disk = nullb->disk;
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	set_capacity(disk, size);
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	disk->major		= null_major;
194262306a36Sopenharmony_ci	disk->first_minor	= nullb->index;
194362306a36Sopenharmony_ci	disk->minors		= 1;
194462306a36Sopenharmony_ci	if (queue_is_mq(nullb->q))
194562306a36Sopenharmony_ci		disk->fops		= &null_rq_ops;
194662306a36Sopenharmony_ci	else
194762306a36Sopenharmony_ci		disk->fops		= &null_bio_ops;
194862306a36Sopenharmony_ci	disk->private_data	= nullb;
194962306a36Sopenharmony_ci	strncpy(disk->disk_name, nullb->disk_name, DISK_NAME_LEN);
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	if (nullb->dev->zoned) {
195262306a36Sopenharmony_ci		int ret = null_register_zoned_dev(nullb);
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci		if (ret)
195562306a36Sopenharmony_ci			return ret;
195662306a36Sopenharmony_ci	}
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	return add_disk(disk);
195962306a36Sopenharmony_ci}
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_cistatic int null_init_tag_set(struct nullb *nullb, struct blk_mq_tag_set *set)
196262306a36Sopenharmony_ci{
196362306a36Sopenharmony_ci	unsigned int flags = BLK_MQ_F_SHOULD_MERGE;
196462306a36Sopenharmony_ci	int hw_queues, numa_node;
196562306a36Sopenharmony_ci	unsigned int queue_depth;
196662306a36Sopenharmony_ci	int poll_queues;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	if (nullb) {
196962306a36Sopenharmony_ci		hw_queues = nullb->dev->submit_queues;
197062306a36Sopenharmony_ci		poll_queues = nullb->dev->poll_queues;
197162306a36Sopenharmony_ci		queue_depth = nullb->dev->hw_queue_depth;
197262306a36Sopenharmony_ci		numa_node = nullb->dev->home_node;
197362306a36Sopenharmony_ci		if (nullb->dev->no_sched)
197462306a36Sopenharmony_ci			flags |= BLK_MQ_F_NO_SCHED;
197562306a36Sopenharmony_ci		if (nullb->dev->shared_tag_bitmap)
197662306a36Sopenharmony_ci			flags |= BLK_MQ_F_TAG_HCTX_SHARED;
197762306a36Sopenharmony_ci		if (nullb->dev->blocking)
197862306a36Sopenharmony_ci			flags |= BLK_MQ_F_BLOCKING;
197962306a36Sopenharmony_ci	} else {
198062306a36Sopenharmony_ci		hw_queues = g_submit_queues;
198162306a36Sopenharmony_ci		poll_queues = g_poll_queues;
198262306a36Sopenharmony_ci		queue_depth = g_hw_queue_depth;
198362306a36Sopenharmony_ci		numa_node = g_home_node;
198462306a36Sopenharmony_ci		if (g_no_sched)
198562306a36Sopenharmony_ci			flags |= BLK_MQ_F_NO_SCHED;
198662306a36Sopenharmony_ci		if (g_shared_tag_bitmap)
198762306a36Sopenharmony_ci			flags |= BLK_MQ_F_TAG_HCTX_SHARED;
198862306a36Sopenharmony_ci		if (g_blocking)
198962306a36Sopenharmony_ci			flags |= BLK_MQ_F_BLOCKING;
199062306a36Sopenharmony_ci	}
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	set->ops = &null_mq_ops;
199362306a36Sopenharmony_ci	set->cmd_size	= sizeof(struct nullb_cmd);
199462306a36Sopenharmony_ci	set->flags = flags;
199562306a36Sopenharmony_ci	set->driver_data = nullb;
199662306a36Sopenharmony_ci	set->nr_hw_queues = hw_queues;
199762306a36Sopenharmony_ci	set->queue_depth = queue_depth;
199862306a36Sopenharmony_ci	set->numa_node = numa_node;
199962306a36Sopenharmony_ci	if (poll_queues) {
200062306a36Sopenharmony_ci		set->nr_hw_queues += poll_queues;
200162306a36Sopenharmony_ci		set->nr_maps = 3;
200262306a36Sopenharmony_ci	} else {
200362306a36Sopenharmony_ci		set->nr_maps = 1;
200462306a36Sopenharmony_ci	}
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	return blk_mq_alloc_tag_set(set);
200762306a36Sopenharmony_ci}
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_cistatic int null_validate_conf(struct nullb_device *dev)
201062306a36Sopenharmony_ci{
201162306a36Sopenharmony_ci	if (dev->queue_mode == NULL_Q_RQ) {
201262306a36Sopenharmony_ci		pr_err("legacy IO path is no longer available\n");
201362306a36Sopenharmony_ci		return -EINVAL;
201462306a36Sopenharmony_ci	}
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	dev->blocksize = round_down(dev->blocksize, 512);
201762306a36Sopenharmony_ci	dev->blocksize = clamp_t(unsigned int, dev->blocksize, 512, 4096);
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	if (dev->queue_mode == NULL_Q_MQ && dev->use_per_node_hctx) {
202062306a36Sopenharmony_ci		if (dev->submit_queues != nr_online_nodes)
202162306a36Sopenharmony_ci			dev->submit_queues = nr_online_nodes;
202262306a36Sopenharmony_ci	} else if (dev->submit_queues > nr_cpu_ids)
202362306a36Sopenharmony_ci		dev->submit_queues = nr_cpu_ids;
202462306a36Sopenharmony_ci	else if (dev->submit_queues == 0)
202562306a36Sopenharmony_ci		dev->submit_queues = 1;
202662306a36Sopenharmony_ci	dev->prev_submit_queues = dev->submit_queues;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	if (dev->poll_queues > g_poll_queues)
202962306a36Sopenharmony_ci		dev->poll_queues = g_poll_queues;
203062306a36Sopenharmony_ci	dev->prev_poll_queues = dev->poll_queues;
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	dev->queue_mode = min_t(unsigned int, dev->queue_mode, NULL_Q_MQ);
203362306a36Sopenharmony_ci	dev->irqmode = min_t(unsigned int, dev->irqmode, NULL_IRQ_TIMER);
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	/* Do memory allocation, so set blocking */
203662306a36Sopenharmony_ci	if (dev->memory_backed)
203762306a36Sopenharmony_ci		dev->blocking = true;
203862306a36Sopenharmony_ci	else /* cache is meaningless */
203962306a36Sopenharmony_ci		dev->cache_size = 0;
204062306a36Sopenharmony_ci	dev->cache_size = min_t(unsigned long, ULONG_MAX / 1024 / 1024,
204162306a36Sopenharmony_ci						dev->cache_size);
204262306a36Sopenharmony_ci	dev->mbps = min_t(unsigned int, 1024 * 40, dev->mbps);
204362306a36Sopenharmony_ci	/* can not stop a queue */
204462306a36Sopenharmony_ci	if (dev->queue_mode == NULL_Q_BIO)
204562306a36Sopenharmony_ci		dev->mbps = 0;
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	if (dev->zoned &&
204862306a36Sopenharmony_ci	    (!dev->zone_size || !is_power_of_2(dev->zone_size))) {
204962306a36Sopenharmony_ci		pr_err("zone_size must be power-of-two\n");
205062306a36Sopenharmony_ci		return -EINVAL;
205162306a36Sopenharmony_ci	}
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	return 0;
205462306a36Sopenharmony_ci}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION
205762306a36Sopenharmony_cistatic bool __null_setup_fault(struct fault_attr *attr, char *str)
205862306a36Sopenharmony_ci{
205962306a36Sopenharmony_ci	if (!str[0])
206062306a36Sopenharmony_ci		return true;
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci	if (!setup_fault_attr(attr, str))
206362306a36Sopenharmony_ci		return false;
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	attr->verbose = 0;
206662306a36Sopenharmony_ci	return true;
206762306a36Sopenharmony_ci}
206862306a36Sopenharmony_ci#endif
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_cistatic bool null_setup_fault(void)
207162306a36Sopenharmony_ci{
207262306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION
207362306a36Sopenharmony_ci	if (!__null_setup_fault(&null_timeout_attr, g_timeout_str))
207462306a36Sopenharmony_ci		return false;
207562306a36Sopenharmony_ci	if (!__null_setup_fault(&null_requeue_attr, g_requeue_str))
207662306a36Sopenharmony_ci		return false;
207762306a36Sopenharmony_ci	if (!__null_setup_fault(&null_init_hctx_attr, g_init_hctx_str))
207862306a36Sopenharmony_ci		return false;
207962306a36Sopenharmony_ci#endif
208062306a36Sopenharmony_ci	return true;
208162306a36Sopenharmony_ci}
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_cistatic int null_add_dev(struct nullb_device *dev)
208462306a36Sopenharmony_ci{
208562306a36Sopenharmony_ci	struct nullb *nullb;
208662306a36Sopenharmony_ci	int rv;
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci	rv = null_validate_conf(dev);
208962306a36Sopenharmony_ci	if (rv)
209062306a36Sopenharmony_ci		return rv;
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	nullb = kzalloc_node(sizeof(*nullb), GFP_KERNEL, dev->home_node);
209362306a36Sopenharmony_ci	if (!nullb) {
209462306a36Sopenharmony_ci		rv = -ENOMEM;
209562306a36Sopenharmony_ci		goto out;
209662306a36Sopenharmony_ci	}
209762306a36Sopenharmony_ci	nullb->dev = dev;
209862306a36Sopenharmony_ci	dev->nullb = nullb;
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	spin_lock_init(&nullb->lock);
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	rv = setup_queues(nullb);
210362306a36Sopenharmony_ci	if (rv)
210462306a36Sopenharmony_ci		goto out_free_nullb;
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	if (dev->queue_mode == NULL_Q_MQ) {
210762306a36Sopenharmony_ci		if (shared_tags) {
210862306a36Sopenharmony_ci			nullb->tag_set = &tag_set;
210962306a36Sopenharmony_ci			rv = 0;
211062306a36Sopenharmony_ci		} else {
211162306a36Sopenharmony_ci			nullb->tag_set = &nullb->__tag_set;
211262306a36Sopenharmony_ci			rv = null_init_tag_set(nullb, nullb->tag_set);
211362306a36Sopenharmony_ci		}
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci		if (rv)
211662306a36Sopenharmony_ci			goto out_cleanup_queues;
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci		nullb->tag_set->timeout = 5 * HZ;
211962306a36Sopenharmony_ci		nullb->disk = blk_mq_alloc_disk(nullb->tag_set, nullb);
212062306a36Sopenharmony_ci		if (IS_ERR(nullb->disk)) {
212162306a36Sopenharmony_ci			rv = PTR_ERR(nullb->disk);
212262306a36Sopenharmony_ci			goto out_cleanup_tags;
212362306a36Sopenharmony_ci		}
212462306a36Sopenharmony_ci		nullb->q = nullb->disk->queue;
212562306a36Sopenharmony_ci	} else if (dev->queue_mode == NULL_Q_BIO) {
212662306a36Sopenharmony_ci		rv = -ENOMEM;
212762306a36Sopenharmony_ci		nullb->disk = blk_alloc_disk(nullb->dev->home_node);
212862306a36Sopenharmony_ci		if (!nullb->disk)
212962306a36Sopenharmony_ci			goto out_cleanup_queues;
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci		nullb->q = nullb->disk->queue;
213262306a36Sopenharmony_ci		rv = init_driver_queues(nullb);
213362306a36Sopenharmony_ci		if (rv)
213462306a36Sopenharmony_ci			goto out_cleanup_disk;
213562306a36Sopenharmony_ci	}
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	if (dev->mbps) {
213862306a36Sopenharmony_ci		set_bit(NULLB_DEV_FL_THROTTLED, &dev->flags);
213962306a36Sopenharmony_ci		nullb_setup_bwtimer(nullb);
214062306a36Sopenharmony_ci	}
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci	if (dev->cache_size > 0) {
214362306a36Sopenharmony_ci		set_bit(NULLB_DEV_FL_CACHE, &nullb->dev->flags);
214462306a36Sopenharmony_ci		blk_queue_write_cache(nullb->q, true, true);
214562306a36Sopenharmony_ci	}
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	if (dev->zoned) {
214862306a36Sopenharmony_ci		rv = null_init_zoned_dev(dev, nullb->q);
214962306a36Sopenharmony_ci		if (rv)
215062306a36Sopenharmony_ci			goto out_cleanup_disk;
215162306a36Sopenharmony_ci	}
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	nullb->q->queuedata = nullb;
215462306a36Sopenharmony_ci	blk_queue_flag_set(QUEUE_FLAG_NONROT, nullb->q);
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	mutex_lock(&lock);
215762306a36Sopenharmony_ci	rv = ida_simple_get(&nullb_indexes, 0, 0, GFP_KERNEL);
215862306a36Sopenharmony_ci	if (rv < 0) {
215962306a36Sopenharmony_ci		mutex_unlock(&lock);
216062306a36Sopenharmony_ci		goto out_cleanup_zone;
216162306a36Sopenharmony_ci	}
216262306a36Sopenharmony_ci	nullb->index = rv;
216362306a36Sopenharmony_ci	dev->index = rv;
216462306a36Sopenharmony_ci	mutex_unlock(&lock);
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	blk_queue_logical_block_size(nullb->q, dev->blocksize);
216762306a36Sopenharmony_ci	blk_queue_physical_block_size(nullb->q, dev->blocksize);
216862306a36Sopenharmony_ci	if (dev->max_sectors)
216962306a36Sopenharmony_ci		blk_queue_max_hw_sectors(nullb->q, dev->max_sectors);
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	if (dev->virt_boundary)
217262306a36Sopenharmony_ci		blk_queue_virt_boundary(nullb->q, PAGE_SIZE - 1);
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci	null_config_discard(nullb);
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	if (config_item_name(&dev->group.cg_item)) {
217762306a36Sopenharmony_ci		/* Use configfs dir name as the device name */
217862306a36Sopenharmony_ci		snprintf(nullb->disk_name, sizeof(nullb->disk_name),
217962306a36Sopenharmony_ci			 "%s", config_item_name(&dev->group.cg_item));
218062306a36Sopenharmony_ci	} else {
218162306a36Sopenharmony_ci		sprintf(nullb->disk_name, "nullb%d", nullb->index);
218262306a36Sopenharmony_ci	}
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci	rv = null_gendisk_register(nullb);
218562306a36Sopenharmony_ci	if (rv)
218662306a36Sopenharmony_ci		goto out_ida_free;
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	mutex_lock(&lock);
218962306a36Sopenharmony_ci	list_add_tail(&nullb->list, &nullb_list);
219062306a36Sopenharmony_ci	mutex_unlock(&lock);
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	pr_info("disk %s created\n", nullb->disk_name);
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	return 0;
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ciout_ida_free:
219762306a36Sopenharmony_ci	ida_free(&nullb_indexes, nullb->index);
219862306a36Sopenharmony_ciout_cleanup_zone:
219962306a36Sopenharmony_ci	null_free_zoned_dev(dev);
220062306a36Sopenharmony_ciout_cleanup_disk:
220162306a36Sopenharmony_ci	put_disk(nullb->disk);
220262306a36Sopenharmony_ciout_cleanup_tags:
220362306a36Sopenharmony_ci	if (dev->queue_mode == NULL_Q_MQ && nullb->tag_set == &nullb->__tag_set)
220462306a36Sopenharmony_ci		blk_mq_free_tag_set(nullb->tag_set);
220562306a36Sopenharmony_ciout_cleanup_queues:
220662306a36Sopenharmony_ci	cleanup_queues(nullb);
220762306a36Sopenharmony_ciout_free_nullb:
220862306a36Sopenharmony_ci	kfree(nullb);
220962306a36Sopenharmony_ci	dev->nullb = NULL;
221062306a36Sopenharmony_ciout:
221162306a36Sopenharmony_ci	return rv;
221262306a36Sopenharmony_ci}
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_cistatic struct nullb *null_find_dev_by_name(const char *name)
221562306a36Sopenharmony_ci{
221662306a36Sopenharmony_ci	struct nullb *nullb = NULL, *nb;
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci	mutex_lock(&lock);
221962306a36Sopenharmony_ci	list_for_each_entry(nb, &nullb_list, list) {
222062306a36Sopenharmony_ci		if (strcmp(nb->disk_name, name) == 0) {
222162306a36Sopenharmony_ci			nullb = nb;
222262306a36Sopenharmony_ci			break;
222362306a36Sopenharmony_ci		}
222462306a36Sopenharmony_ci	}
222562306a36Sopenharmony_ci	mutex_unlock(&lock);
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	return nullb;
222862306a36Sopenharmony_ci}
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_cistatic int null_create_dev(void)
223162306a36Sopenharmony_ci{
223262306a36Sopenharmony_ci	struct nullb_device *dev;
223362306a36Sopenharmony_ci	int ret;
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci	dev = null_alloc_dev();
223662306a36Sopenharmony_ci	if (!dev)
223762306a36Sopenharmony_ci		return -ENOMEM;
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci	ret = null_add_dev(dev);
224062306a36Sopenharmony_ci	if (ret) {
224162306a36Sopenharmony_ci		null_free_dev(dev);
224262306a36Sopenharmony_ci		return ret;
224362306a36Sopenharmony_ci	}
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	return 0;
224662306a36Sopenharmony_ci}
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_cistatic void null_destroy_dev(struct nullb *nullb)
224962306a36Sopenharmony_ci{
225062306a36Sopenharmony_ci	struct nullb_device *dev = nullb->dev;
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	null_del_dev(nullb);
225362306a36Sopenharmony_ci	null_free_device_storage(dev, false);
225462306a36Sopenharmony_ci	null_free_dev(dev);
225562306a36Sopenharmony_ci}
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_cistatic int __init null_init(void)
225862306a36Sopenharmony_ci{
225962306a36Sopenharmony_ci	int ret = 0;
226062306a36Sopenharmony_ci	unsigned int i;
226162306a36Sopenharmony_ci	struct nullb *nullb;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci	if (g_bs > PAGE_SIZE) {
226462306a36Sopenharmony_ci		pr_warn("invalid block size\n");
226562306a36Sopenharmony_ci		pr_warn("defaults block size to %lu\n", PAGE_SIZE);
226662306a36Sopenharmony_ci		g_bs = PAGE_SIZE;
226762306a36Sopenharmony_ci	}
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci	if (g_home_node != NUMA_NO_NODE && g_home_node >= nr_online_nodes) {
227062306a36Sopenharmony_ci		pr_err("invalid home_node value\n");
227162306a36Sopenharmony_ci		g_home_node = NUMA_NO_NODE;
227262306a36Sopenharmony_ci	}
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	if (!null_setup_fault())
227562306a36Sopenharmony_ci		return -EINVAL;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	if (g_queue_mode == NULL_Q_RQ) {
227862306a36Sopenharmony_ci		pr_err("legacy IO path is no longer available\n");
227962306a36Sopenharmony_ci		return -EINVAL;
228062306a36Sopenharmony_ci	}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	if (g_queue_mode == NULL_Q_MQ && g_use_per_node_hctx) {
228362306a36Sopenharmony_ci		if (g_submit_queues != nr_online_nodes) {
228462306a36Sopenharmony_ci			pr_warn("submit_queues param is set to %u.\n",
228562306a36Sopenharmony_ci				nr_online_nodes);
228662306a36Sopenharmony_ci			g_submit_queues = nr_online_nodes;
228762306a36Sopenharmony_ci		}
228862306a36Sopenharmony_ci	} else if (g_submit_queues > nr_cpu_ids) {
228962306a36Sopenharmony_ci		g_submit_queues = nr_cpu_ids;
229062306a36Sopenharmony_ci	} else if (g_submit_queues <= 0) {
229162306a36Sopenharmony_ci		g_submit_queues = 1;
229262306a36Sopenharmony_ci	}
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	if (g_queue_mode == NULL_Q_MQ && shared_tags) {
229562306a36Sopenharmony_ci		ret = null_init_tag_set(NULL, &tag_set);
229662306a36Sopenharmony_ci		if (ret)
229762306a36Sopenharmony_ci			return ret;
229862306a36Sopenharmony_ci	}
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci	config_group_init(&nullb_subsys.su_group);
230162306a36Sopenharmony_ci	mutex_init(&nullb_subsys.su_mutex);
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	ret = configfs_register_subsystem(&nullb_subsys);
230462306a36Sopenharmony_ci	if (ret)
230562306a36Sopenharmony_ci		goto err_tagset;
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci	mutex_init(&lock);
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	null_major = register_blkdev(0, "nullb");
231062306a36Sopenharmony_ci	if (null_major < 0) {
231162306a36Sopenharmony_ci		ret = null_major;
231262306a36Sopenharmony_ci		goto err_conf;
231362306a36Sopenharmony_ci	}
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci	for (i = 0; i < nr_devices; i++) {
231662306a36Sopenharmony_ci		ret = null_create_dev();
231762306a36Sopenharmony_ci		if (ret)
231862306a36Sopenharmony_ci			goto err_dev;
231962306a36Sopenharmony_ci	}
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci	pr_info("module loaded\n");
232262306a36Sopenharmony_ci	return 0;
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_cierr_dev:
232562306a36Sopenharmony_ci	while (!list_empty(&nullb_list)) {
232662306a36Sopenharmony_ci		nullb = list_entry(nullb_list.next, struct nullb, list);
232762306a36Sopenharmony_ci		null_destroy_dev(nullb);
232862306a36Sopenharmony_ci	}
232962306a36Sopenharmony_ci	unregister_blkdev(null_major, "nullb");
233062306a36Sopenharmony_cierr_conf:
233162306a36Sopenharmony_ci	configfs_unregister_subsystem(&nullb_subsys);
233262306a36Sopenharmony_cierr_tagset:
233362306a36Sopenharmony_ci	if (g_queue_mode == NULL_Q_MQ && shared_tags)
233462306a36Sopenharmony_ci		blk_mq_free_tag_set(&tag_set);
233562306a36Sopenharmony_ci	return ret;
233662306a36Sopenharmony_ci}
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_cistatic void __exit null_exit(void)
233962306a36Sopenharmony_ci{
234062306a36Sopenharmony_ci	struct nullb *nullb;
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_ci	configfs_unregister_subsystem(&nullb_subsys);
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	unregister_blkdev(null_major, "nullb");
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	mutex_lock(&lock);
234762306a36Sopenharmony_ci	while (!list_empty(&nullb_list)) {
234862306a36Sopenharmony_ci		nullb = list_entry(nullb_list.next, struct nullb, list);
234962306a36Sopenharmony_ci		null_destroy_dev(nullb);
235062306a36Sopenharmony_ci	}
235162306a36Sopenharmony_ci	mutex_unlock(&lock);
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ci	if (g_queue_mode == NULL_Q_MQ && shared_tags)
235462306a36Sopenharmony_ci		blk_mq_free_tag_set(&tag_set);
235562306a36Sopenharmony_ci}
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_cimodule_init(null_init);
235862306a36Sopenharmony_cimodule_exit(null_exit);
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ciMODULE_AUTHOR("Jens Axboe <axboe@kernel.dk>");
236162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2362