linux/drivers/md/dm-linear.c
<<
>>
Prefs
   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_same_bios = 1;
  64        ti->num_write_zeroes_bios = 1;
  65        ti->private = lc;
  66        return 0;
  67
  68      bad:
  69        kfree(lc);
  70        return ret;
  71}
  72
  73static void linear_dtr(struct dm_target *ti)
  74{
  75        struct linear_c *lc = (struct linear_c *) ti->private;
  76
  77        dm_put_device(ti, lc->dev);
  78        kfree(lc);
  79}
  80
  81static sector_t linear_map_sector(struct dm_target *ti, sector_t bi_sector)
  82{
  83        struct linear_c *lc = ti->private;
  84
  85        return lc->start + dm_target_offset(ti, bi_sector);
  86}
  87
  88static void linear_map_bio(struct dm_target *ti, struct bio *bio)
  89{
  90        struct linear_c *lc = ti->private;
  91
  92        bio_set_dev(bio, lc->dev->bdev);
  93        if (bio_sectors(bio) || op_is_zone_mgmt(bio_op(bio)))
  94                bio->bi_iter.bi_sector =
  95                        linear_map_sector(ti, bio->bi_iter.bi_sector);
  96}
  97
  98static int linear_map(struct dm_target *ti, struct bio *bio)
  99{
 100        linear_map_bio(ti, bio);
 101
 102        return DM_MAPIO_REMAPPED;
 103}
 104
 105static void linear_status(struct dm_target *ti, status_type_t type,
 106                          unsigned status_flags, char *result, unsigned maxlen)
 107{
 108        struct linear_c *lc = (struct linear_c *) ti->private;
 109        size_t sz = 0;
 110
 111        switch (type) {
 112        case STATUSTYPE_INFO:
 113                result[0] = '\0';
 114                break;
 115
 116        case STATUSTYPE_TABLE:
 117                DMEMIT("%s %llu", lc->dev->name, (unsigned long long)lc->start);
 118                break;
 119
 120        case STATUSTYPE_IMA:
 121                DMEMIT_TARGET_NAME_VERSION(ti->type);
 122                DMEMIT(",device_name=%s,start=%llu;", lc->dev->name,
 123                       (unsigned long long)lc->start);
 124                break;
 125        }
 126}
 127
 128static int linear_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
 129{
 130        struct linear_c *lc = (struct linear_c *) ti->private;
 131        struct dm_dev *dev = lc->dev;
 132
 133        *bdev = dev->bdev;
 134
 135        /*
 136         * Only pass ioctls through if the device sizes match exactly.
 137         */
 138        if (lc->start ||
 139            ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
 140                return 1;
 141        return 0;
 142}
 143
 144#ifdef CONFIG_BLK_DEV_ZONED
 145static int linear_report_zones(struct dm_target *ti,
 146                struct dm_report_zones_args *args, unsigned int nr_zones)
 147{
 148        struct linear_c *lc = ti->private;
 149
 150        return dm_report_zones(lc->dev->bdev, lc->start,
 151                               linear_map_sector(ti, args->next_sector),
 152                               args, nr_zones);
 153}
 154#else
 155#define linear_report_zones NULL
 156#endif
 157
 158static int linear_iterate_devices(struct dm_target *ti,
 159                                  iterate_devices_callout_fn fn, void *data)
 160{
 161        struct linear_c *lc = ti->private;
 162
 163        return fn(ti, lc->dev, lc->start, ti->len, data);
 164}
 165
 166#if IS_ENABLED(CONFIG_DAX_DRIVER)
 167static long linear_dax_direct_access(struct dm_target *ti, pgoff_t pgoff,
 168                long nr_pages, void **kaddr, pfn_t *pfn)
 169{
 170        long ret;
 171        struct linear_c *lc = ti->private;
 172        struct block_device *bdev = lc->dev->bdev;
 173        struct dax_device *dax_dev = lc->dev->dax_dev;
 174        sector_t dev_sector, sector = pgoff * PAGE_SECTORS;
 175
 176        dev_sector = linear_map_sector(ti, sector);
 177        ret = bdev_dax_pgoff(bdev, dev_sector, nr_pages * PAGE_SIZE, &pgoff);
 178        if (ret)
 179                return ret;
 180        return dax_direct_access(dax_dev, pgoff, nr_pages, kaddr, pfn);
 181}
 182
 183static size_t linear_dax_copy_from_iter(struct dm_target *ti, pgoff_t pgoff,
 184                void *addr, size_t bytes, struct iov_iter *i)
 185{
 186        struct linear_c *lc = ti->private;
 187        struct block_device *bdev = lc->dev->bdev;
 188        struct dax_device *dax_dev = lc->dev->dax_dev;
 189        sector_t dev_sector, sector = pgoff * PAGE_SECTORS;
 190
 191        dev_sector = linear_map_sector(ti, sector);
 192        if (bdev_dax_pgoff(bdev, dev_sector, ALIGN(bytes, PAGE_SIZE), &pgoff))
 193                return 0;
 194        return dax_copy_from_iter(dax_dev, pgoff, addr, bytes, i);
 195}
 196
 197static size_t linear_dax_copy_to_iter(struct dm_target *ti, pgoff_t pgoff,
 198                void *addr, size_t bytes, struct iov_iter *i)
 199{
 200        struct linear_c *lc = ti->private;
 201        struct block_device *bdev = lc->dev->bdev;
 202        struct dax_device *dax_dev = lc->dev->dax_dev;
 203        sector_t dev_sector, sector = pgoff * PAGE_SECTORS;
 204
 205        dev_sector = linear_map_sector(ti, sector);
 206        if (bdev_dax_pgoff(bdev, dev_sector, ALIGN(bytes, PAGE_SIZE), &pgoff))
 207                return 0;
 208        return dax_copy_to_iter(dax_dev, pgoff, addr, bytes, i);
 209}
 210
 211static int linear_dax_zero_page_range(struct dm_target *ti, pgoff_t pgoff,
 212                                      size_t nr_pages)
 213{
 214        int ret;
 215        struct linear_c *lc = ti->private;
 216        struct block_device *bdev = lc->dev->bdev;
 217        struct dax_device *dax_dev = lc->dev->dax_dev;
 218        sector_t dev_sector, sector = pgoff * PAGE_SECTORS;
 219
 220        dev_sector = linear_map_sector(ti, sector);
 221        ret = bdev_dax_pgoff(bdev, dev_sector, nr_pages << PAGE_SHIFT, &pgoff);
 222        if (ret)
 223                return ret;
 224        return dax_zero_page_range(dax_dev, pgoff, nr_pages);
 225}
 226
 227#else
 228#define linear_dax_direct_access NULL
 229#define linear_dax_copy_from_iter NULL
 230#define linear_dax_copy_to_iter NULL
 231#define linear_dax_zero_page_range NULL
 232#endif
 233
 234static struct target_type linear_target = {
 235        .name   = "linear",
 236        .version = {1, 4, 0},
 237        .features = DM_TARGET_PASSES_INTEGRITY | DM_TARGET_NOWAIT |
 238                    DM_TARGET_ZONED_HM | DM_TARGET_PASSES_CRYPTO,
 239        .report_zones = linear_report_zones,
 240        .module = THIS_MODULE,
 241        .ctr    = linear_ctr,
 242        .dtr    = linear_dtr,
 243        .map    = linear_map,
 244        .status = linear_status,
 245        .prepare_ioctl = linear_prepare_ioctl,
 246        .iterate_devices = linear_iterate_devices,
 247        .direct_access = linear_dax_direct_access,
 248        .dax_copy_from_iter = linear_dax_copy_from_iter,
 249        .dax_copy_to_iter = linear_dax_copy_to_iter,
 250        .dax_zero_page_range = linear_dax_zero_page_range,
 251};
 252
 253int __init dm_linear_init(void)
 254{
 255        int r = dm_register_target(&linear_target);
 256
 257        if (r < 0)
 258                DMERR("register failed %d", r);
 259
 260        return r;
 261}
 262
 263void dm_linear_exit(void)
 264{
 265        dm_unregister_target(&linear_target);
 266}
 267