File: dm-reverse.c

package info (click to toggle)
devmapper 2%3A1.02.08-1
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 4,276 kB
  • ctags: 2,921
  • sloc: ansic: 16,422; sh: 2,778; makefile: 406; perl: 16
file content (173 lines) | stat: -rw-r--r-- 3,735 bytes parent folder | download | duplicates (3)
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)