brintos

brintos / linux-shallow public Read only

0
0
Text · 5.3 KiB · 49fb0f6 Raw
232 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2001-2003 Sistina Software (UK) Limited.4 *5 * This file is released under the GPL.6 */7 8#include "dm.h"9#include <linux/module.h>10#include <linux/init.h>11#include <linux/blkdev.h>12#include <linux/bio.h>13#include <linux/dax.h>14#include <linux/slab.h>15#include <linux/device-mapper.h>16 17#define DM_MSG_PREFIX "linear"18 19/*20 * Linear: maps a linear range of a device.21 */22struct linear_c {23	struct dm_dev *dev;24	sector_t start;25};26 27/*28 * Construct a linear mapping: <dev_path> <offset>29 */30static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)31{32	struct linear_c *lc;33	unsigned long long tmp;34	char dummy;35	int ret;36 37	if (argc != 2) {38		ti->error = "Invalid argument count";39		return -EINVAL;40	}41 42	lc = kmalloc(sizeof(*lc), GFP_KERNEL);43	if (lc == NULL) {44		ti->error = "Cannot allocate linear context";45		return -ENOMEM;46	}47 48	ret = -EINVAL;49	if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1 || tmp != (sector_t)tmp) {50		ti->error = "Invalid device sector";51		goto bad;52	}53	lc->start = tmp;54 55	ret = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &lc->dev);56	if (ret) {57		ti->error = "Device lookup failed";58		goto bad;59	}60 61	ti->num_flush_bios = 1;62	ti->num_discard_bios = 1;63	ti->num_secure_erase_bios = 1;64	ti->num_write_zeroes_bios = 1;65	ti->flush_bypasses_map = true;66	ti->private = lc;67	return 0;68 69bad:70	kfree(lc);71	return ret;72}73 74static void linear_dtr(struct dm_target *ti)75{76	struct linear_c *lc = ti->private;77 78	dm_put_device(ti, lc->dev);79	kfree(lc);80}81 82static sector_t linear_map_sector(struct dm_target *ti, sector_t bi_sector)83{84	struct linear_c *lc = ti->private;85 86	return lc->start + dm_target_offset(ti, bi_sector);87}88 89int linear_map(struct dm_target *ti, struct bio *bio)90{91	struct linear_c *lc = ti->private;92 93	bio_set_dev(bio, lc->dev->bdev);94	bio->bi_iter.bi_sector = linear_map_sector(ti, bio->bi_iter.bi_sector);95 96	return DM_MAPIO_REMAPPED;97}98 99static void linear_status(struct dm_target *ti, status_type_t type,100			  unsigned int status_flags, char *result, unsigned int maxlen)101{102	struct linear_c *lc = ti->private;103	size_t sz = 0;104 105	switch (type) {106	case STATUSTYPE_INFO:107		result[0] = '\0';108		break;109 110	case STATUSTYPE_TABLE:111		DMEMIT("%s %llu", lc->dev->name, (unsigned long long)lc->start);112		break;113 114	case STATUSTYPE_IMA:115		DMEMIT_TARGET_NAME_VERSION(ti->type);116		DMEMIT(",device_name=%s,start=%llu;", lc->dev->name,117		       (unsigned long long)lc->start);118		break;119	}120}121 122static int linear_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)123{124	struct linear_c *lc = ti->private;125	struct dm_dev *dev = lc->dev;126 127	*bdev = dev->bdev;128 129	/*130	 * Only pass ioctls through if the device sizes match exactly.131	 */132	if (lc->start || ti->len != bdev_nr_sectors(dev->bdev))133		return 1;134	return 0;135}136 137#ifdef CONFIG_BLK_DEV_ZONED138static int linear_report_zones(struct dm_target *ti,139		struct dm_report_zones_args *args, unsigned int nr_zones)140{141	struct linear_c *lc = ti->private;142 143	return dm_report_zones(lc->dev->bdev, lc->start,144			       linear_map_sector(ti, args->next_sector),145			       args, nr_zones);146}147#else148#define linear_report_zones NULL149#endif150 151static int linear_iterate_devices(struct dm_target *ti,152				  iterate_devices_callout_fn fn, void *data)153{154	struct linear_c *lc = ti->private;155 156	return fn(ti, lc->dev, lc->start, ti->len, data);157}158 159#if IS_ENABLED(CONFIG_FS_DAX)160static struct dax_device *linear_dax_pgoff(struct dm_target *ti, pgoff_t *pgoff)161{162	struct linear_c *lc = ti->private;163	sector_t sector = linear_map_sector(ti, *pgoff << PAGE_SECTORS_SHIFT);164 165	*pgoff = (get_start_sect(lc->dev->bdev) + sector) >> PAGE_SECTORS_SHIFT;166	return lc->dev->dax_dev;167}168 169static long linear_dax_direct_access(struct dm_target *ti, pgoff_t pgoff,170		long nr_pages, enum dax_access_mode mode, void **kaddr,171		pfn_t *pfn)172{173	struct dax_device *dax_dev = linear_dax_pgoff(ti, &pgoff);174 175	return dax_direct_access(dax_dev, pgoff, nr_pages, mode, kaddr, pfn);176}177 178static int linear_dax_zero_page_range(struct dm_target *ti, pgoff_t pgoff,179				      size_t nr_pages)180{181	struct dax_device *dax_dev = linear_dax_pgoff(ti, &pgoff);182 183	return dax_zero_page_range(dax_dev, pgoff, nr_pages);184}185 186static size_t linear_dax_recovery_write(struct dm_target *ti, pgoff_t pgoff,187		void *addr, size_t bytes, struct iov_iter *i)188{189	struct dax_device *dax_dev = linear_dax_pgoff(ti, &pgoff);190 191	return dax_recovery_write(dax_dev, pgoff, addr, bytes, i);192}193 194#else195#define linear_dax_direct_access NULL196#define linear_dax_zero_page_range NULL197#define linear_dax_recovery_write NULL198#endif199 200static struct target_type linear_target = {201	.name   = "linear",202	.version = {1, 4, 0},203	.features = DM_TARGET_PASSES_INTEGRITY | DM_TARGET_NOWAIT |204		    DM_TARGET_ZONED_HM | DM_TARGET_PASSES_CRYPTO,205	.report_zones = linear_report_zones,206	.module = THIS_MODULE,207	.ctr    = linear_ctr,208	.dtr    = linear_dtr,209	.map    = linear_map,210	.status = linear_status,211	.prepare_ioctl = linear_prepare_ioctl,212	.iterate_devices = linear_iterate_devices,213	.direct_access = linear_dax_direct_access,214	.dax_zero_page_range = linear_dax_zero_page_range,215	.dax_recovery_write = linear_dax_recovery_write,216};217 218int __init dm_linear_init(void)219{220	int r = dm_register_target(&linear_target);221 222	if (r < 0)223		DMERR("register failed %d", r);224 225	return r;226}227 228void dm_linear_exit(void)229{230	dm_unregister_target(&linear_target);231}232