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/slab.h>
  13#include <linux/device-mapper.h>
  14
  15#define DM_MSG_PREFIX "linear"
  16
  17/*
  18 * Linear: maps a linear range of a device.
  19 */
  20struct linear_c {
  21        struct dm_dev *dev;
  22        sector_t start;
  23};
  24
  25/*
  26 * Construct a linear mapping: <dev_path> <offset>
  27 */
  28static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
  29{
  30        struct linear_c *lc;
  31        unsigned long long tmp;
  32        char dummy;
  33
  34        if (argc != 2) {
  35                ti->error = "Invalid argument count";
  36                return -EINVAL;
  37        }
  38
  39        lc = kmalloc(sizeof(*lc), GFP_KERNEL);
  40        if (lc == NULL) {
  41                ti->error = "dm-linear: Cannot allocate linear context";
  42                return -ENOMEM;
  43        }
  44
  45        if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1) {
  46                ti->error = "dm-linear: Invalid device sector";
  47                goto bad;
  48        }
  49        lc->start = tmp;
  50
  51        if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &lc->dev)) {
  52                ti->error = "dm-linear: Device lookup failed";
  53                goto bad;
  54        }
  55
  56        ti->num_flush_bios = 1;
  57        ti->num_discard_bios = 1;
  58        ti->num_write_same_bios = 1;
  59        ti->private = lc;
  60        return 0;
  61
  62      bad:
  63        kfree(lc);
  64        return -EINVAL;
  65}
  66
  67static void linear_dtr(struct dm_target *ti)
  68{
  69        struct linear_c *lc = (struct linear_c *) ti->private;
  70
  71        dm_put_device(ti, lc->dev);
  72        kfree(lc);
  73}
  74
  75static sector_t linear_map_sector(struct dm_target *ti, sector_t bi_sector)
  76{
  77        struct linear_c *lc = ti->private;
  78
  79        return lc->start + dm_target_offset(ti, bi_sector);
  80}
  81
  82static void linear_map_bio(struct dm_target *ti, struct bio *bio)
  83{
  84        struct linear_c *lc = ti->private;
  85
  86        bio->bi_bdev = lc->dev->bdev;
  87        if (bio_sectors(bio))
  88                bio->bi_sector = linear_map_sector(ti, bio->bi_sector);
  89}
  90
  91static int linear_map(struct dm_target *ti, struct bio *bio)
  92{
  93        linear_map_bio(ti, bio);
  94
  95        return DM_MAPIO_REMAPPED;
  96}
  97
  98static void linear_status(struct dm_target *ti, status_type_t type,
  99                          unsigned status_flags, char *result, unsigned maxlen)
 100{
 101        struct linear_c *lc = (struct linear_c *) ti->private;
 102
 103        switch (type) {
 104        case STATUSTYPE_INFO:
 105                result[0] = '\0';
 106                break;
 107
 108        case STATUSTYPE_TABLE:
 109                snprintf(result, maxlen, "%s %llu", lc->dev->name,
 110                                (unsigned long long)lc->start);
 111                break;
 112        }
 113}
 114
 115static int linear_ioctl(struct dm_target *ti, unsigned int cmd,
 116                        unsigned long arg)
 117{
 118        struct linear_c *lc = (struct linear_c *) ti->private;
 119        struct dm_dev *dev = lc->dev;
 120        int r = 0;
 121
 122        /*
 123         * Only pass ioctls through if the device sizes match exactly.
 124         */
 125        if (lc->start ||
 126            ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
 127                r = scsi_verify_blk_ioctl(NULL, cmd);
 128
 129        return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg);
 130}
 131
 132static int linear_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
 133                        struct bio_vec *biovec, int max_size)
 134{
 135        struct linear_c *lc = ti->private;
 136        struct request_queue *q = bdev_get_queue(lc->dev->bdev);
 137
 138        if (!q->merge_bvec_fn)
 139                return max_size;
 140
 141        bvm->bi_bdev = lc->dev->bdev;
 142        bvm->bi_sector = linear_map_sector(ti, bvm->bi_sector);
 143
 144        return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
 145}
 146
 147static int linear_iterate_devices(struct dm_target *ti,
 148                                  iterate_devices_callout_fn fn, void *data)
 149{
 150        struct linear_c *lc = ti->private;
 151
 152        return fn(ti, lc->dev, lc->start, ti->len, data);
 153}
 154
 155static struct target_type linear_target = {
 156        .name   = "linear",
 157        .version = {1, 2, 1},
 158        .module = THIS_MODULE,
 159        .ctr    = linear_ctr,
 160        .dtr    = linear_dtr,
 161        .map    = linear_map,
 162        .status = linear_status,
 163        .ioctl  = linear_ioctl,
 164        .merge  = linear_merge,
 165        .iterate_devices = linear_iterate_devices,
 166};
 167
 168int __init dm_linear_init(void)
 169{
 170        int r = dm_register_target(&linear_target);
 171
 172        if (r < 0)
 173                DMERR("register failed %d", r);
 174
 175        return r;
 176}
 177
 178void dm_linear_exit(void)
 179{
 180        dm_unregister_target(&linear_target);
 181}
 182