18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (C) 2020 Red Hat GmbH
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is released under the GPL.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Device-mapper target to emulate smaller logical block
78c2ecf20Sopenharmony_ci * size on backing devices exposing (natively) larger ones.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * E.g. 512 byte sector emulation on 4K native disks.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "dm.h"
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
158c2ecf20Sopenharmony_ci#include <linux/dm-bufio.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define DM_MSG_PREFIX "ebs"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic void ebs_dtr(struct dm_target *ti);
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* Emulated block size context. */
228c2ecf20Sopenharmony_cistruct ebs_c {
238c2ecf20Sopenharmony_ci	struct dm_dev *dev;		/* Underlying device to emulate block size on. */
248c2ecf20Sopenharmony_ci	struct dm_bufio_client *bufio;	/* Use dm-bufio for read and read-modify-write processing. */
258c2ecf20Sopenharmony_ci	struct workqueue_struct *wq;	/* Workqueue for ^ processing of bios. */
268c2ecf20Sopenharmony_ci	struct work_struct ws;		/* Work item used for ^. */
278c2ecf20Sopenharmony_ci	struct bio_list bios_in;	/* Worker bios input list. */
288c2ecf20Sopenharmony_ci	spinlock_t lock;		/* Guard bios input list above. */
298c2ecf20Sopenharmony_ci	sector_t start;			/* <start> table line argument, see ebs_ctr below. */
308c2ecf20Sopenharmony_ci	unsigned int e_bs;		/* Emulated block size in sectors exposed to upper layer. */
318c2ecf20Sopenharmony_ci	unsigned int u_bs;		/* Underlying block size in sectors retrievd from/set on lower layer device. */
328c2ecf20Sopenharmony_ci	unsigned char block_shift;	/* bitshift sectors -> blocks used in dm-bufio API. */
338c2ecf20Sopenharmony_ci	bool u_bs_set:1;		/* Flag to indicate underlying block size is set on table line. */
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic inline sector_t __sector_to_block(struct ebs_c *ec, sector_t sector)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	return sector >> ec->block_shift;
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic inline sector_t __block_mod(sector_t sector, unsigned int bs)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	return sector & (bs - 1);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/* Return number of blocks for a bio, accounting for misalignement of start and end sectors. */
478c2ecf20Sopenharmony_cistatic inline unsigned int __nr_blocks(struct ebs_c *ec, struct bio *bio)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	sector_t end_sector = __block_mod(bio->bi_iter.bi_sector, ec->u_bs) + bio_sectors(bio);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	return __sector_to_block(ec, end_sector) + (__block_mod(end_sector, ec->u_bs) ? 1 : 0);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic inline bool __ebs_check_bs(unsigned int bs)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	return bs && is_power_of_2(bs);
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci/*
608c2ecf20Sopenharmony_ci * READ/WRITE:
618c2ecf20Sopenharmony_ci *
628c2ecf20Sopenharmony_ci * copy blocks between bufio blocks and bio vector's (partial/overlapping) pages.
638c2ecf20Sopenharmony_ci */
648c2ecf20Sopenharmony_cistatic int __ebs_rw_bvec(struct ebs_c *ec, int rw, struct bio_vec *bv, struct bvec_iter *iter)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	int r = 0;
678c2ecf20Sopenharmony_ci	unsigned char *ba, *pa;
688c2ecf20Sopenharmony_ci	unsigned int cur_len;
698c2ecf20Sopenharmony_ci	unsigned int bv_len = bv->bv_len;
708c2ecf20Sopenharmony_ci	unsigned int buf_off = to_bytes(__block_mod(iter->bi_sector, ec->u_bs));
718c2ecf20Sopenharmony_ci	sector_t block = __sector_to_block(ec, iter->bi_sector);
728c2ecf20Sopenharmony_ci	struct dm_buffer *b;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	if (unlikely(!bv->bv_page || !bv_len))
758c2ecf20Sopenharmony_ci		return -EIO;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	pa = page_address(bv->bv_page) + bv->bv_offset;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	/* Handle overlapping page <-> blocks */
808c2ecf20Sopenharmony_ci	while (bv_len) {
818c2ecf20Sopenharmony_ci		cur_len = min(dm_bufio_get_block_size(ec->bufio) - buf_off, bv_len);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci		/* Avoid reading for writes in case bio vector's page overwrites block completely. */
848c2ecf20Sopenharmony_ci		if (rw == READ || buf_off || bv_len < dm_bufio_get_block_size(ec->bufio))
858c2ecf20Sopenharmony_ci			ba = dm_bufio_read(ec->bufio, block, &b);
868c2ecf20Sopenharmony_ci		else
878c2ecf20Sopenharmony_ci			ba = dm_bufio_new(ec->bufio, block, &b);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci		if (unlikely(IS_ERR(ba))) {
908c2ecf20Sopenharmony_ci			/*
918c2ecf20Sopenharmony_ci			 * Carry on with next buffer, if any, to issue all possible
928c2ecf20Sopenharmony_ci			 * data but return error.
938c2ecf20Sopenharmony_ci			 */
948c2ecf20Sopenharmony_ci			r = PTR_ERR(ba);
958c2ecf20Sopenharmony_ci		} else {
968c2ecf20Sopenharmony_ci			/* Copy data to/from bio to buffer if read/new was successful above. */
978c2ecf20Sopenharmony_ci			ba += buf_off;
988c2ecf20Sopenharmony_ci			if (rw == READ) {
998c2ecf20Sopenharmony_ci				memcpy(pa, ba, cur_len);
1008c2ecf20Sopenharmony_ci				flush_dcache_page(bv->bv_page);
1018c2ecf20Sopenharmony_ci			} else {
1028c2ecf20Sopenharmony_ci				flush_dcache_page(bv->bv_page);
1038c2ecf20Sopenharmony_ci				memcpy(ba, pa, cur_len);
1048c2ecf20Sopenharmony_ci				dm_bufio_mark_partial_buffer_dirty(b, buf_off, buf_off + cur_len);
1058c2ecf20Sopenharmony_ci			}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci			dm_bufio_release(b);
1088c2ecf20Sopenharmony_ci		}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci		pa += cur_len;
1118c2ecf20Sopenharmony_ci		bv_len -= cur_len;
1128c2ecf20Sopenharmony_ci		buf_off = 0;
1138c2ecf20Sopenharmony_ci		block++;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	return r;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci/* READ/WRITE: iterate bio vector's copying between (partial) pages and bufio blocks. */
1208c2ecf20Sopenharmony_cistatic int __ebs_rw_bio(struct ebs_c *ec, int rw, struct bio *bio)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	int r = 0, rr;
1238c2ecf20Sopenharmony_ci	struct bio_vec bv;
1248c2ecf20Sopenharmony_ci	struct bvec_iter iter;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	bio_for_each_bvec(bv, bio, iter) {
1278c2ecf20Sopenharmony_ci		rr = __ebs_rw_bvec(ec, rw, &bv, &iter);
1288c2ecf20Sopenharmony_ci		if (rr)
1298c2ecf20Sopenharmony_ci			r = rr;
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	return r;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci/*
1368c2ecf20Sopenharmony_ci * Discard bio's blocks, i.e. pass discards down.
1378c2ecf20Sopenharmony_ci *
1388c2ecf20Sopenharmony_ci * Avoid discarding partial blocks at beginning and end;
1398c2ecf20Sopenharmony_ci * return 0 in case no blocks can be discarded as a result.
1408c2ecf20Sopenharmony_ci */
1418c2ecf20Sopenharmony_cistatic int __ebs_discard_bio(struct ebs_c *ec, struct bio *bio)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	sector_t block, blocks, sector = bio->bi_iter.bi_sector;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	block = __sector_to_block(ec, sector);
1468c2ecf20Sopenharmony_ci	blocks = __nr_blocks(ec, bio);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	/*
1498c2ecf20Sopenharmony_ci	 * Partial first underlying block (__nr_blocks() may have
1508c2ecf20Sopenharmony_ci	 * resulted in one block).
1518c2ecf20Sopenharmony_ci	 */
1528c2ecf20Sopenharmony_ci	if (__block_mod(sector, ec->u_bs)) {
1538c2ecf20Sopenharmony_ci		block++;
1548c2ecf20Sopenharmony_ci		blocks--;
1558c2ecf20Sopenharmony_ci	}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/* Partial last underlying block if any. */
1588c2ecf20Sopenharmony_ci	if (blocks && __block_mod(bio_end_sector(bio), ec->u_bs))
1598c2ecf20Sopenharmony_ci		blocks--;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	return blocks ? dm_bufio_issue_discard(ec->bufio, block, blocks) : 0;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci/* Release blocks them from the bufio cache. */
1658c2ecf20Sopenharmony_cistatic void __ebs_forget_bio(struct ebs_c *ec, struct bio *bio)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	sector_t blocks, sector = bio->bi_iter.bi_sector;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	blocks = __nr_blocks(ec, bio);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	dm_bufio_forget_buffers(ec->bufio, __sector_to_block(ec, sector), blocks);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci/* Worker funtion to process incoming bios. */
1758c2ecf20Sopenharmony_cistatic void __ebs_process_bios(struct work_struct *ws)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	int r;
1788c2ecf20Sopenharmony_ci	bool write = false;
1798c2ecf20Sopenharmony_ci	sector_t block1, block2;
1808c2ecf20Sopenharmony_ci	struct ebs_c *ec = container_of(ws, struct ebs_c, ws);
1818c2ecf20Sopenharmony_ci	struct bio *bio;
1828c2ecf20Sopenharmony_ci	struct bio_list bios;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	bio_list_init(&bios);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	spin_lock_irq(&ec->lock);
1878c2ecf20Sopenharmony_ci	bios = ec->bios_in;
1888c2ecf20Sopenharmony_ci	bio_list_init(&ec->bios_in);
1898c2ecf20Sopenharmony_ci	spin_unlock_irq(&ec->lock);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	/* Prefetch all read and any mis-aligned write buffers */
1928c2ecf20Sopenharmony_ci	bio_list_for_each(bio, &bios) {
1938c2ecf20Sopenharmony_ci		block1 = __sector_to_block(ec, bio->bi_iter.bi_sector);
1948c2ecf20Sopenharmony_ci		if (bio_op(bio) == REQ_OP_READ)
1958c2ecf20Sopenharmony_ci			dm_bufio_prefetch(ec->bufio, block1, __nr_blocks(ec, bio));
1968c2ecf20Sopenharmony_ci		else if (bio_op(bio) == REQ_OP_WRITE && !(bio->bi_opf & REQ_PREFLUSH)) {
1978c2ecf20Sopenharmony_ci			block2 = __sector_to_block(ec, bio_end_sector(bio));
1988c2ecf20Sopenharmony_ci			if (__block_mod(bio->bi_iter.bi_sector, ec->u_bs))
1998c2ecf20Sopenharmony_ci				dm_bufio_prefetch(ec->bufio, block1, 1);
2008c2ecf20Sopenharmony_ci			if (__block_mod(bio_end_sector(bio), ec->u_bs) && block2 != block1)
2018c2ecf20Sopenharmony_ci				dm_bufio_prefetch(ec->bufio, block2, 1);
2028c2ecf20Sopenharmony_ci		}
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	bio_list_for_each(bio, &bios) {
2068c2ecf20Sopenharmony_ci		r = -EIO;
2078c2ecf20Sopenharmony_ci		if (bio_op(bio) == REQ_OP_READ)
2088c2ecf20Sopenharmony_ci			r = __ebs_rw_bio(ec, READ, bio);
2098c2ecf20Sopenharmony_ci		else if (bio_op(bio) == REQ_OP_WRITE) {
2108c2ecf20Sopenharmony_ci			write = true;
2118c2ecf20Sopenharmony_ci			r = __ebs_rw_bio(ec, WRITE, bio);
2128c2ecf20Sopenharmony_ci		} else if (bio_op(bio) == REQ_OP_DISCARD) {
2138c2ecf20Sopenharmony_ci			__ebs_forget_bio(ec, bio);
2148c2ecf20Sopenharmony_ci			r = __ebs_discard_bio(ec, bio);
2158c2ecf20Sopenharmony_ci		}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci		if (r < 0)
2188c2ecf20Sopenharmony_ci			bio->bi_status = errno_to_blk_status(r);
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	/*
2228c2ecf20Sopenharmony_ci	 * We write dirty buffers after processing I/O on them
2238c2ecf20Sopenharmony_ci	 * but before we endio thus addressing REQ_FUA/REQ_SYNC.
2248c2ecf20Sopenharmony_ci	 */
2258c2ecf20Sopenharmony_ci	r = write ? dm_bufio_write_dirty_buffers(ec->bufio) : 0;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	while ((bio = bio_list_pop(&bios))) {
2288c2ecf20Sopenharmony_ci		/* Any other request is endioed. */
2298c2ecf20Sopenharmony_ci		if (unlikely(r && bio_op(bio) == REQ_OP_WRITE))
2308c2ecf20Sopenharmony_ci			bio_io_error(bio);
2318c2ecf20Sopenharmony_ci		else
2328c2ecf20Sopenharmony_ci			bio_endio(bio);
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci/*
2378c2ecf20Sopenharmony_ci * Construct an emulated block size mapping: <dev_path> <offset> <ebs> [<ubs>]
2388c2ecf20Sopenharmony_ci *
2398c2ecf20Sopenharmony_ci * <dev_path>: path of the underlying device
2408c2ecf20Sopenharmony_ci * <offset>: offset in 512 bytes sectors into <dev_path>
2418c2ecf20Sopenharmony_ci * <ebs>: emulated block size in units of 512 bytes exposed to the upper layer
2428c2ecf20Sopenharmony_ci * [<ubs>]: underlying block size in units of 512 bytes imposed on the lower layer;
2438c2ecf20Sopenharmony_ci * 	    optional, if not supplied, retrieve logical block size from underlying device
2448c2ecf20Sopenharmony_ci */
2458c2ecf20Sopenharmony_cistatic int ebs_ctr(struct dm_target *ti, unsigned int argc, char **argv)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	int r;
2488c2ecf20Sopenharmony_ci	unsigned short tmp1;
2498c2ecf20Sopenharmony_ci	unsigned long long tmp;
2508c2ecf20Sopenharmony_ci	char dummy;
2518c2ecf20Sopenharmony_ci	struct ebs_c *ec;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	if (argc < 3 || argc > 4) {
2548c2ecf20Sopenharmony_ci		ti->error = "Invalid argument count";
2558c2ecf20Sopenharmony_ci		return -EINVAL;
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	ec = ti->private = kzalloc(sizeof(*ec), GFP_KERNEL);
2598c2ecf20Sopenharmony_ci	if (!ec) {
2608c2ecf20Sopenharmony_ci		ti->error = "Cannot allocate ebs context";
2618c2ecf20Sopenharmony_ci		return -ENOMEM;
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	r = -EINVAL;
2658c2ecf20Sopenharmony_ci	if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1 ||
2668c2ecf20Sopenharmony_ci	    tmp != (sector_t)tmp ||
2678c2ecf20Sopenharmony_ci	    (sector_t)tmp >= ti->len) {
2688c2ecf20Sopenharmony_ci		ti->error = "Invalid device offset sector";
2698c2ecf20Sopenharmony_ci		goto bad;
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci	ec->start = tmp;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	if (sscanf(argv[2], "%hu%c", &tmp1, &dummy) != 1 ||
2748c2ecf20Sopenharmony_ci	    !__ebs_check_bs(tmp1) ||
2758c2ecf20Sopenharmony_ci	    to_bytes(tmp1) > PAGE_SIZE) {
2768c2ecf20Sopenharmony_ci		ti->error = "Invalid emulated block size";
2778c2ecf20Sopenharmony_ci		goto bad;
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci	ec->e_bs = tmp1;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	if (argc > 3) {
2828c2ecf20Sopenharmony_ci		if (sscanf(argv[3], "%hu%c", &tmp1, &dummy) != 1 || !__ebs_check_bs(tmp1)) {
2838c2ecf20Sopenharmony_ci			ti->error = "Invalid underlying block size";
2848c2ecf20Sopenharmony_ci			goto bad;
2858c2ecf20Sopenharmony_ci		}
2868c2ecf20Sopenharmony_ci		ec->u_bs = tmp1;
2878c2ecf20Sopenharmony_ci		ec->u_bs_set = true;
2888c2ecf20Sopenharmony_ci	} else
2898c2ecf20Sopenharmony_ci		ec->u_bs_set = false;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &ec->dev);
2928c2ecf20Sopenharmony_ci	if (r) {
2938c2ecf20Sopenharmony_ci		ti->error = "Device lookup failed";
2948c2ecf20Sopenharmony_ci		ec->dev = NULL;
2958c2ecf20Sopenharmony_ci		goto bad;
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	r = -EINVAL;
2998c2ecf20Sopenharmony_ci	if (!ec->u_bs_set) {
3008c2ecf20Sopenharmony_ci		ec->u_bs = to_sector(bdev_logical_block_size(ec->dev->bdev));
3018c2ecf20Sopenharmony_ci		if (!__ebs_check_bs(ec->u_bs)) {
3028c2ecf20Sopenharmony_ci			ti->error = "Invalid retrieved underlying block size";
3038c2ecf20Sopenharmony_ci			goto bad;
3048c2ecf20Sopenharmony_ci		}
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (!ec->u_bs_set && ec->e_bs == ec->u_bs)
3088c2ecf20Sopenharmony_ci		DMINFO("Emulation superfluous: emulated equal to underlying block size");
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	if (__block_mod(ec->start, ec->u_bs)) {
3118c2ecf20Sopenharmony_ci		ti->error = "Device offset must be multiple of underlying block size";
3128c2ecf20Sopenharmony_ci		goto bad;
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	ec->bufio = dm_bufio_client_create(ec->dev->bdev, to_bytes(ec->u_bs), 1, 0, NULL, NULL);
3168c2ecf20Sopenharmony_ci	if (IS_ERR(ec->bufio)) {
3178c2ecf20Sopenharmony_ci		ti->error = "Cannot create dm bufio client";
3188c2ecf20Sopenharmony_ci		r = PTR_ERR(ec->bufio);
3198c2ecf20Sopenharmony_ci		ec->bufio = NULL;
3208c2ecf20Sopenharmony_ci		goto bad;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	ec->wq = alloc_ordered_workqueue("dm-" DM_MSG_PREFIX, WQ_MEM_RECLAIM);
3248c2ecf20Sopenharmony_ci	if (!ec->wq) {
3258c2ecf20Sopenharmony_ci		ti->error = "Cannot create dm-" DM_MSG_PREFIX " workqueue";
3268c2ecf20Sopenharmony_ci		r = -ENOMEM;
3278c2ecf20Sopenharmony_ci		goto bad;
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	ec->block_shift = __ffs(ec->u_bs);
3318c2ecf20Sopenharmony_ci	INIT_WORK(&ec->ws, &__ebs_process_bios);
3328c2ecf20Sopenharmony_ci	bio_list_init(&ec->bios_in);
3338c2ecf20Sopenharmony_ci	spin_lock_init(&ec->lock);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	ti->num_flush_bios = 1;
3368c2ecf20Sopenharmony_ci	ti->num_discard_bios = 1;
3378c2ecf20Sopenharmony_ci	ti->num_secure_erase_bios = 0;
3388c2ecf20Sopenharmony_ci	ti->num_write_same_bios = 0;
3398c2ecf20Sopenharmony_ci	ti->num_write_zeroes_bios = 0;
3408c2ecf20Sopenharmony_ci	return 0;
3418c2ecf20Sopenharmony_cibad:
3428c2ecf20Sopenharmony_ci	ebs_dtr(ti);
3438c2ecf20Sopenharmony_ci	return r;
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic void ebs_dtr(struct dm_target *ti)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct ebs_c *ec = ti->private;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (ec->wq)
3518c2ecf20Sopenharmony_ci		destroy_workqueue(ec->wq);
3528c2ecf20Sopenharmony_ci	if (ec->bufio)
3538c2ecf20Sopenharmony_ci		dm_bufio_client_destroy(ec->bufio);
3548c2ecf20Sopenharmony_ci	if (ec->dev)
3558c2ecf20Sopenharmony_ci		dm_put_device(ti, ec->dev);
3568c2ecf20Sopenharmony_ci	kfree(ec);
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic int ebs_map(struct dm_target *ti, struct bio *bio)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	struct ebs_c *ec = ti->private;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	bio_set_dev(bio, ec->dev->bdev);
3648c2ecf20Sopenharmony_ci	bio->bi_iter.bi_sector = ec->start + dm_target_offset(ti, bio->bi_iter.bi_sector);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (unlikely(bio_op(bio) == REQ_OP_FLUSH))
3678c2ecf20Sopenharmony_ci		return DM_MAPIO_REMAPPED;
3688c2ecf20Sopenharmony_ci	/*
3698c2ecf20Sopenharmony_ci	 * Only queue for bufio processing in case of partial or overlapping buffers
3708c2ecf20Sopenharmony_ci	 * -or-
3718c2ecf20Sopenharmony_ci	 * emulation with ebs == ubs aiming for tests of dm-bufio overhead.
3728c2ecf20Sopenharmony_ci	 */
3738c2ecf20Sopenharmony_ci	if (likely(__block_mod(bio->bi_iter.bi_sector, ec->u_bs) ||
3748c2ecf20Sopenharmony_ci		   __block_mod(bio_end_sector(bio), ec->u_bs) ||
3758c2ecf20Sopenharmony_ci		   ec->e_bs == ec->u_bs)) {
3768c2ecf20Sopenharmony_ci		spin_lock_irq(&ec->lock);
3778c2ecf20Sopenharmony_ci		bio_list_add(&ec->bios_in, bio);
3788c2ecf20Sopenharmony_ci		spin_unlock_irq(&ec->lock);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci		queue_work(ec->wq, &ec->ws);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci		return DM_MAPIO_SUBMITTED;
3838c2ecf20Sopenharmony_ci	}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	/* Forget any buffer content relative to this direct backing device I/O. */
3868c2ecf20Sopenharmony_ci	__ebs_forget_bio(ec, bio);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	return DM_MAPIO_REMAPPED;
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic void ebs_status(struct dm_target *ti, status_type_t type,
3928c2ecf20Sopenharmony_ci		       unsigned status_flags, char *result, unsigned maxlen)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	struct ebs_c *ec = ti->private;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	switch (type) {
3978c2ecf20Sopenharmony_ci	case STATUSTYPE_INFO:
3988c2ecf20Sopenharmony_ci		*result = '\0';
3998c2ecf20Sopenharmony_ci		break;
4008c2ecf20Sopenharmony_ci	case STATUSTYPE_TABLE:
4018c2ecf20Sopenharmony_ci		snprintf(result, maxlen, ec->u_bs_set ? "%s %llu %u %u" : "%s %llu %u",
4028c2ecf20Sopenharmony_ci			 ec->dev->name, (unsigned long long) ec->start, ec->e_bs, ec->u_bs);
4038c2ecf20Sopenharmony_ci		break;
4048c2ecf20Sopenharmony_ci	}
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic int ebs_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	struct ebs_c *ec = ti->private;
4108c2ecf20Sopenharmony_ci	struct dm_dev *dev = ec->dev;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	/*
4138c2ecf20Sopenharmony_ci	 * Only pass ioctls through if the device sizes match exactly.
4148c2ecf20Sopenharmony_ci	 */
4158c2ecf20Sopenharmony_ci	*bdev = dev->bdev;
4168c2ecf20Sopenharmony_ci	return !!(ec->start || ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT);
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistatic void ebs_io_hints(struct dm_target *ti, struct queue_limits *limits)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	struct ebs_c *ec = ti->private;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	limits->logical_block_size = to_bytes(ec->e_bs);
4248c2ecf20Sopenharmony_ci	limits->physical_block_size = to_bytes(ec->u_bs);
4258c2ecf20Sopenharmony_ci	limits->alignment_offset = limits->physical_block_size;
4268c2ecf20Sopenharmony_ci	blk_limits_io_min(limits, limits->logical_block_size);
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic int ebs_iterate_devices(struct dm_target *ti,
4308c2ecf20Sopenharmony_ci				  iterate_devices_callout_fn fn, void *data)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	struct ebs_c *ec = ti->private;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	return fn(ti, ec->dev, ec->start, ti->len, data);
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic struct target_type ebs_target = {
4388c2ecf20Sopenharmony_ci	.name		 = "ebs",
4398c2ecf20Sopenharmony_ci	.version	 = {1, 0, 1},
4408c2ecf20Sopenharmony_ci	.features	 = DM_TARGET_PASSES_INTEGRITY,
4418c2ecf20Sopenharmony_ci	.module		 = THIS_MODULE,
4428c2ecf20Sopenharmony_ci	.ctr		 = ebs_ctr,
4438c2ecf20Sopenharmony_ci	.dtr		 = ebs_dtr,
4448c2ecf20Sopenharmony_ci	.map		 = ebs_map,
4458c2ecf20Sopenharmony_ci	.status		 = ebs_status,
4468c2ecf20Sopenharmony_ci	.io_hints	 = ebs_io_hints,
4478c2ecf20Sopenharmony_ci	.prepare_ioctl	 = ebs_prepare_ioctl,
4488c2ecf20Sopenharmony_ci	.iterate_devices = ebs_iterate_devices,
4498c2ecf20Sopenharmony_ci};
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_cistatic int __init dm_ebs_init(void)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	int r = dm_register_target(&ebs_target);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	if (r < 0)
4568c2ecf20Sopenharmony_ci		DMERR("register failed %d", r);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	return r;
4598c2ecf20Sopenharmony_ci}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_cistatic void dm_ebs_exit(void)
4628c2ecf20Sopenharmony_ci{
4638c2ecf20Sopenharmony_ci	dm_unregister_target(&ebs_target);
4648c2ecf20Sopenharmony_ci}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_cimodule_init(dm_ebs_init);
4678c2ecf20Sopenharmony_cimodule_exit(dm_ebs_exit);
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ciMODULE_AUTHOR("Heinz Mauelshagen <dm-devel@redhat.com>");
4708c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DM_NAME " emulated block size target");
4718c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
472