aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-25 23:51:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-25 23:51:44 -0400
commit44bbd7ac2658eb1118342493026ef141e259b739 (patch)
treea804d3503e48ee8b2bd0dd3c40235e482a75a512 /drivers/md
parent24c6d02fe8c34bc958aa4c464efc1cc10d43e29d (diff)
parent29915202006c2e7bafe81348eb498ff9a724ac61 (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/Kconfig6
-rw-r--r--drivers/md/Makefile1
-rw-r--r--drivers/md/dm-crypt.c19
-rw-r--r--drivers/md/dm-flakey.c212
-rw-r--r--drivers/md/dm-ioctl.c46
-rw-r--r--drivers/md/dm-log.c2
-rw-r--r--drivers/md/dm-mpath.c17
-rw-r--r--drivers/md/dm-snap.c2
-rw-r--r--drivers/md/dm-stripe.c23
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
330config 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
330endif # MD 336endif # 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
29obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o 29obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o
30obj-$(CONFIG_DM_CRYPT) += dm-crypt.o 30obj-$(CONFIG_DM_CRYPT) += dm-crypt.o
31obj-$(CONFIG_DM_DELAY) += dm-delay.o 31obj-$(CONFIG_DM_DELAY) += dm-delay.o
32obj-$(CONFIG_DM_FLAKEY) += dm-flakey.o
32obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o 33obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o
33obj-$(CONFIG_DM_MULTIPATH_QL) += dm-queue-length.o 34obj-$(CONFIG_DM_MULTIPATH_QL) += dm-queue-length.o
34obj-$(CONFIG_DM_MULTIPATH_ST) += dm-service-time.o 35obj-$(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
1325static int crypt_set_key(struct crypt_config *cc, char *key) 1325static 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
1345out:
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
1343static int crypt_wipe_key(struct crypt_config *cc) 1352static 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 */
22struct 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 */
33static 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
85bad:
86 kfree(fc);
87 return -EINVAL;
88}
89
90static 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
98static 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
105static 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
114static 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
130static 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
149static 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
156static 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
171static 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
178static 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
191static 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
201static void __exit dm_flakey_exit(void)
202{
203 dm_unregister_target(&flakey_target);
204}
205
206/* Module hooks */
207module_init(dm_flakey_init);
208module_exit(dm_flakey_exit);
209
210MODULE_DESCRIPTION(DM_NAME " flakey target");
211MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
212MODULE_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
1504static void free_params(struct dm_ioctl *param)
1505{
1506 vfree(param);
1507}
1508
1509static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) 1504static 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
1534bad:
1535 if (secure_data)
1536 memset(dmi, 0, tmp.data_size);
1537 vfree(dmi);
1538 return -EFAULT;
1530} 1539}
1531 1540
1532static int validate_params(uint cmd, struct dm_ioctl *param) 1541static 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)
1561static int ctl_ioctl(uint command, struct dm_ioctl __user *user) 1571static 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: 1641out:
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:
1065static int action_dev(struct multipath *m, struct dm_dev *dev, 1072static 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 *---------------------------------------------------------------*/
1670static struct target_type multipath_target = { 1677static 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
399static 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
399static struct target_type stripe_target = { 419static 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
412int __init dm_stripe_init(void) 433int __init dm_stripe_init(void)