diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-25 23:51:44 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-25 23:51:44 -0400 |
commit | 44bbd7ac2658eb1118342493026ef141e259b739 (patch) | |
tree | a804d3503e48ee8b2bd0dd3c40235e482a75a512 /drivers/md | |
parent | 24c6d02fe8c34bc958aa4c464efc1cc10d43e29d (diff) | |
parent | 29915202006c2e7bafe81348eb498ff9a724ac61 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm
* git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm:
dm stripe: implement merge method
dm mpath: allow table load with no priority groups
dm mpath: fail message ioctl if specified path is not valid
dm ioctl: add flag to wipe buffers for secure data
dm ioctl: prepare for crypt key wiping
dm crypt: wipe keys string immediately after key is set
dm: add flakey target
dm: fix opening log and cow devices for read only tables
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/Kconfig | 6 | ||||
-rw-r--r-- | drivers/md/Makefile | 1 | ||||
-rw-r--r-- | drivers/md/dm-crypt.c | 19 | ||||
-rw-r--r-- | drivers/md/dm-flakey.c | 212 | ||||
-rw-r--r-- | drivers/md/dm-ioctl.c | 46 | ||||
-rw-r--r-- | drivers/md/dm-log.c | 2 | ||||
-rw-r--r-- | drivers/md/dm-mpath.c | 17 | ||||
-rw-r--r-- | drivers/md/dm-snap.c | 2 | ||||
-rw-r--r-- | drivers/md/dm-stripe.c | 23 |
9 files changed, 300 insertions, 28 deletions
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 98d9ec85e0eb..8420129fc5ee 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig | |||
@@ -327,4 +327,10 @@ config DM_UEVENT | |||
327 | ---help--- | 327 | ---help--- |
328 | Generate udev events for DM events. | 328 | Generate udev events for DM events. |
329 | 329 | ||
330 | config DM_FLAKEY | ||
331 | tristate "Flakey target (EXPERIMENTAL)" | ||
332 | depends on BLK_DEV_DM && EXPERIMENTAL | ||
333 | ---help--- | ||
334 | A target that intermittently fails I/O for debugging purposes. | ||
335 | |||
330 | endif # MD | 336 | endif # MD |
diff --git a/drivers/md/Makefile b/drivers/md/Makefile index d0138606c2e8..448838b1f92a 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile | |||
@@ -29,6 +29,7 @@ obj-$(CONFIG_BLK_DEV_MD) += md-mod.o | |||
29 | obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o | 29 | obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o |
30 | obj-$(CONFIG_DM_CRYPT) += dm-crypt.o | 30 | obj-$(CONFIG_DM_CRYPT) += dm-crypt.o |
31 | obj-$(CONFIG_DM_DELAY) += dm-delay.o | 31 | obj-$(CONFIG_DM_DELAY) += dm-delay.o |
32 | obj-$(CONFIG_DM_FLAKEY) += dm-flakey.o | ||
32 | obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o | 33 | obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o |
33 | obj-$(CONFIG_DM_MULTIPATH_QL) += dm-queue-length.o | 34 | obj-$(CONFIG_DM_MULTIPATH_QL) += dm-queue-length.o |
34 | obj-$(CONFIG_DM_MULTIPATH_ST) += dm-service-time.o | 35 | obj-$(CONFIG_DM_MULTIPATH_ST) += dm-service-time.o |
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 2c62c1169f78..c8827ffd85bb 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c | |||
@@ -1324,20 +1324,29 @@ static int crypt_setkey_allcpus(struct crypt_config *cc) | |||
1324 | 1324 | ||
1325 | static int crypt_set_key(struct crypt_config *cc, char *key) | 1325 | static int crypt_set_key(struct crypt_config *cc, char *key) |
1326 | { | 1326 | { |
1327 | int r = -EINVAL; | ||
1328 | int key_string_len = strlen(key); | ||
1329 | |||
1327 | /* The key size may not be changed. */ | 1330 | /* The key size may not be changed. */ |
1328 | if (cc->key_size != (strlen(key) >> 1)) | 1331 | if (cc->key_size != (key_string_len >> 1)) |
1329 | return -EINVAL; | 1332 | goto out; |
1330 | 1333 | ||
1331 | /* Hyphen (which gives a key_size of zero) means there is no key. */ | 1334 | /* Hyphen (which gives a key_size of zero) means there is no key. */ |
1332 | if (!cc->key_size && strcmp(key, "-")) | 1335 | if (!cc->key_size && strcmp(key, "-")) |
1333 | return -EINVAL; | 1336 | goto out; |
1334 | 1337 | ||
1335 | if (cc->key_size && crypt_decode_key(cc->key, key, cc->key_size) < 0) | 1338 | if (cc->key_size && crypt_decode_key(cc->key, key, cc->key_size) < 0) |
1336 | return -EINVAL; | 1339 | goto out; |
1337 | 1340 | ||
1338 | set_bit(DM_CRYPT_KEY_VALID, &cc->flags); | 1341 | set_bit(DM_CRYPT_KEY_VALID, &cc->flags); |
1339 | 1342 | ||
1340 | return crypt_setkey_allcpus(cc); | 1343 | r = crypt_setkey_allcpus(cc); |
1344 | |||
1345 | out: | ||
1346 | /* Hex key string not needed after here, so wipe it. */ | ||
1347 | memset(key, '0', key_string_len); | ||
1348 | |||
1349 | return r; | ||
1341 | } | 1350 | } |
1342 | 1351 | ||
1343 | static int crypt_wipe_key(struct crypt_config *cc) | 1352 | static int crypt_wipe_key(struct crypt_config *cc) |
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c new file mode 100644 index 000000000000..ea790623c30b --- /dev/null +++ b/drivers/md/dm-flakey.c | |||
@@ -0,0 +1,212 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2003 Sistina Software (UK) Limited. | ||
3 | * Copyright (C) 2004, 2010 Red Hat, Inc. All rights reserved. | ||
4 | * | ||
5 | * This file is released under the GPL. | ||
6 | */ | ||
7 | |||
8 | #include <linux/device-mapper.h> | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/blkdev.h> | ||
13 | #include <linux/bio.h> | ||
14 | #include <linux/slab.h> | ||
15 | |||
16 | #define DM_MSG_PREFIX "flakey" | ||
17 | |||
18 | /* | ||
19 | * Flakey: Used for testing only, simulates intermittent, | ||
20 | * catastrophic device failure. | ||
21 | */ | ||
22 | struct flakey_c { | ||
23 | struct dm_dev *dev; | ||
24 | unsigned long start_time; | ||
25 | sector_t start; | ||
26 | unsigned up_interval; | ||
27 | unsigned down_interval; | ||
28 | }; | ||
29 | |||
30 | /* | ||
31 | * Construct a flakey mapping: <dev_path> <offset> <up interval> <down interval> | ||
32 | */ | ||
33 | static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv) | ||
34 | { | ||
35 | struct flakey_c *fc; | ||
36 | unsigned long long tmp; | ||
37 | |||
38 | if (argc != 4) { | ||
39 | ti->error = "dm-flakey: Invalid argument count"; | ||
40 | return -EINVAL; | ||
41 | } | ||
42 | |||
43 | fc = kmalloc(sizeof(*fc), GFP_KERNEL); | ||
44 | if (!fc) { | ||
45 | ti->error = "dm-flakey: Cannot allocate linear context"; | ||
46 | return -ENOMEM; | ||
47 | } | ||
48 | fc->start_time = jiffies; | ||
49 | |||
50 | if (sscanf(argv[1], "%llu", &tmp) != 1) { | ||
51 | ti->error = "dm-flakey: Invalid device sector"; | ||
52 | goto bad; | ||
53 | } | ||
54 | fc->start = tmp; | ||
55 | |||
56 | if (sscanf(argv[2], "%u", &fc->up_interval) != 1) { | ||
57 | ti->error = "dm-flakey: Invalid up interval"; | ||
58 | goto bad; | ||
59 | } | ||
60 | |||
61 | if (sscanf(argv[3], "%u", &fc->down_interval) != 1) { | ||
62 | ti->error = "dm-flakey: Invalid down interval"; | ||
63 | goto bad; | ||
64 | } | ||
65 | |||
66 | if (!(fc->up_interval + fc->down_interval)) { | ||
67 | ti->error = "dm-flakey: Total (up + down) interval is zero"; | ||
68 | goto bad; | ||
69 | } | ||
70 | |||
71 | if (fc->up_interval + fc->down_interval < fc->up_interval) { | ||
72 | ti->error = "dm-flakey: Interval overflow"; | ||
73 | goto bad; | ||
74 | } | ||
75 | |||
76 | if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &fc->dev)) { | ||
77 | ti->error = "dm-flakey: Device lookup failed"; | ||
78 | goto bad; | ||
79 | } | ||
80 | |||
81 | ti->num_flush_requests = 1; | ||
82 | ti->private = fc; | ||
83 | return 0; | ||
84 | |||
85 | bad: | ||
86 | kfree(fc); | ||
87 | return -EINVAL; | ||
88 | } | ||
89 | |||
90 | static void flakey_dtr(struct dm_target *ti) | ||
91 | { | ||
92 | struct flakey_c *fc = ti->private; | ||
93 | |||
94 | dm_put_device(ti, fc->dev); | ||
95 | kfree(fc); | ||
96 | } | ||
97 | |||
98 | static sector_t flakey_map_sector(struct dm_target *ti, sector_t bi_sector) | ||
99 | { | ||
100 | struct flakey_c *fc = ti->private; | ||
101 | |||
102 | return fc->start + (bi_sector - ti->begin); | ||
103 | } | ||
104 | |||
105 | static void flakey_map_bio(struct dm_target *ti, struct bio *bio) | ||
106 | { | ||
107 | struct flakey_c *fc = ti->private; | ||
108 | |||
109 | bio->bi_bdev = fc->dev->bdev; | ||
110 | if (bio_sectors(bio)) | ||
111 | bio->bi_sector = flakey_map_sector(ti, bio->bi_sector); | ||
112 | } | ||
113 | |||
114 | static int flakey_map(struct dm_target *ti, struct bio *bio, | ||
115 | union map_info *map_context) | ||
116 | { | ||
117 | struct flakey_c *fc = ti->private; | ||
118 | unsigned elapsed; | ||
119 | |||
120 | /* Are we alive ? */ | ||
121 | elapsed = (jiffies - fc->start_time) / HZ; | ||
122 | if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) | ||
123 | return -EIO; | ||
124 | |||
125 | flakey_map_bio(ti, bio); | ||
126 | |||
127 | return DM_MAPIO_REMAPPED; | ||
128 | } | ||
129 | |||
130 | static int flakey_status(struct dm_target *ti, status_type_t type, | ||
131 | char *result, unsigned int maxlen) | ||
132 | { | ||
133 | struct flakey_c *fc = ti->private; | ||
134 | |||
135 | switch (type) { | ||
136 | case STATUSTYPE_INFO: | ||
137 | result[0] = '\0'; | ||
138 | break; | ||
139 | |||
140 | case STATUSTYPE_TABLE: | ||
141 | snprintf(result, maxlen, "%s %llu %u %u", fc->dev->name, | ||
142 | (unsigned long long)fc->start, fc->up_interval, | ||
143 | fc->down_interval); | ||
144 | break; | ||
145 | } | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg) | ||
150 | { | ||
151 | struct flakey_c *fc = ti->private; | ||
152 | |||
153 | return __blkdev_driver_ioctl(fc->dev->bdev, fc->dev->mode, cmd, arg); | ||
154 | } | ||
155 | |||
156 | static int flakey_merge(struct dm_target *ti, struct bvec_merge_data *bvm, | ||
157 | struct bio_vec *biovec, int max_size) | ||
158 | { | ||
159 | struct flakey_c *fc = ti->private; | ||
160 | struct request_queue *q = bdev_get_queue(fc->dev->bdev); | ||
161 | |||
162 | if (!q->merge_bvec_fn) | ||
163 | return max_size; | ||
164 | |||
165 | bvm->bi_bdev = fc->dev->bdev; | ||
166 | bvm->bi_sector = flakey_map_sector(ti, bvm->bi_sector); | ||
167 | |||
168 | return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); | ||
169 | } | ||
170 | |||
171 | static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) | ||
172 | { | ||
173 | struct flakey_c *fc = ti->private; | ||
174 | |||
175 | return fn(ti, fc->dev, fc->start, ti->len, data); | ||
176 | } | ||
177 | |||
178 | static struct target_type flakey_target = { | ||
179 | .name = "flakey", | ||
180 | .version = {1, 1, 0}, | ||
181 | .module = THIS_MODULE, | ||
182 | .ctr = flakey_ctr, | ||
183 | .dtr = flakey_dtr, | ||
184 | .map = flakey_map, | ||
185 | .status = flakey_status, | ||
186 | .ioctl = flakey_ioctl, | ||
187 | .merge = flakey_merge, | ||
188 | .iterate_devices = flakey_iterate_devices, | ||
189 | }; | ||
190 | |||
191 | static int __init dm_flakey_init(void) | ||
192 | { | ||
193 | int r = dm_register_target(&flakey_target); | ||
194 | |||
195 | if (r < 0) | ||
196 | DMERR("register failed %d", r); | ||
197 | |||
198 | return r; | ||
199 | } | ||
200 | |||
201 | static void __exit dm_flakey_exit(void) | ||
202 | { | ||
203 | dm_unregister_target(&flakey_target); | ||
204 | } | ||
205 | |||
206 | /* Module hooks */ | ||
207 | module_init(dm_flakey_init); | ||
208 | module_exit(dm_flakey_exit); | ||
209 | |||
210 | MODULE_DESCRIPTION(DM_NAME " flakey target"); | ||
211 | MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>"); | ||
212 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 6d12775a1061..4cacdad2270a 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c | |||
@@ -1501,14 +1501,10 @@ static int check_version(unsigned int cmd, struct dm_ioctl __user *user) | |||
1501 | return r; | 1501 | return r; |
1502 | } | 1502 | } |
1503 | 1503 | ||
1504 | static void free_params(struct dm_ioctl *param) | ||
1505 | { | ||
1506 | vfree(param); | ||
1507 | } | ||
1508 | |||
1509 | static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) | 1504 | static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) |
1510 | { | 1505 | { |
1511 | struct dm_ioctl tmp, *dmi; | 1506 | struct dm_ioctl tmp, *dmi; |
1507 | int secure_data; | ||
1512 | 1508 | ||
1513 | if (copy_from_user(&tmp, user, sizeof(tmp) - sizeof(tmp.data))) | 1509 | if (copy_from_user(&tmp, user, sizeof(tmp) - sizeof(tmp.data))) |
1514 | return -EFAULT; | 1510 | return -EFAULT; |
@@ -1516,17 +1512,30 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) | |||
1516 | if (tmp.data_size < (sizeof(tmp) - sizeof(tmp.data))) | 1512 | if (tmp.data_size < (sizeof(tmp) - sizeof(tmp.data))) |
1517 | return -EINVAL; | 1513 | return -EINVAL; |
1518 | 1514 | ||
1515 | secure_data = tmp.flags & DM_SECURE_DATA_FLAG; | ||
1516 | |||
1519 | dmi = vmalloc(tmp.data_size); | 1517 | dmi = vmalloc(tmp.data_size); |
1520 | if (!dmi) | 1518 | if (!dmi) { |
1519 | if (secure_data && clear_user(user, tmp.data_size)) | ||
1520 | return -EFAULT; | ||
1521 | return -ENOMEM; | 1521 | return -ENOMEM; |
1522 | |||
1523 | if (copy_from_user(dmi, user, tmp.data_size)) { | ||
1524 | vfree(dmi); | ||
1525 | return -EFAULT; | ||
1526 | } | 1522 | } |
1527 | 1523 | ||
1524 | if (copy_from_user(dmi, user, tmp.data_size)) | ||
1525 | goto bad; | ||
1526 | |||
1527 | /* Wipe the user buffer so we do not return it to userspace */ | ||
1528 | if (secure_data && clear_user(user, tmp.data_size)) | ||
1529 | goto bad; | ||
1530 | |||
1528 | *param = dmi; | 1531 | *param = dmi; |
1529 | return 0; | 1532 | return 0; |
1533 | |||
1534 | bad: | ||
1535 | if (secure_data) | ||
1536 | memset(dmi, 0, tmp.data_size); | ||
1537 | vfree(dmi); | ||
1538 | return -EFAULT; | ||
1530 | } | 1539 | } |
1531 | 1540 | ||
1532 | static int validate_params(uint cmd, struct dm_ioctl *param) | 1541 | static int validate_params(uint cmd, struct dm_ioctl *param) |
@@ -1534,6 +1543,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param) | |||
1534 | /* Always clear this flag */ | 1543 | /* Always clear this flag */ |
1535 | param->flags &= ~DM_BUFFER_FULL_FLAG; | 1544 | param->flags &= ~DM_BUFFER_FULL_FLAG; |
1536 | param->flags &= ~DM_UEVENT_GENERATED_FLAG; | 1545 | param->flags &= ~DM_UEVENT_GENERATED_FLAG; |
1546 | param->flags &= ~DM_SECURE_DATA_FLAG; | ||
1537 | 1547 | ||
1538 | /* Ignores parameters */ | 1548 | /* Ignores parameters */ |
1539 | if (cmd == DM_REMOVE_ALL_CMD || | 1549 | if (cmd == DM_REMOVE_ALL_CMD || |
@@ -1561,10 +1571,11 @@ static int validate_params(uint cmd, struct dm_ioctl *param) | |||
1561 | static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | 1571 | static int ctl_ioctl(uint command, struct dm_ioctl __user *user) |
1562 | { | 1572 | { |
1563 | int r = 0; | 1573 | int r = 0; |
1574 | int wipe_buffer; | ||
1564 | unsigned int cmd; | 1575 | unsigned int cmd; |
1565 | struct dm_ioctl *uninitialized_var(param); | 1576 | struct dm_ioctl *uninitialized_var(param); |
1566 | ioctl_fn fn = NULL; | 1577 | ioctl_fn fn = NULL; |
1567 | size_t param_size; | 1578 | size_t input_param_size; |
1568 | 1579 | ||
1569 | /* only root can play with this */ | 1580 | /* only root can play with this */ |
1570 | if (!capable(CAP_SYS_ADMIN)) | 1581 | if (!capable(CAP_SYS_ADMIN)) |
@@ -1611,13 +1622,15 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | |||
1611 | if (r) | 1622 | if (r) |
1612 | return r; | 1623 | return r; |
1613 | 1624 | ||
1625 | input_param_size = param->data_size; | ||
1626 | wipe_buffer = param->flags & DM_SECURE_DATA_FLAG; | ||
1627 | |||
1614 | r = validate_params(cmd, param); | 1628 | r = validate_params(cmd, param); |
1615 | if (r) | 1629 | if (r) |
1616 | goto out; | 1630 | goto out; |
1617 | 1631 | ||
1618 | param_size = param->data_size; | ||
1619 | param->data_size = sizeof(*param); | 1632 | param->data_size = sizeof(*param); |
1620 | r = fn(param, param_size); | 1633 | r = fn(param, input_param_size); |
1621 | 1634 | ||
1622 | /* | 1635 | /* |
1623 | * Copy the results back to userland. | 1636 | * Copy the results back to userland. |
@@ -1625,8 +1638,11 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | |||
1625 | if (!r && copy_to_user(user, param, param->data_size)) | 1638 | if (!r && copy_to_user(user, param, param->data_size)) |
1626 | r = -EFAULT; | 1639 | r = -EFAULT; |
1627 | 1640 | ||
1628 | out: | 1641 | out: |
1629 | free_params(param); | 1642 | if (wipe_buffer) |
1643 | memset(param, 0, input_param_size); | ||
1644 | |||
1645 | vfree(param); | ||
1630 | return r; | 1646 | return r; |
1631 | } | 1647 | } |
1632 | 1648 | ||
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index 57968eb382c1..a1f321889676 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c | |||
@@ -543,7 +543,7 @@ static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti, | |||
543 | return -EINVAL; | 543 | return -EINVAL; |
544 | } | 544 | } |
545 | 545 | ||
546 | r = dm_get_device(ti, argv[0], FMODE_READ | FMODE_WRITE, &dev); | 546 | r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &dev); |
547 | if (r) | 547 | if (r) |
548 | return r; | 548 | return r; |
549 | 549 | ||
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 4b0b63c290a6..a550a057d991 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
@@ -844,8 +844,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, | |||
844 | { | 844 | { |
845 | /* target parameters */ | 845 | /* target parameters */ |
846 | static struct param _params[] = { | 846 | static struct param _params[] = { |
847 | {1, 1024, "invalid number of priority groups"}, | 847 | {0, 1024, "invalid number of priority groups"}, |
848 | {1, 1024, "invalid initial priority group number"}, | 848 | {0, 1024, "invalid initial priority group number"}, |
849 | }; | 849 | }; |
850 | 850 | ||
851 | int r; | 851 | int r; |
@@ -879,6 +879,13 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, | |||
879 | if (r) | 879 | if (r) |
880 | goto bad; | 880 | goto bad; |
881 | 881 | ||
882 | if ((!m->nr_priority_groups && next_pg_num) || | ||
883 | (m->nr_priority_groups && !next_pg_num)) { | ||
884 | ti->error = "invalid initial priority group"; | ||
885 | r = -EINVAL; | ||
886 | goto bad; | ||
887 | } | ||
888 | |||
882 | /* parse the priority groups */ | 889 | /* parse the priority groups */ |
883 | while (as.argc) { | 890 | while (as.argc) { |
884 | struct priority_group *pg; | 891 | struct priority_group *pg; |
@@ -1065,7 +1072,7 @@ out: | |||
1065 | static int action_dev(struct multipath *m, struct dm_dev *dev, | 1072 | static int action_dev(struct multipath *m, struct dm_dev *dev, |
1066 | action_fn action) | 1073 | action_fn action) |
1067 | { | 1074 | { |
1068 | int r = 0; | 1075 | int r = -EINVAL; |
1069 | struct pgpath *pgpath; | 1076 | struct pgpath *pgpath; |
1070 | struct priority_group *pg; | 1077 | struct priority_group *pg; |
1071 | 1078 | ||
@@ -1415,7 +1422,7 @@ static int multipath_status(struct dm_target *ti, status_type_t type, | |||
1415 | else if (m->current_pg) | 1422 | else if (m->current_pg) |
1416 | pg_num = m->current_pg->pg_num; | 1423 | pg_num = m->current_pg->pg_num; |
1417 | else | 1424 | else |
1418 | pg_num = 1; | 1425 | pg_num = (m->nr_priority_groups ? 1 : 0); |
1419 | 1426 | ||
1420 | DMEMIT("%u ", pg_num); | 1427 | DMEMIT("%u ", pg_num); |
1421 | 1428 | ||
@@ -1669,7 +1676,7 @@ out: | |||
1669 | *---------------------------------------------------------------*/ | 1676 | *---------------------------------------------------------------*/ |
1670 | static struct target_type multipath_target = { | 1677 | static struct target_type multipath_target = { |
1671 | .name = "multipath", | 1678 | .name = "multipath", |
1672 | .version = {1, 2, 0}, | 1679 | .version = {1, 3, 0}, |
1673 | .module = THIS_MODULE, | 1680 | .module = THIS_MODULE, |
1674 | .ctr = multipath_ctr, | 1681 | .ctr = multipath_ctr, |
1675 | .dtr = multipath_dtr, | 1682 | .dtr = multipath_dtr, |
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index fdde53cd12b7..a2d330942cb2 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -1080,7 +1080,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1080 | argv++; | 1080 | argv++; |
1081 | argc--; | 1081 | argc--; |
1082 | 1082 | ||
1083 | r = dm_get_device(ti, cow_path, FMODE_READ | FMODE_WRITE, &s->cow); | 1083 | r = dm_get_device(ti, cow_path, dm_table_get_mode(ti->table), &s->cow); |
1084 | if (r) { | 1084 | if (r) { |
1085 | ti->error = "Cannot get COW device"; | 1085 | ti->error = "Cannot get COW device"; |
1086 | goto bad_cow; | 1086 | goto bad_cow; |
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index dddfa14f2982..3d80cf0c152d 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c | |||
@@ -396,9 +396,29 @@ static void stripe_io_hints(struct dm_target *ti, | |||
396 | blk_limits_io_opt(limits, chunk_size * sc->stripes); | 396 | blk_limits_io_opt(limits, chunk_size * sc->stripes); |
397 | } | 397 | } |
398 | 398 | ||
399 | static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm, | ||
400 | struct bio_vec *biovec, int max_size) | ||
401 | { | ||
402 | struct stripe_c *sc = ti->private; | ||
403 | sector_t bvm_sector = bvm->bi_sector; | ||
404 | uint32_t stripe; | ||
405 | struct request_queue *q; | ||
406 | |||
407 | stripe_map_sector(sc, bvm_sector, &stripe, &bvm_sector); | ||
408 | |||
409 | q = bdev_get_queue(sc->stripe[stripe].dev->bdev); | ||
410 | if (!q->merge_bvec_fn) | ||
411 | return max_size; | ||
412 | |||
413 | bvm->bi_bdev = sc->stripe[stripe].dev->bdev; | ||
414 | bvm->bi_sector = sc->stripe[stripe].physical_start + bvm_sector; | ||
415 | |||
416 | return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); | ||
417 | } | ||
418 | |||
399 | static struct target_type stripe_target = { | 419 | static struct target_type stripe_target = { |
400 | .name = "striped", | 420 | .name = "striped", |
401 | .version = {1, 3, 1}, | 421 | .version = {1, 4, 0}, |
402 | .module = THIS_MODULE, | 422 | .module = THIS_MODULE, |
403 | .ctr = stripe_ctr, | 423 | .ctr = stripe_ctr, |
404 | .dtr = stripe_dtr, | 424 | .dtr = stripe_dtr, |
@@ -407,6 +427,7 @@ static struct target_type stripe_target = { | |||
407 | .status = stripe_status, | 427 | .status = stripe_status, |
408 | .iterate_devices = stripe_iterate_devices, | 428 | .iterate_devices = stripe_iterate_devices, |
409 | .io_hints = stripe_io_hints, | 429 | .io_hints = stripe_io_hints, |
430 | .merge = stripe_merge, | ||
410 | }; | 431 | }; |
411 | 432 | ||
412 | int __init dm_stripe_init(void) | 433 | int __init dm_stripe_init(void) |