cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dm-linear.c (5380B)


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