1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
#include "dm.h"
#include <linux/module.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/bio.h>
#include <linux/slab.h>
MODULE_AUTHOR("Christophe Saout <christophe@saout.de>");
MODULE_DESCRIPTION(DM_NAME " target for reverse block mapping");
MODULE_LICENSE("GPL");
struct reverse_c {
uint32_t chunk_shift;
sector_t chunk_mask;
sector_t chunk_last;
struct dm_dev *dev;
sector_t start;
};
/*
* Construct a reverse mapping.
* <chunk size (2^^n)> <dev_path> <offset>
*/
static int reverse_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
struct reverse_c *rc;
uint32_t chunk_size;
sector_t chunk_count;
char *end;
if (argc != 3) {
ti->error = "dm-reverse: Not enough arguments";
return -EINVAL;
}
chunk_size = simple_strtoul(argv[0], &end, 10);
if (*end) {
ti->error = "dm-reverse: Invalid chunk_size";
return -EINVAL;
}
/*
* chunk_size is a power of two
*/
if (!chunk_size || (chunk_size & (chunk_size - 1))) {
ti->error = "dm-reverse: Invalid chunk size";
return -EINVAL;
}
/*
* How do we handle a small last <-> first chunk?
* We simply don't... so
* length has to be a multiple of the chunk size
*/
chunk_count = ti->len;
if (sector_div(chunk_count, chunk_size) > 0) {
ti->error = "dm-reverse: Size must be a multiple of the chunk size";
return -EINVAL;
}
rc = kmalloc(sizeof(*rc), GFP_KERNEL);
if (rc == NULL) {
ti->error = "dm-reverse: Cannot allocate reverse context ";
return -ENOMEM;
}
if (sscanf(argv[2], SECTOR_FORMAT, &rc->start) != 1) {
ti->error = "dm-reverse: Invalid device sector";
goto bad;
}
if (dm_get_device(ti, argv[1], rc->start, ti->len,
dm_table_get_mode(ti->table), &rc->dev)) {
ti->error = "dm-reverse: Device lookup failed";
goto bad;
}
ti->split_io = chunk_size;
rc->chunk_last = chunk_count - 1;
rc->chunk_mask = ((sector_t) chunk_size) - 1;
for (rc->chunk_shift = 0; chunk_size; rc->chunk_shift++)
chunk_size >>= 1;
rc->chunk_shift--;
ti->private = rc;
return 0;
bad:
kfree(rc);
return -EINVAL;
}
static void reverse_dtr(struct dm_target *ti)
{
struct reverse_c *rc = (struct reverse_c *) ti->private;
dm_put_device(ti, rc->dev);
kfree(rc);
}
static int reverse_map(struct dm_target *ti, struct bio *bio)
{
struct reverse_c *rc = (struct reverse_c *) ti->private;
sector_t offset = bio->bi_sector - ti->begin;
uint32_t chunk = (uint32_t) (offset >> rc->chunk_shift);
chunk = rc->chunk_last - chunk;
bio->bi_bdev = rc->dev->bdev;
bio->bi_sector = rc->start + (chunk << rc->chunk_shift)
+ (offset & rc->chunk_mask);
return 1;
}
static int reverse_status(struct dm_target *ti,
status_type_t type, char *result, unsigned int maxlen)
{
struct reverse_c *rc = (struct reverse_c *) ti->private;
char b[BDEVNAME_SIZE];
switch (type) {
case STATUSTYPE_INFO:
result[0] = '\0';
break;
case STATUSTYPE_TABLE:
snprintf(result, maxlen, SECTOR_FORMAT " %s " SECTOR_FORMAT,
rc->chunk_mask + 1, bdevname(rc->dev->bdev, b), rc->start);
break;
}
return 0;
}
static struct target_type reverse_target = {
.name = "reverse",
.module = THIS_MODULE,
.ctr = reverse_ctr,
.dtr = reverse_dtr,
.map = reverse_map,
.status = reverse_status,
};
int __init dm_reverse_init(void)
{
int r;
r = dm_register_target(&reverse_target);
if (r < 0)
DMWARN("reverse target registration failed");
return r;
}
void dm_reverse_exit(void)
{
if (dm_unregister_target(&reverse_target))
DMWARN("reverse target unregistration failed");
return;
}
module_init(dm_reverse_init)
module_exit(dm_reverse_exit)
|