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