18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (C) 2001-2003 Sistina Software (UK) Limited.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is released under the GPL.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include "dm.h"
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
118c2ecf20Sopenharmony_ci#include <linux/bio.h>
128c2ecf20Sopenharmony_ci#include <linux/dax.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci#include <linux/device-mapper.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define DM_MSG_PREFIX "linear"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/*
198c2ecf20Sopenharmony_ci * Linear: maps a linear range of a device.
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_cistruct linear_c {
228c2ecf20Sopenharmony_ci	struct dm_dev *dev;
238c2ecf20Sopenharmony_ci	sector_t start;
248c2ecf20Sopenharmony_ci};
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/*
278c2ecf20Sopenharmony_ci * Construct a linear mapping: <dev_path> <offset>
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_cistatic int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	struct linear_c *lc;
328c2ecf20Sopenharmony_ci	unsigned long long tmp;
338c2ecf20Sopenharmony_ci	char dummy;
348c2ecf20Sopenharmony_ci	int ret;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	if (argc != 2) {
378c2ecf20Sopenharmony_ci		ti->error = "Invalid argument count";
388c2ecf20Sopenharmony_ci		return -EINVAL;
398c2ecf20Sopenharmony_ci	}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	lc = kmalloc(sizeof(*lc), GFP_KERNEL);
428c2ecf20Sopenharmony_ci	if (lc == NULL) {
438c2ecf20Sopenharmony_ci		ti->error = "Cannot allocate linear context";
448c2ecf20Sopenharmony_ci		return -ENOMEM;
458c2ecf20Sopenharmony_ci	}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	ret = -EINVAL;
488c2ecf20Sopenharmony_ci	if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1 || tmp != (sector_t)tmp) {
498c2ecf20Sopenharmony_ci		ti->error = "Invalid device sector";
508c2ecf20Sopenharmony_ci		goto bad;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci	lc->start = tmp;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	ret = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &lc->dev);
558c2ecf20Sopenharmony_ci	if (ret) {
568c2ecf20Sopenharmony_ci		ti->error = "Device lookup failed";
578c2ecf20Sopenharmony_ci		goto bad;
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	ti->num_flush_bios = 1;
618c2ecf20Sopenharmony_ci	ti->num_discard_bios = 1;
628c2ecf20Sopenharmony_ci	ti->num_secure_erase_bios = 1;
638c2ecf20Sopenharmony_ci	ti->num_write_same_bios = 1;
648c2ecf20Sopenharmony_ci	ti->num_write_zeroes_bios = 1;
658c2ecf20Sopenharmony_ci	ti->private = lc;
668c2ecf20Sopenharmony_ci	return 0;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci      bad:
698c2ecf20Sopenharmony_ci	kfree(lc);
708c2ecf20Sopenharmony_ci	return ret;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic void linear_dtr(struct dm_target *ti)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	struct linear_c *lc = (struct linear_c *) ti->private;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	dm_put_device(ti, lc->dev);
788c2ecf20Sopenharmony_ci	kfree(lc);
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic sector_t linear_map_sector(struct dm_target *ti, sector_t bi_sector)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct linear_c *lc = ti->private;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	return lc->start + dm_target_offset(ti, bi_sector);
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic void linear_map_bio(struct dm_target *ti, struct bio *bio)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	struct linear_c *lc = ti->private;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	bio_set_dev(bio, lc->dev->bdev);
938c2ecf20Sopenharmony_ci	if (bio_sectors(bio) || op_is_zone_mgmt(bio_op(bio)))
948c2ecf20Sopenharmony_ci		bio->bi_iter.bi_sector =
958c2ecf20Sopenharmony_ci			linear_map_sector(ti, bio->bi_iter.bi_sector);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic int linear_map(struct dm_target *ti, struct bio *bio)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	linear_map_bio(ti, bio);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	return DM_MAPIO_REMAPPED;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic void linear_status(struct dm_target *ti, status_type_t type,
1068c2ecf20Sopenharmony_ci			  unsigned status_flags, char *result, unsigned maxlen)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	struct linear_c *lc = (struct linear_c *) ti->private;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	switch (type) {
1118c2ecf20Sopenharmony_ci	case STATUSTYPE_INFO:
1128c2ecf20Sopenharmony_ci		result[0] = '\0';
1138c2ecf20Sopenharmony_ci		break;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	case STATUSTYPE_TABLE:
1168c2ecf20Sopenharmony_ci		snprintf(result, maxlen, "%s %llu", lc->dev->name,
1178c2ecf20Sopenharmony_ci				(unsigned long long)lc->start);
1188c2ecf20Sopenharmony_ci		break;
1198c2ecf20Sopenharmony_ci	}
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic int linear_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	struct linear_c *lc = (struct linear_c *) ti->private;
1258c2ecf20Sopenharmony_ci	struct dm_dev *dev = lc->dev;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	*bdev = dev->bdev;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	/*
1308c2ecf20Sopenharmony_ci	 * Only pass ioctls through if the device sizes match exactly.
1318c2ecf20Sopenharmony_ci	 */
1328c2ecf20Sopenharmony_ci	if (lc->start ||
1338c2ecf20Sopenharmony_ci	    ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
1348c2ecf20Sopenharmony_ci		return 1;
1358c2ecf20Sopenharmony_ci	return 0;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED
1398c2ecf20Sopenharmony_cistatic int linear_report_zones(struct dm_target *ti,
1408c2ecf20Sopenharmony_ci		struct dm_report_zones_args *args, unsigned int nr_zones)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	struct linear_c *lc = ti->private;
1438c2ecf20Sopenharmony_ci	sector_t sector = linear_map_sector(ti, args->next_sector);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	args->start = lc->start;
1468c2ecf20Sopenharmony_ci	return blkdev_report_zones(lc->dev->bdev, sector, nr_zones,
1478c2ecf20Sopenharmony_ci				   dm_report_zones_cb, args);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci#endif
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic int linear_iterate_devices(struct dm_target *ti,
1528c2ecf20Sopenharmony_ci				  iterate_devices_callout_fn fn, void *data)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	struct linear_c *lc = ti->private;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	return fn(ti, lc->dev, lc->start, ti->len, data);
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DAX_DRIVER)
1608c2ecf20Sopenharmony_cistatic long linear_dax_direct_access(struct dm_target *ti, pgoff_t pgoff,
1618c2ecf20Sopenharmony_ci		long nr_pages, void **kaddr, pfn_t *pfn)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	long ret;
1648c2ecf20Sopenharmony_ci	struct linear_c *lc = ti->private;
1658c2ecf20Sopenharmony_ci	struct block_device *bdev = lc->dev->bdev;
1668c2ecf20Sopenharmony_ci	struct dax_device *dax_dev = lc->dev->dax_dev;
1678c2ecf20Sopenharmony_ci	sector_t dev_sector, sector = pgoff * PAGE_SECTORS;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	dev_sector = linear_map_sector(ti, sector);
1708c2ecf20Sopenharmony_ci	ret = bdev_dax_pgoff(bdev, dev_sector, nr_pages * PAGE_SIZE, &pgoff);
1718c2ecf20Sopenharmony_ci	if (ret)
1728c2ecf20Sopenharmony_ci		return ret;
1738c2ecf20Sopenharmony_ci	return dax_direct_access(dax_dev, pgoff, nr_pages, kaddr, pfn);
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic size_t linear_dax_copy_from_iter(struct dm_target *ti, pgoff_t pgoff,
1778c2ecf20Sopenharmony_ci		void *addr, size_t bytes, struct iov_iter *i)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	struct linear_c *lc = ti->private;
1808c2ecf20Sopenharmony_ci	struct block_device *bdev = lc->dev->bdev;
1818c2ecf20Sopenharmony_ci	struct dax_device *dax_dev = lc->dev->dax_dev;
1828c2ecf20Sopenharmony_ci	sector_t dev_sector, sector = pgoff * PAGE_SECTORS;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	dev_sector = linear_map_sector(ti, sector);
1858c2ecf20Sopenharmony_ci	if (bdev_dax_pgoff(bdev, dev_sector, ALIGN(bytes, PAGE_SIZE), &pgoff))
1868c2ecf20Sopenharmony_ci		return 0;
1878c2ecf20Sopenharmony_ci	return dax_copy_from_iter(dax_dev, pgoff, addr, bytes, i);
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic size_t linear_dax_copy_to_iter(struct dm_target *ti, pgoff_t pgoff,
1918c2ecf20Sopenharmony_ci		void *addr, size_t bytes, struct iov_iter *i)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	struct linear_c *lc = ti->private;
1948c2ecf20Sopenharmony_ci	struct block_device *bdev = lc->dev->bdev;
1958c2ecf20Sopenharmony_ci	struct dax_device *dax_dev = lc->dev->dax_dev;
1968c2ecf20Sopenharmony_ci	sector_t dev_sector, sector = pgoff * PAGE_SECTORS;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	dev_sector = linear_map_sector(ti, sector);
1998c2ecf20Sopenharmony_ci	if (bdev_dax_pgoff(bdev, dev_sector, ALIGN(bytes, PAGE_SIZE), &pgoff))
2008c2ecf20Sopenharmony_ci		return 0;
2018c2ecf20Sopenharmony_ci	return dax_copy_to_iter(dax_dev, pgoff, addr, bytes, i);
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic int linear_dax_zero_page_range(struct dm_target *ti, pgoff_t pgoff,
2058c2ecf20Sopenharmony_ci				      size_t nr_pages)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	int ret;
2088c2ecf20Sopenharmony_ci	struct linear_c *lc = ti->private;
2098c2ecf20Sopenharmony_ci	struct block_device *bdev = lc->dev->bdev;
2108c2ecf20Sopenharmony_ci	struct dax_device *dax_dev = lc->dev->dax_dev;
2118c2ecf20Sopenharmony_ci	sector_t dev_sector, sector = pgoff * PAGE_SECTORS;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	dev_sector = linear_map_sector(ti, sector);
2148c2ecf20Sopenharmony_ci	ret = bdev_dax_pgoff(bdev, dev_sector, nr_pages << PAGE_SHIFT, &pgoff);
2158c2ecf20Sopenharmony_ci	if (ret)
2168c2ecf20Sopenharmony_ci		return ret;
2178c2ecf20Sopenharmony_ci	return dax_zero_page_range(dax_dev, pgoff, nr_pages);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci#else
2218c2ecf20Sopenharmony_ci#define linear_dax_direct_access NULL
2228c2ecf20Sopenharmony_ci#define linear_dax_copy_from_iter NULL
2238c2ecf20Sopenharmony_ci#define linear_dax_copy_to_iter NULL
2248c2ecf20Sopenharmony_ci#define linear_dax_zero_page_range NULL
2258c2ecf20Sopenharmony_ci#endif
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic struct target_type linear_target = {
2288c2ecf20Sopenharmony_ci	.name   = "linear",
2298c2ecf20Sopenharmony_ci	.version = {1, 4, 0},
2308c2ecf20Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED
2318c2ecf20Sopenharmony_ci	.features = DM_TARGET_PASSES_INTEGRITY | DM_TARGET_NOWAIT |
2328c2ecf20Sopenharmony_ci		    DM_TARGET_ZONED_HM,
2338c2ecf20Sopenharmony_ci	.report_zones = linear_report_zones,
2348c2ecf20Sopenharmony_ci#else
2358c2ecf20Sopenharmony_ci	.features = DM_TARGET_PASSES_INTEGRITY | DM_TARGET_NOWAIT,
2368c2ecf20Sopenharmony_ci#endif
2378c2ecf20Sopenharmony_ci	.module = THIS_MODULE,
2388c2ecf20Sopenharmony_ci	.ctr    = linear_ctr,
2398c2ecf20Sopenharmony_ci	.dtr    = linear_dtr,
2408c2ecf20Sopenharmony_ci	.map    = linear_map,
2418c2ecf20Sopenharmony_ci	.status = linear_status,
2428c2ecf20Sopenharmony_ci	.prepare_ioctl = linear_prepare_ioctl,
2438c2ecf20Sopenharmony_ci	.iterate_devices = linear_iterate_devices,
2448c2ecf20Sopenharmony_ci	.direct_access = linear_dax_direct_access,
2458c2ecf20Sopenharmony_ci	.dax_copy_from_iter = linear_dax_copy_from_iter,
2468c2ecf20Sopenharmony_ci	.dax_copy_to_iter = linear_dax_copy_to_iter,
2478c2ecf20Sopenharmony_ci	.dax_zero_page_range = linear_dax_zero_page_range,
2488c2ecf20Sopenharmony_ci};
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ciint __init dm_linear_init(void)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	int r = dm_register_target(&linear_target);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if (r < 0)
2558c2ecf20Sopenharmony_ci		DMERR("register failed %d", r);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	return r;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_civoid dm_linear_exit(void)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	dm_unregister_target(&linear_target);
2638c2ecf20Sopenharmony_ci}
264