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_requests = 1;
  57        ti->num_discard_requests = 1;
  58        ti->private = lc;
  59        return 0;
  60
  61      bad:
  62        kfree(lc);
  63        return -EINVAL;
  64}
  65
  66static void linear_dtr(struct dm_target *ti)
  67{
  68        struct linear_c *lc = (struct linear_c *) ti->private;
  69
  70        dm_put_device(ti, lc->dev);
  71        kfree(lc);
  72}
  73
  74static sector_t linear_map_sector(struct dm_target *ti, sector_t bi_sector)
  75{
  76        struct linear_c *lc = ti->private;
  77
  78        return lc->start + dm_target_offset(ti, bi_sector);
  79}
  80
  81static void linear_map_bio(struct dm_target *ti, struct bio *bio)
  82{
  83        struct linear_c *lc = ti->private;
  84
  85        bio->bi_bdev = lc->dev->bdev;
  86        if (bio_sectors(bio))
  87                bio->bi_sector = linear_map_sector(ti, bio->bi_sector);
  88}
  89
  90static int linear_map(struct dm_target *ti, struct bio *bio,
  91                      union map_info *map_context)
  92{
  93        linear_map_bio(ti, bio);
  94
  95        return DM_MAPIO_REMAPPED;
  96}
  97
  98static int 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        return 0;
 114}
 115
 116static int linear_ioctl(struct dm_target *ti, unsigned int cmd,
 117                        unsigned long arg)
 118{
 119        struct linear_c *lc = (struct linear_c *) ti->private;
 120        struct dm_dev *dev = lc->dev;
 121        int r = 0;
 122
 123        /*
 124         * Only pass ioctls through if the device sizes match exactly.
 125         */
 126        if (lc->start ||
 127            ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
 128                r = scsi_verify_blk_ioctl(NULL, cmd);
 129
 130        return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg);
 131}
 132
 133static int linear_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
 134                        struct bio_vec *biovec, int max_size)
 135{
 136        struct linear_c *lc = ti->private;
 137        struct request_queue *q = bdev_get_queue(lc->dev->bdev);
 138
 139        if (!q->merge_bvec_fn)
 140                return max_size;
 141
 142        bvm->bi_bdev = lc->dev->bdev;
 143        bvm->bi_sector = linear_map_sector(ti, bvm->bi_sector);
 144
 145        return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
 146}
 147
 148static int linear_iterate_devices(struct dm_target *ti,
 149                                  iterate_devices_callout_fn fn, void *data)
 150{
 151        struct linear_c *lc = ti->private;
 152
 153        return fn(ti, lc->dev, lc->start, ti->len, data);
 154}
 155
 156static struct target_type linear_target = {
 157        .name   = "linear",
 158        .version = {1, 1, 0},
 159        .module = THIS_MODULE,
 160        .ctr    = linear_ctr,
 161        .dtr    = linear_dtr,
 162        .map    = linear_map,
 163        .status = linear_status,
 164        .ioctl  = linear_ioctl,
 165        .merge  = linear_merge,
 166        .iterate_devices = linear_iterate_devices,
 167};
 168
 169int __init dm_linear_init(void)
 170{
 171        int r = dm_register_target(&linear_target);
 172
 173        if (r < 0)
 174                DMERR("register failed %d", r);
 175
 176        return r;
 177}
 178
 179void dm_linear_exit(void)
 180{
 181        dm_unregister_target(&linear_target);
 182}
 183
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.