Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | ||
9 | #include <linux/module.h> | |
10 | #include <linux/init.h> | |
11 | #include <linux/blkdev.h> | |
12 | #include <linux/bio.h> | |
13 | #include <linux/slab.h> | |
14 | ||
72d94861 AK |
15 | #define DM_MSG_PREFIX "linear" |
16 | ||
1da177e4 LT |
17 | /* |
18 | * Linear: maps a linear range of a device. | |
19 | */ | |
20 | struct linear_c { | |
21 | struct dm_dev *dev; | |
22 | sector_t start; | |
23 | }; | |
24 | ||
25 | /* | |
26 | * Construct a linear mapping: <dev_path> <offset> | |
27 | */ | |
28 | static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |
29 | { | |
30 | struct linear_c *lc; | |
4ee218cd | 31 | unsigned long long tmp; |
1da177e4 LT |
32 | |
33 | if (argc != 2) { | |
72d94861 | 34 | ti->error = "Invalid argument count"; |
1da177e4 LT |
35 | return -EINVAL; |
36 | } | |
37 | ||
38 | lc = kmalloc(sizeof(*lc), GFP_KERNEL); | |
39 | if (lc == NULL) { | |
40 | ti->error = "dm-linear: Cannot allocate linear context"; | |
41 | return -ENOMEM; | |
42 | } | |
43 | ||
4ee218cd | 44 | if (sscanf(argv[1], "%llu", &tmp) != 1) { |
1da177e4 LT |
45 | ti->error = "dm-linear: Invalid device sector"; |
46 | goto bad; | |
47 | } | |
4ee218cd | 48 | lc->start = tmp; |
1da177e4 LT |
49 | |
50 | if (dm_get_device(ti, argv[0], lc->start, ti->len, | |
51 | dm_table_get_mode(ti->table), &lc->dev)) { | |
52 | ti->error = "dm-linear: Device lookup failed"; | |
53 | goto bad; | |
54 | } | |
55 | ||
56 | ti->private = lc; | |
57 | return 0; | |
58 | ||
59 | bad: | |
60 | kfree(lc); | |
61 | return -EINVAL; | |
62 | } | |
63 | ||
64 | static void linear_dtr(struct dm_target *ti) | |
65 | { | |
66 | struct linear_c *lc = (struct linear_c *) ti->private; | |
67 | ||
68 | dm_put_device(ti, lc->dev); | |
69 | kfree(lc); | |
70 | } | |
71 | ||
72 | static int linear_map(struct dm_target *ti, struct bio *bio, | |
73 | union map_info *map_context) | |
74 | { | |
75 | struct linear_c *lc = (struct linear_c *) ti->private; | |
76 | ||
77 | bio->bi_bdev = lc->dev->bdev; | |
78 | bio->bi_sector = lc->start + (bio->bi_sector - ti->begin); | |
79 | ||
d2a7ad29 | 80 | return DM_MAPIO_REMAPPED; |
1da177e4 LT |
81 | } |
82 | ||
83 | static int linear_status(struct dm_target *ti, status_type_t type, | |
84 | char *result, unsigned int maxlen) | |
85 | { | |
86 | struct linear_c *lc = (struct linear_c *) ti->private; | |
87 | ||
88 | switch (type) { | |
89 | case STATUSTYPE_INFO: | |
90 | result[0] = '\0'; | |
91 | break; | |
92 | ||
93 | case STATUSTYPE_TABLE: | |
4ee218cd AM |
94 | snprintf(result, maxlen, "%s %llu", lc->dev->name, |
95 | (unsigned long long)lc->start); | |
1da177e4 LT |
96 | break; |
97 | } | |
98 | return 0; | |
99 | } | |
100 | ||
ab17ffa4 MB |
101 | static int linear_ioctl(struct dm_target *ti, struct inode *inode, |
102 | struct file *filp, unsigned int cmd, | |
103 | unsigned long arg) | |
104 | { | |
105 | struct linear_c *lc = (struct linear_c *) ti->private; | |
106 | struct block_device *bdev = lc->dev->bdev; | |
e90dae1f MB |
107 | struct file fake_file = {}; |
108 | struct dentry fake_dentry = {}; | |
ab17ffa4 | 109 | |
e90dae1f | 110 | fake_file.f_mode = lc->dev->mode; |
c649bb9c | 111 | fake_file.f_path.dentry = &fake_dentry; |
e90dae1f MB |
112 | fake_dentry.d_inode = bdev->bd_inode; |
113 | ||
114 | return blkdev_driver_ioctl(bdev->bd_inode, &fake_file, bdev->bd_disk, cmd, arg); | |
ab17ffa4 MB |
115 | } |
116 | ||
1da177e4 LT |
117 | static struct target_type linear_target = { |
118 | .name = "linear", | |
ab17ffa4 | 119 | .version= {1, 0, 2}, |
1da177e4 LT |
120 | .module = THIS_MODULE, |
121 | .ctr = linear_ctr, | |
122 | .dtr = linear_dtr, | |
123 | .map = linear_map, | |
124 | .status = linear_status, | |
ab17ffa4 | 125 | .ioctl = linear_ioctl, |
1da177e4 LT |
126 | }; |
127 | ||
128 | int __init dm_linear_init(void) | |
129 | { | |
130 | int r = dm_register_target(&linear_target); | |
131 | ||
132 | if (r < 0) | |
72d94861 | 133 | DMERR("register failed %d", r); |
1da177e4 LT |
134 | |
135 | return r; | |
136 | } | |
137 | ||
138 | void dm_linear_exit(void) | |
139 | { | |
140 | int r = dm_unregister_target(&linear_target); | |
141 | ||
142 | if (r < 0) | |
72d94861 | 143 | DMERR("unregister failed %d", r); |
1da177e4 | 144 | } |