diff options
author | NeilBrown <neilb@suse.de> | 2012-08-01 06:40:02 -0400 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2012-08-01 06:40:02 -0400 |
commit | bb181e2e48f8c85db08c9cb015cbba9618dbf05c (patch) | |
tree | 191bc24dd97bcb174535cc217af082f16da3b43d /drivers/md | |
parent | d57368afe63b3b7b45ce6c2b8c5276417935be2f (diff) | |
parent | c039c332f23e794deb6d6f37b9f07ff3b27fb2cf (diff) |
Merge commit 'c039c332f23e794deb6d6f37b9f07ff3b27fb2cf' into md
Pull in pre-requisites for adding raid10 support to dm-raid.
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/Kconfig | 9 | ||||
-rw-r--r-- | drivers/md/dm-crypt.c | 5 | ||||
-rw-r--r-- | drivers/md/dm-exception-store.c | 13 | ||||
-rw-r--r-- | drivers/md/dm-mpath.c | 47 | ||||
-rw-r--r-- | drivers/md/dm-raid.c | 54 | ||||
-rw-r--r-- | drivers/md/dm-raid1.c | 9 | ||||
-rw-r--r-- | drivers/md/dm-region-hash.c | 5 | ||||
-rw-r--r-- | drivers/md/dm-snap.c | 28 | ||||
-rw-r--r-- | drivers/md/dm-stripe.c | 83 | ||||
-rw-r--r-- | drivers/md/dm-thin-metadata.c | 31 | ||||
-rw-r--r-- | drivers/md/dm-thin-metadata.h | 2 | ||||
-rw-r--r-- | drivers/md/dm-thin.c | 105 | ||||
-rw-r--r-- | drivers/md/dm.c | 40 | ||||
-rw-r--r-- | drivers/md/persistent-data/Makefile | 1 | ||||
-rw-r--r-- | drivers/md/persistent-data/dm-space-map-checker.c | 446 | ||||
-rw-r--r-- | drivers/md/persistent-data/dm-space-map-checker.h | 26 | ||||
-rw-r--r-- | drivers/md/persistent-data/dm-space-map-disk.c | 34 | ||||
-rw-r--r-- | drivers/md/persistent-data/dm-transaction-manager.c | 29 |
18 files changed, 280 insertions, 687 deletions
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 10f122a3a856..1eee45b69b71 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig | |||
@@ -260,15 +260,6 @@ config DM_DEBUG_BLOCK_STACK_TRACING | |||
260 | 260 | ||
261 | If unsure, say N. | 261 | If unsure, say N. |
262 | 262 | ||
263 | config DM_DEBUG_SPACE_MAPS | ||
264 | boolean "Extra validation for thin provisioning space maps" | ||
265 | depends on DM_THIN_PROVISIONING | ||
266 | ---help--- | ||
267 | Enable this for messages that may help debug problems with the | ||
268 | space maps used by thin provisioning. | ||
269 | |||
270 | If unsure, say N. | ||
271 | |||
272 | config DM_MIRROR | 263 | config DM_MIRROR |
273 | tristate "Mirror target" | 264 | tristate "Mirror target" |
274 | depends on BLK_DEV_DM | 265 | depends on BLK_DEV_DM |
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 3f06df59fd82..e2b32401ecc7 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c | |||
@@ -1241,7 +1241,6 @@ static void kcryptd_queue_crypt(struct dm_crypt_io *io) | |||
1241 | static int crypt_decode_key(u8 *key, char *hex, unsigned int size) | 1241 | static int crypt_decode_key(u8 *key, char *hex, unsigned int size) |
1242 | { | 1242 | { |
1243 | char buffer[3]; | 1243 | char buffer[3]; |
1244 | char *endp; | ||
1245 | unsigned int i; | 1244 | unsigned int i; |
1246 | 1245 | ||
1247 | buffer[2] = '\0'; | 1246 | buffer[2] = '\0'; |
@@ -1250,9 +1249,7 @@ static int crypt_decode_key(u8 *key, char *hex, unsigned int size) | |||
1250 | buffer[0] = *hex++; | 1249 | buffer[0] = *hex++; |
1251 | buffer[1] = *hex++; | 1250 | buffer[1] = *hex++; |
1252 | 1251 | ||
1253 | key[i] = (u8)simple_strtoul(buffer, &endp, 16); | 1252 | if (kstrtou8(buffer, 16, &key[i])) |
1254 | |||
1255 | if (endp != &buffer[2]) | ||
1256 | return -EINVAL; | 1253 | return -EINVAL; |
1257 | } | 1254 | } |
1258 | 1255 | ||
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index aa70f7d43a1a..ebaa4f803eec 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c | |||
@@ -142,24 +142,19 @@ EXPORT_SYMBOL(dm_exception_store_type_unregister); | |||
142 | static int set_chunk_size(struct dm_exception_store *store, | 142 | static int set_chunk_size(struct dm_exception_store *store, |
143 | const char *chunk_size_arg, char **error) | 143 | const char *chunk_size_arg, char **error) |
144 | { | 144 | { |
145 | unsigned long chunk_size_ulong; | 145 | unsigned chunk_size; |
146 | char *value; | ||
147 | 146 | ||
148 | chunk_size_ulong = simple_strtoul(chunk_size_arg, &value, 10); | 147 | if (kstrtouint(chunk_size_arg, 10, &chunk_size)) { |
149 | if (*chunk_size_arg == '\0' || *value != '\0' || | ||
150 | chunk_size_ulong > UINT_MAX) { | ||
151 | *error = "Invalid chunk size"; | 148 | *error = "Invalid chunk size"; |
152 | return -EINVAL; | 149 | return -EINVAL; |
153 | } | 150 | } |
154 | 151 | ||
155 | if (!chunk_size_ulong) { | 152 | if (!chunk_size) { |
156 | store->chunk_size = store->chunk_mask = store->chunk_shift = 0; | 153 | store->chunk_size = store->chunk_mask = store->chunk_shift = 0; |
157 | return 0; | 154 | return 0; |
158 | } | 155 | } |
159 | 156 | ||
160 | return dm_exception_store_set_chunk_size(store, | 157 | return dm_exception_store_set_chunk_size(store, chunk_size, error); |
161 | (unsigned) chunk_size_ulong, | ||
162 | error); | ||
163 | } | 158 | } |
164 | 159 | ||
165 | int dm_exception_store_set_chunk_size(struct dm_exception_store *store, | 160 | int dm_exception_store_set_chunk_size(struct dm_exception_store *store, |
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 638dae048b4f..8a3b2d53f81b 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
@@ -85,6 +85,7 @@ struct multipath { | |||
85 | unsigned queue_io:1; /* Must we queue all I/O? */ | 85 | unsigned queue_io:1; /* Must we queue all I/O? */ |
86 | unsigned queue_if_no_path:1; /* Queue I/O if last path fails? */ | 86 | unsigned queue_if_no_path:1; /* Queue I/O if last path fails? */ |
87 | unsigned saved_queue_if_no_path:1; /* Saved state during suspension */ | 87 | unsigned saved_queue_if_no_path:1; /* Saved state during suspension */ |
88 | unsigned retain_attached_hw_handler:1; /* If there's already a hw_handler present, don't change it. */ | ||
88 | 89 | ||
89 | unsigned pg_init_retries; /* Number of times to retry pg_init */ | 90 | unsigned pg_init_retries; /* Number of times to retry pg_init */ |
90 | unsigned pg_init_count; /* Number of times pg_init called */ | 91 | unsigned pg_init_count; /* Number of times pg_init called */ |
@@ -568,6 +569,8 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps | |||
568 | int r; | 569 | int r; |
569 | struct pgpath *p; | 570 | struct pgpath *p; |
570 | struct multipath *m = ti->private; | 571 | struct multipath *m = ti->private; |
572 | struct request_queue *q = NULL; | ||
573 | const char *attached_handler_name; | ||
571 | 574 | ||
572 | /* we need at least a path arg */ | 575 | /* we need at least a path arg */ |
573 | if (as->argc < 1) { | 576 | if (as->argc < 1) { |
@@ -586,13 +589,37 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps | |||
586 | goto bad; | 589 | goto bad; |
587 | } | 590 | } |
588 | 591 | ||
589 | if (m->hw_handler_name) { | 592 | if (m->retain_attached_hw_handler || m->hw_handler_name) |
590 | struct request_queue *q = bdev_get_queue(p->path.dev->bdev); | 593 | q = bdev_get_queue(p->path.dev->bdev); |
594 | |||
595 | if (m->retain_attached_hw_handler) { | ||
596 | attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL); | ||
597 | if (attached_handler_name) { | ||
598 | /* | ||
599 | * Reset hw_handler_name to match the attached handler | ||
600 | * and clear any hw_handler_params associated with the | ||
601 | * ignored handler. | ||
602 | * | ||
603 | * NB. This modifies the table line to show the actual | ||
604 | * handler instead of the original table passed in. | ||
605 | */ | ||
606 | kfree(m->hw_handler_name); | ||
607 | m->hw_handler_name = attached_handler_name; | ||
608 | |||
609 | kfree(m->hw_handler_params); | ||
610 | m->hw_handler_params = NULL; | ||
611 | } | ||
612 | } | ||
591 | 613 | ||
614 | if (m->hw_handler_name) { | ||
615 | /* | ||
616 | * Increments scsi_dh reference, even when using an | ||
617 | * already-attached handler. | ||
618 | */ | ||
592 | r = scsi_dh_attach(q, m->hw_handler_name); | 619 | r = scsi_dh_attach(q, m->hw_handler_name); |
593 | if (r == -EBUSY) { | 620 | if (r == -EBUSY) { |
594 | /* | 621 | /* |
595 | * Already attached to different hw_handler, | 622 | * Already attached to different hw_handler: |
596 | * try to reattach with correct one. | 623 | * try to reattach with correct one. |
597 | */ | 624 | */ |
598 | scsi_dh_detach(q); | 625 | scsi_dh_detach(q); |
@@ -760,7 +787,7 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) | |||
760 | const char *arg_name; | 787 | const char *arg_name; |
761 | 788 | ||
762 | static struct dm_arg _args[] = { | 789 | static struct dm_arg _args[] = { |
763 | {0, 5, "invalid number of feature args"}, | 790 | {0, 6, "invalid number of feature args"}, |
764 | {1, 50, "pg_init_retries must be between 1 and 50"}, | 791 | {1, 50, "pg_init_retries must be between 1 and 50"}, |
765 | {0, 60000, "pg_init_delay_msecs must be between 0 and 60000"}, | 792 | {0, 60000, "pg_init_delay_msecs must be between 0 and 60000"}, |
766 | }; | 793 | }; |
@@ -781,6 +808,11 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) | |||
781 | continue; | 808 | continue; |
782 | } | 809 | } |
783 | 810 | ||
811 | if (!strcasecmp(arg_name, "retain_attached_hw_handler")) { | ||
812 | m->retain_attached_hw_handler = 1; | ||
813 | continue; | ||
814 | } | ||
815 | |||
784 | if (!strcasecmp(arg_name, "pg_init_retries") && | 816 | if (!strcasecmp(arg_name, "pg_init_retries") && |
785 | (argc >= 1)) { | 817 | (argc >= 1)) { |
786 | r = dm_read_arg(_args + 1, as, &m->pg_init_retries, &ti->error); | 818 | r = dm_read_arg(_args + 1, as, &m->pg_init_retries, &ti->error); |
@@ -1364,13 +1396,16 @@ static int multipath_status(struct dm_target *ti, status_type_t type, | |||
1364 | else { | 1396 | else { |
1365 | DMEMIT("%u ", m->queue_if_no_path + | 1397 | DMEMIT("%u ", m->queue_if_no_path + |
1366 | (m->pg_init_retries > 0) * 2 + | 1398 | (m->pg_init_retries > 0) * 2 + |
1367 | (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2); | 1399 | (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2 + |
1400 | m->retain_attached_hw_handler); | ||
1368 | if (m->queue_if_no_path) | 1401 | if (m->queue_if_no_path) |
1369 | DMEMIT("queue_if_no_path "); | 1402 | DMEMIT("queue_if_no_path "); |
1370 | if (m->pg_init_retries) | 1403 | if (m->pg_init_retries) |
1371 | DMEMIT("pg_init_retries %u ", m->pg_init_retries); | 1404 | DMEMIT("pg_init_retries %u ", m->pg_init_retries); |
1372 | if (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) | 1405 | if (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) |
1373 | DMEMIT("pg_init_delay_msecs %u ", m->pg_init_delay_msecs); | 1406 | DMEMIT("pg_init_delay_msecs %u ", m->pg_init_delay_msecs); |
1407 | if (m->retain_attached_hw_handler) | ||
1408 | DMEMIT("retain_attached_hw_handler "); | ||
1374 | } | 1409 | } |
1375 | 1410 | ||
1376 | if (!m->hw_handler_name || type == STATUSTYPE_INFO) | 1411 | if (!m->hw_handler_name || type == STATUSTYPE_INFO) |
@@ -1656,7 +1691,7 @@ out: | |||
1656 | *---------------------------------------------------------------*/ | 1691 | *---------------------------------------------------------------*/ |
1657 | static struct target_type multipath_target = { | 1692 | static struct target_type multipath_target = { |
1658 | .name = "multipath", | 1693 | .name = "multipath", |
1659 | .version = {1, 4, 0}, | 1694 | .version = {1, 5, 0}, |
1660 | .module = THIS_MODULE, | 1695 | .module = THIS_MODULE, |
1661 | .ctr = multipath_ctr, | 1696 | .ctr = multipath_ctr, |
1662 | .dtr = multipath_dtr, | 1697 | .dtr = multipath_dtr, |
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 017c34d78d61..f4275a8e860c 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c | |||
@@ -101,20 +101,12 @@ static struct raid_set *context_alloc(struct dm_target *ti, struct raid_type *ra | |||
101 | { | 101 | { |
102 | unsigned i; | 102 | unsigned i; |
103 | struct raid_set *rs; | 103 | struct raid_set *rs; |
104 | sector_t sectors_per_dev; | ||
105 | 104 | ||
106 | if (raid_devs <= raid_type->parity_devs) { | 105 | if (raid_devs <= raid_type->parity_devs) { |
107 | ti->error = "Insufficient number of devices"; | 106 | ti->error = "Insufficient number of devices"; |
108 | return ERR_PTR(-EINVAL); | 107 | return ERR_PTR(-EINVAL); |
109 | } | 108 | } |
110 | 109 | ||
111 | sectors_per_dev = ti->len; | ||
112 | if ((raid_type->level > 1) && | ||
113 | sector_div(sectors_per_dev, (raid_devs - raid_type->parity_devs))) { | ||
114 | ti->error = "Target length not divisible by number of data devices"; | ||
115 | return ERR_PTR(-EINVAL); | ||
116 | } | ||
117 | |||
118 | rs = kzalloc(sizeof(*rs) + raid_devs * sizeof(rs->dev[0]), GFP_KERNEL); | 110 | rs = kzalloc(sizeof(*rs) + raid_devs * sizeof(rs->dev[0]), GFP_KERNEL); |
119 | if (!rs) { | 111 | if (!rs) { |
120 | ti->error = "Cannot allocate raid context"; | 112 | ti->error = "Cannot allocate raid context"; |
@@ -128,7 +120,6 @@ static struct raid_set *context_alloc(struct dm_target *ti, struct raid_type *ra | |||
128 | rs->md.raid_disks = raid_devs; | 120 | rs->md.raid_disks = raid_devs; |
129 | rs->md.level = raid_type->level; | 121 | rs->md.level = raid_type->level; |
130 | rs->md.new_level = rs->md.level; | 122 | rs->md.new_level = rs->md.level; |
131 | rs->md.dev_sectors = sectors_per_dev; | ||
132 | rs->md.layout = raid_type->algorithm; | 123 | rs->md.layout = raid_type->algorithm; |
133 | rs->md.new_layout = rs->md.layout; | 124 | rs->md.new_layout = rs->md.layout; |
134 | rs->md.delta_disks = 0; | 125 | rs->md.delta_disks = 0; |
@@ -143,6 +134,7 @@ static struct raid_set *context_alloc(struct dm_target *ti, struct raid_type *ra | |||
143 | * rs->md.external | 134 | * rs->md.external |
144 | * rs->md.chunk_sectors | 135 | * rs->md.chunk_sectors |
145 | * rs->md.new_chunk_sectors | 136 | * rs->md.new_chunk_sectors |
137 | * rs->md.dev_sectors | ||
146 | */ | 138 | */ |
147 | 139 | ||
148 | return rs; | 140 | return rs; |
@@ -353,6 +345,8 @@ static int parse_raid_params(struct raid_set *rs, char **argv, | |||
353 | { | 345 | { |
354 | unsigned i, rebuild_cnt = 0; | 346 | unsigned i, rebuild_cnt = 0; |
355 | unsigned long value, region_size = 0; | 347 | unsigned long value, region_size = 0; |
348 | sector_t sectors_per_dev = rs->ti->len; | ||
349 | sector_t max_io_len; | ||
356 | char *key; | 350 | char *key; |
357 | 351 | ||
358 | /* | 352 | /* |
@@ -429,13 +423,28 @@ static int parse_raid_params(struct raid_set *rs, char **argv, | |||
429 | 423 | ||
430 | if (!strcasecmp(key, "rebuild")) { | 424 | if (!strcasecmp(key, "rebuild")) { |
431 | rebuild_cnt++; | 425 | rebuild_cnt++; |
432 | if (((rs->raid_type->level != 1) && | 426 | |
433 | (rebuild_cnt > rs->raid_type->parity_devs)) || | 427 | switch (rs->raid_type->level) { |
434 | ((rs->raid_type->level == 1) && | 428 | case 1: |
435 | (rebuild_cnt > (rs->md.raid_disks - 1)))) { | 429 | if (rebuild_cnt >= rs->md.raid_disks) { |
436 | rs->ti->error = "Too many rebuild devices specified for given RAID type"; | 430 | rs->ti->error = "Too many rebuild devices specified"; |
431 | return -EINVAL; | ||
432 | } | ||
433 | break; | ||
434 | case 4: | ||
435 | case 5: | ||
436 | case 6: | ||
437 | if (rebuild_cnt > rs->raid_type->parity_devs) { | ||
438 | rs->ti->error = "Too many rebuild devices specified for given RAID type"; | ||
439 | return -EINVAL; | ||
440 | } | ||
441 | break; | ||
442 | default: | ||
443 | DMERR("The rebuild parameter is not supported for %s", rs->raid_type->name); | ||
444 | rs->ti->error = "Rebuild not supported for this RAID type"; | ||
437 | return -EINVAL; | 445 | return -EINVAL; |
438 | } | 446 | } |
447 | |||
439 | if (value > rs->md.raid_disks) { | 448 | if (value > rs->md.raid_disks) { |
440 | rs->ti->error = "Invalid rebuild index given"; | 449 | rs->ti->error = "Invalid rebuild index given"; |
441 | return -EINVAL; | 450 | return -EINVAL; |
@@ -522,14 +531,19 @@ static int parse_raid_params(struct raid_set *rs, char **argv, | |||
522 | return -EINVAL; | 531 | return -EINVAL; |
523 | 532 | ||
524 | if (rs->md.chunk_sectors) | 533 | if (rs->md.chunk_sectors) |
525 | rs->ti->split_io = rs->md.chunk_sectors; | 534 | max_io_len = rs->md.chunk_sectors; |
526 | else | 535 | else |
527 | rs->ti->split_io = region_size; | 536 | max_io_len = region_size; |
528 | 537 | ||
529 | if (rs->md.chunk_sectors) | 538 | if (dm_set_target_max_io_len(rs->ti, max_io_len)) |
530 | rs->ti->split_io = rs->md.chunk_sectors; | 539 | return -EINVAL; |
531 | else | 540 | |
532 | rs->ti->split_io = region_size; | 541 | if ((rs->raid_type->level > 1) && |
542 | sector_div(sectors_per_dev, (rs->md.raid_disks - rs->raid_type->parity_devs))) { | ||
543 | rs->ti->error = "Target length not divisible by number of data devices"; | ||
544 | return -EINVAL; | ||
545 | } | ||
546 | rs->md.dev_sectors = sectors_per_dev; | ||
533 | 547 | ||
534 | /* Assume there are no metadata devices until the drives are parsed */ | 548 | /* Assume there are no metadata devices until the drives are parsed */ |
535 | rs->md.persistent = 0; | 549 | rs->md.persistent = 0; |
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index d039de8322f0..819ccba65912 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c | |||
@@ -1081,9 +1081,14 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1081 | } | 1081 | } |
1082 | 1082 | ||
1083 | ti->private = ms; | 1083 | ti->private = ms; |
1084 | ti->split_io = dm_rh_get_region_size(ms->rh); | 1084 | |
1085 | r = dm_set_target_max_io_len(ti, dm_rh_get_region_size(ms->rh)); | ||
1086 | if (r) | ||
1087 | goto err_free_context; | ||
1088 | |||
1085 | ti->num_flush_requests = 1; | 1089 | ti->num_flush_requests = 1; |
1086 | ti->num_discard_requests = 1; | 1090 | ti->num_discard_requests = 1; |
1091 | ti->discard_zeroes_data_unsupported = 1; | ||
1087 | 1092 | ||
1088 | ms->kmirrord_wq = alloc_workqueue("kmirrord", | 1093 | ms->kmirrord_wq = alloc_workqueue("kmirrord", |
1089 | WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0); | 1094 | WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0); |
@@ -1214,7 +1219,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, | |||
1214 | * We need to dec pending if this was a write. | 1219 | * We need to dec pending if this was a write. |
1215 | */ | 1220 | */ |
1216 | if (rw == WRITE) { | 1221 | if (rw == WRITE) { |
1217 | if (!(bio->bi_rw & REQ_FLUSH)) | 1222 | if (!(bio->bi_rw & (REQ_FLUSH | REQ_DISCARD))) |
1218 | dm_rh_dec(ms->rh, map_context->ll); | 1223 | dm_rh_dec(ms->rh, map_context->ll); |
1219 | return error; | 1224 | return error; |
1220 | } | 1225 | } |
diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c index 7771ed212182..69732e03eb34 100644 --- a/drivers/md/dm-region-hash.c +++ b/drivers/md/dm-region-hash.c | |||
@@ -404,6 +404,9 @@ void dm_rh_mark_nosync(struct dm_region_hash *rh, struct bio *bio) | |||
404 | return; | 404 | return; |
405 | } | 405 | } |
406 | 406 | ||
407 | if (bio->bi_rw & REQ_DISCARD) | ||
408 | return; | ||
409 | |||
407 | /* We must inform the log that the sync count has changed. */ | 410 | /* We must inform the log that the sync count has changed. */ |
408 | log->type->set_region_sync(log, region, 0); | 411 | log->type->set_region_sync(log, region, 0); |
409 | 412 | ||
@@ -524,7 +527,7 @@ void dm_rh_inc_pending(struct dm_region_hash *rh, struct bio_list *bios) | |||
524 | struct bio *bio; | 527 | struct bio *bio; |
525 | 528 | ||
526 | for (bio = bios->head; bio; bio = bio->bi_next) { | 529 | for (bio = bios->head; bio; bio = bio->bi_next) { |
527 | if (bio->bi_rw & REQ_FLUSH) | 530 | if (bio->bi_rw & (REQ_FLUSH | REQ_DISCARD)) |
528 | continue; | 531 | continue; |
529 | rh_inc(rh, dm_rh_bio_to_region(rh, bio)); | 532 | rh_inc(rh, dm_rh_bio_to_region(rh, bio)); |
530 | } | 533 | } |
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 6f758870fc19..6c0f3e33923a 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -691,7 +691,7 @@ static int dm_add_exception(void *context, chunk_t old, chunk_t new) | |||
691 | * Return a minimum chunk size of all snapshots that have the specified origin. | 691 | * Return a minimum chunk size of all snapshots that have the specified origin. |
692 | * Return zero if the origin has no snapshots. | 692 | * Return zero if the origin has no snapshots. |
693 | */ | 693 | */ |
694 | static sector_t __minimum_chunk_size(struct origin *o) | 694 | static uint32_t __minimum_chunk_size(struct origin *o) |
695 | { | 695 | { |
696 | struct dm_snapshot *snap; | 696 | struct dm_snapshot *snap; |
697 | unsigned chunk_size = 0; | 697 | unsigned chunk_size = 0; |
@@ -701,7 +701,7 @@ static sector_t __minimum_chunk_size(struct origin *o) | |||
701 | chunk_size = min_not_zero(chunk_size, | 701 | chunk_size = min_not_zero(chunk_size, |
702 | snap->store->chunk_size); | 702 | snap->store->chunk_size); |
703 | 703 | ||
704 | return chunk_size; | 704 | return (uint32_t) chunk_size; |
705 | } | 705 | } |
706 | 706 | ||
707 | /* | 707 | /* |
@@ -1172,7 +1172,10 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1172 | ti->error = "Chunk size not set"; | 1172 | ti->error = "Chunk size not set"; |
1173 | goto bad_read_metadata; | 1173 | goto bad_read_metadata; |
1174 | } | 1174 | } |
1175 | ti->split_io = s->store->chunk_size; | 1175 | |
1176 | r = dm_set_target_max_io_len(ti, s->store->chunk_size); | ||
1177 | if (r) | ||
1178 | goto bad_read_metadata; | ||
1176 | 1179 | ||
1177 | return 0; | 1180 | return 0; |
1178 | 1181 | ||
@@ -1239,7 +1242,7 @@ static void __handover_exceptions(struct dm_snapshot *snap_src, | |||
1239 | snap_dest->store->snap = snap_dest; | 1242 | snap_dest->store->snap = snap_dest; |
1240 | snap_src->store->snap = snap_src; | 1243 | snap_src->store->snap = snap_src; |
1241 | 1244 | ||
1242 | snap_dest->ti->split_io = snap_dest->store->chunk_size; | 1245 | snap_dest->ti->max_io_len = snap_dest->store->chunk_size; |
1243 | snap_dest->valid = snap_src->valid; | 1246 | snap_dest->valid = snap_src->valid; |
1244 | 1247 | ||
1245 | /* | 1248 | /* |
@@ -1817,9 +1820,9 @@ static void snapshot_resume(struct dm_target *ti) | |||
1817 | up_write(&s->lock); | 1820 | up_write(&s->lock); |
1818 | } | 1821 | } |
1819 | 1822 | ||
1820 | static sector_t get_origin_minimum_chunksize(struct block_device *bdev) | 1823 | static uint32_t get_origin_minimum_chunksize(struct block_device *bdev) |
1821 | { | 1824 | { |
1822 | sector_t min_chunksize; | 1825 | uint32_t min_chunksize; |
1823 | 1826 | ||
1824 | down_read(&_origins_lock); | 1827 | down_read(&_origins_lock); |
1825 | min_chunksize = __minimum_chunk_size(__lookup_origin(bdev)); | 1828 | min_chunksize = __minimum_chunk_size(__lookup_origin(bdev)); |
@@ -1838,9 +1841,9 @@ static void snapshot_merge_resume(struct dm_target *ti) | |||
1838 | snapshot_resume(ti); | 1841 | snapshot_resume(ti); |
1839 | 1842 | ||
1840 | /* | 1843 | /* |
1841 | * snapshot-merge acts as an origin, so set ti->split_io | 1844 | * snapshot-merge acts as an origin, so set ti->max_io_len |
1842 | */ | 1845 | */ |
1843 | ti->split_io = get_origin_minimum_chunksize(s->origin->bdev); | 1846 | ti->max_io_len = get_origin_minimum_chunksize(s->origin->bdev); |
1844 | 1847 | ||
1845 | start_merge(s); | 1848 | start_merge(s); |
1846 | } | 1849 | } |
@@ -2073,12 +2076,12 @@ static int origin_write_extent(struct dm_snapshot *merging_snap, | |||
2073 | struct origin *o; | 2076 | struct origin *o; |
2074 | 2077 | ||
2075 | /* | 2078 | /* |
2076 | * The origin's __minimum_chunk_size() got stored in split_io | 2079 | * The origin's __minimum_chunk_size() got stored in max_io_len |
2077 | * by snapshot_merge_resume(). | 2080 | * by snapshot_merge_resume(). |
2078 | */ | 2081 | */ |
2079 | down_read(&_origins_lock); | 2082 | down_read(&_origins_lock); |
2080 | o = __lookup_origin(merging_snap->origin->bdev); | 2083 | o = __lookup_origin(merging_snap->origin->bdev); |
2081 | for (n = 0; n < size; n += merging_snap->ti->split_io) | 2084 | for (n = 0; n < size; n += merging_snap->ti->max_io_len) |
2082 | if (__origin_write(&o->snapshots, sector + n, NULL) == | 2085 | if (__origin_write(&o->snapshots, sector + n, NULL) == |
2083 | DM_MAPIO_SUBMITTED) | 2086 | DM_MAPIO_SUBMITTED) |
2084 | must_wait = 1; | 2087 | must_wait = 1; |
@@ -2138,14 +2141,14 @@ static int origin_map(struct dm_target *ti, struct bio *bio, | |||
2138 | } | 2141 | } |
2139 | 2142 | ||
2140 | /* | 2143 | /* |
2141 | * Set the target "split_io" field to the minimum of all the snapshots' | 2144 | * Set the target "max_io_len" field to the minimum of all the snapshots' |
2142 | * chunk sizes. | 2145 | * chunk sizes. |
2143 | */ | 2146 | */ |
2144 | static void origin_resume(struct dm_target *ti) | 2147 | static void origin_resume(struct dm_target *ti) |
2145 | { | 2148 | { |
2146 | struct dm_dev *dev = ti->private; | 2149 | struct dm_dev *dev = ti->private; |
2147 | 2150 | ||
2148 | ti->split_io = get_origin_minimum_chunksize(dev->bdev); | 2151 | ti->max_io_len = get_origin_minimum_chunksize(dev->bdev); |
2149 | } | 2152 | } |
2150 | 2153 | ||
2151 | static int origin_status(struct dm_target *ti, status_type_t type, char *result, | 2154 | static int origin_status(struct dm_target *ti, status_type_t type, char *result, |
@@ -2176,7 +2179,6 @@ static int origin_merge(struct dm_target *ti, struct bvec_merge_data *bvm, | |||
2176 | return max_size; | 2179 | return max_size; |
2177 | 2180 | ||
2178 | bvm->bi_bdev = dev->bdev; | 2181 | bvm->bi_bdev = dev->bdev; |
2179 | bvm->bi_sector = bvm->bi_sector; | ||
2180 | 2182 | ||
2181 | return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); | 2183 | return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); |
2182 | } | 2184 | } |
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 35c94ff24ad5..9e8f4cc63d6c 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c | |||
@@ -26,14 +26,12 @@ struct stripe { | |||
26 | struct stripe_c { | 26 | struct stripe_c { |
27 | uint32_t stripes; | 27 | uint32_t stripes; |
28 | int stripes_shift; | 28 | int stripes_shift; |
29 | sector_t stripes_mask; | ||
30 | 29 | ||
31 | /* The size of this target / num. stripes */ | 30 | /* The size of this target / num. stripes */ |
32 | sector_t stripe_width; | 31 | sector_t stripe_width; |
33 | 32 | ||
34 | /* stripe chunk size */ | 33 | uint32_t chunk_size; |
35 | uint32_t chunk_shift; | 34 | int chunk_size_shift; |
36 | sector_t chunk_mask; | ||
37 | 35 | ||
38 | /* Needed for handling events */ | 36 | /* Needed for handling events */ |
39 | struct dm_target *ti; | 37 | struct dm_target *ti; |
@@ -91,7 +89,7 @@ static int get_stripe(struct dm_target *ti, struct stripe_c *sc, | |||
91 | 89 | ||
92 | /* | 90 | /* |
93 | * Construct a striped mapping. | 91 | * Construct a striped mapping. |
94 | * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+ | 92 | * <number of stripes> <chunk size> [<dev_path> <offset>]+ |
95 | */ | 93 | */ |
96 | static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | 94 | static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) |
97 | { | 95 | { |
@@ -99,7 +97,6 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
99 | sector_t width; | 97 | sector_t width; |
100 | uint32_t stripes; | 98 | uint32_t stripes; |
101 | uint32_t chunk_size; | 99 | uint32_t chunk_size; |
102 | char *end; | ||
103 | int r; | 100 | int r; |
104 | unsigned int i; | 101 | unsigned int i; |
105 | 102 | ||
@@ -108,34 +105,23 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
108 | return -EINVAL; | 105 | return -EINVAL; |
109 | } | 106 | } |
110 | 107 | ||
111 | stripes = simple_strtoul(argv[0], &end, 10); | 108 | if (kstrtouint(argv[0], 10, &stripes) || !stripes) { |
112 | if (!stripes || *end) { | ||
113 | ti->error = "Invalid stripe count"; | 109 | ti->error = "Invalid stripe count"; |
114 | return -EINVAL; | 110 | return -EINVAL; |
115 | } | 111 | } |
116 | 112 | ||
117 | chunk_size = simple_strtoul(argv[1], &end, 10); | 113 | if (kstrtouint(argv[1], 10, &chunk_size) || !chunk_size) { |
118 | if (*end) { | ||
119 | ti->error = "Invalid chunk_size"; | 114 | ti->error = "Invalid chunk_size"; |
120 | return -EINVAL; | 115 | return -EINVAL; |
121 | } | 116 | } |
122 | 117 | ||
123 | /* | 118 | width = ti->len; |
124 | * chunk_size is a power of two | 119 | if (sector_div(width, chunk_size)) { |
125 | */ | ||
126 | if (!is_power_of_2(chunk_size) || | ||
127 | (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) { | ||
128 | ti->error = "Invalid chunk size"; | ||
129 | return -EINVAL; | ||
130 | } | ||
131 | |||
132 | if (ti->len & (chunk_size - 1)) { | ||
133 | ti->error = "Target length not divisible by " | 120 | ti->error = "Target length not divisible by " |
134 | "chunk size"; | 121 | "chunk size"; |
135 | return -EINVAL; | 122 | return -EINVAL; |
136 | } | 123 | } |
137 | 124 | ||
138 | width = ti->len; | ||
139 | if (sector_div(width, stripes)) { | 125 | if (sector_div(width, stripes)) { |
140 | ti->error = "Target length not divisible by " | 126 | ti->error = "Target length not divisible by " |
141 | "number of stripes"; | 127 | "number of stripes"; |
@@ -167,17 +153,21 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
167 | 153 | ||
168 | if (stripes & (stripes - 1)) | 154 | if (stripes & (stripes - 1)) |
169 | sc->stripes_shift = -1; | 155 | sc->stripes_shift = -1; |
170 | else { | 156 | else |
171 | sc->stripes_shift = ffs(stripes) - 1; | 157 | sc->stripes_shift = __ffs(stripes); |
172 | sc->stripes_mask = ((sector_t) stripes) - 1; | 158 | |
173 | } | 159 | r = dm_set_target_max_io_len(ti, chunk_size); |
160 | if (r) | ||
161 | return r; | ||
174 | 162 | ||
175 | ti->split_io = chunk_size; | ||
176 | ti->num_flush_requests = stripes; | 163 | ti->num_flush_requests = stripes; |
177 | ti->num_discard_requests = stripes; | 164 | ti->num_discard_requests = stripes; |
178 | 165 | ||
179 | sc->chunk_shift = ffs(chunk_size) - 1; | 166 | sc->chunk_size = chunk_size; |
180 | sc->chunk_mask = ((sector_t) chunk_size) - 1; | 167 | if (chunk_size & (chunk_size - 1)) |
168 | sc->chunk_size_shift = -1; | ||
169 | else | ||
170 | sc->chunk_size_shift = __ffs(chunk_size); | ||
181 | 171 | ||
182 | /* | 172 | /* |
183 | * Get the stripe destinations. | 173 | * Get the stripe destinations. |
@@ -216,17 +206,29 @@ static void stripe_dtr(struct dm_target *ti) | |||
216 | static void stripe_map_sector(struct stripe_c *sc, sector_t sector, | 206 | static void stripe_map_sector(struct stripe_c *sc, sector_t sector, |
217 | uint32_t *stripe, sector_t *result) | 207 | uint32_t *stripe, sector_t *result) |
218 | { | 208 | { |
219 | sector_t offset = dm_target_offset(sc->ti, sector); | 209 | sector_t chunk = dm_target_offset(sc->ti, sector); |
220 | sector_t chunk = offset >> sc->chunk_shift; | 210 | sector_t chunk_offset; |
211 | |||
212 | if (sc->chunk_size_shift < 0) | ||
213 | chunk_offset = sector_div(chunk, sc->chunk_size); | ||
214 | else { | ||
215 | chunk_offset = chunk & (sc->chunk_size - 1); | ||
216 | chunk >>= sc->chunk_size_shift; | ||
217 | } | ||
221 | 218 | ||
222 | if (sc->stripes_shift < 0) | 219 | if (sc->stripes_shift < 0) |
223 | *stripe = sector_div(chunk, sc->stripes); | 220 | *stripe = sector_div(chunk, sc->stripes); |
224 | else { | 221 | else { |
225 | *stripe = chunk & sc->stripes_mask; | 222 | *stripe = chunk & (sc->stripes - 1); |
226 | chunk >>= sc->stripes_shift; | 223 | chunk >>= sc->stripes_shift; |
227 | } | 224 | } |
228 | 225 | ||
229 | *result = (chunk << sc->chunk_shift) | (offset & sc->chunk_mask); | 226 | if (sc->chunk_size_shift < 0) |
227 | chunk *= sc->chunk_size; | ||
228 | else | ||
229 | chunk <<= sc->chunk_size_shift; | ||
230 | |||
231 | *result = chunk + chunk_offset; | ||
230 | } | 232 | } |
231 | 233 | ||
232 | static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector, | 234 | static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector, |
@@ -237,9 +239,16 @@ static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector, | |||
237 | stripe_map_sector(sc, sector, &stripe, result); | 239 | stripe_map_sector(sc, sector, &stripe, result); |
238 | if (stripe == target_stripe) | 240 | if (stripe == target_stripe) |
239 | return; | 241 | return; |
240 | *result &= ~sc->chunk_mask; /* round down */ | 242 | |
243 | /* round down */ | ||
244 | sector = *result; | ||
245 | if (sc->chunk_size_shift < 0) | ||
246 | *result -= sector_div(sector, sc->chunk_size); | ||
247 | else | ||
248 | *result = sector & ~(sector_t)(sc->chunk_size - 1); | ||
249 | |||
241 | if (target_stripe < stripe) | 250 | if (target_stripe < stripe) |
242 | *result += sc->chunk_mask + 1; /* next chunk */ | 251 | *result += sc->chunk_size; /* next chunk */ |
243 | } | 252 | } |
244 | 253 | ||
245 | static int stripe_map_discard(struct stripe_c *sc, struct bio *bio, | 254 | static int stripe_map_discard(struct stripe_c *sc, struct bio *bio, |
@@ -324,7 +333,7 @@ static int stripe_status(struct dm_target *ti, | |||
324 | 333 | ||
325 | case STATUSTYPE_TABLE: | 334 | case STATUSTYPE_TABLE: |
326 | DMEMIT("%d %llu", sc->stripes, | 335 | DMEMIT("%d %llu", sc->stripes, |
327 | (unsigned long long)sc->chunk_mask + 1); | 336 | (unsigned long long)sc->chunk_size); |
328 | for (i = 0; i < sc->stripes; i++) | 337 | for (i = 0; i < sc->stripes; i++) |
329 | DMEMIT(" %s %llu", sc->stripe[i].dev->name, | 338 | DMEMIT(" %s %llu", sc->stripe[i].dev->name, |
330 | (unsigned long long)sc->stripe[i].physical_start); | 339 | (unsigned long long)sc->stripe[i].physical_start); |
@@ -391,7 +400,7 @@ static void stripe_io_hints(struct dm_target *ti, | |||
391 | struct queue_limits *limits) | 400 | struct queue_limits *limits) |
392 | { | 401 | { |
393 | struct stripe_c *sc = ti->private; | 402 | struct stripe_c *sc = ti->private; |
394 | unsigned chunk_size = (sc->chunk_mask + 1) << 9; | 403 | unsigned chunk_size = sc->chunk_size << SECTOR_SHIFT; |
395 | 404 | ||
396 | blk_limits_io_min(limits, chunk_size); | 405 | blk_limits_io_min(limits, chunk_size); |
397 | blk_limits_io_opt(limits, chunk_size * sc->stripes); | 406 | blk_limits_io_opt(limits, chunk_size * sc->stripes); |
@@ -419,7 +428,7 @@ static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm, | |||
419 | 428 | ||
420 | static struct target_type stripe_target = { | 429 | static struct target_type stripe_target = { |
421 | .name = "striped", | 430 | .name = "striped", |
422 | .version = {1, 4, 0}, | 431 | .version = {1, 5, 0}, |
423 | .module = THIS_MODULE, | 432 | .module = THIS_MODULE, |
424 | .ctr = stripe_ctr, | 433 | .ctr = stripe_ctr, |
425 | .dtr = stripe_dtr, | 434 | .dtr = stripe_dtr, |
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index 3e2907f0bc46..31f9827dfb56 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c | |||
@@ -80,6 +80,12 @@ | |||
80 | #define THIN_METADATA_CACHE_SIZE 64 | 80 | #define THIN_METADATA_CACHE_SIZE 64 |
81 | #define SECTOR_TO_BLOCK_SHIFT 3 | 81 | #define SECTOR_TO_BLOCK_SHIFT 3 |
82 | 82 | ||
83 | /* | ||
84 | * 3 for btree insert + | ||
85 | * 2 for btree lookup used within space map | ||
86 | */ | ||
87 | #define THIN_MAX_CONCURRENT_LOCKS 5 | ||
88 | |||
83 | /* This should be plenty */ | 89 | /* This should be plenty */ |
84 | #define SPACE_MAP_ROOT_SIZE 128 | 90 | #define SPACE_MAP_ROOT_SIZE 128 |
85 | 91 | ||
@@ -597,31 +603,31 @@ static int __commit_transaction(struct dm_pool_metadata *pmd) | |||
597 | 603 | ||
598 | r = __write_changed_details(pmd); | 604 | r = __write_changed_details(pmd); |
599 | if (r < 0) | 605 | if (r < 0) |
600 | goto out; | 606 | return r; |
601 | 607 | ||
602 | if (!pmd->need_commit) | 608 | if (!pmd->need_commit) |
603 | goto out; | 609 | return r; |
604 | 610 | ||
605 | r = dm_sm_commit(pmd->data_sm); | 611 | r = dm_sm_commit(pmd->data_sm); |
606 | if (r < 0) | 612 | if (r < 0) |
607 | goto out; | 613 | return r; |
608 | 614 | ||
609 | r = dm_tm_pre_commit(pmd->tm); | 615 | r = dm_tm_pre_commit(pmd->tm); |
610 | if (r < 0) | 616 | if (r < 0) |
611 | goto out; | 617 | return r; |
612 | 618 | ||
613 | r = dm_sm_root_size(pmd->metadata_sm, &metadata_len); | 619 | r = dm_sm_root_size(pmd->metadata_sm, &metadata_len); |
614 | if (r < 0) | 620 | if (r < 0) |
615 | goto out; | 621 | return r; |
616 | 622 | ||
617 | r = dm_sm_root_size(pmd->data_sm, &data_len); | 623 | r = dm_sm_root_size(pmd->data_sm, &data_len); |
618 | if (r < 0) | 624 | if (r < 0) |
619 | goto out; | 625 | return r; |
620 | 626 | ||
621 | r = dm_bm_write_lock(pmd->bm, THIN_SUPERBLOCK_LOCATION, | 627 | r = dm_bm_write_lock(pmd->bm, THIN_SUPERBLOCK_LOCATION, |
622 | &sb_validator, &sblock); | 628 | &sb_validator, &sblock); |
623 | if (r) | 629 | if (r) |
624 | goto out; | 630 | return r; |
625 | 631 | ||
626 | disk_super = dm_block_data(sblock); | 632 | disk_super = dm_block_data(sblock); |
627 | disk_super->time = cpu_to_le32(pmd->time); | 633 | disk_super->time = cpu_to_le32(pmd->time); |
@@ -644,7 +650,6 @@ static int __commit_transaction(struct dm_pool_metadata *pmd) | |||
644 | if (!r) | 650 | if (!r) |
645 | pmd->need_commit = 0; | 651 | pmd->need_commit = 0; |
646 | 652 | ||
647 | out: | ||
648 | return r; | 653 | return r; |
649 | 654 | ||
650 | out_locked: | 655 | out_locked: |
@@ -669,13 +674,9 @@ struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev, | |||
669 | return ERR_PTR(-ENOMEM); | 674 | return ERR_PTR(-ENOMEM); |
670 | } | 675 | } |
671 | 676 | ||
672 | /* | ||
673 | * Max hex locks: | ||
674 | * 3 for btree insert + | ||
675 | * 2 for btree lookup used within space map | ||
676 | */ | ||
677 | bm = dm_block_manager_create(bdev, THIN_METADATA_BLOCK_SIZE, | 677 | bm = dm_block_manager_create(bdev, THIN_METADATA_BLOCK_SIZE, |
678 | THIN_METADATA_CACHE_SIZE, 5); | 678 | THIN_METADATA_CACHE_SIZE, |
679 | THIN_MAX_CONCURRENT_LOCKS); | ||
679 | if (!bm) { | 680 | if (!bm) { |
680 | DMERR("could not create block manager"); | 681 | DMERR("could not create block manager"); |
681 | kfree(pmd); | 682 | kfree(pmd); |
@@ -1262,7 +1263,7 @@ dm_thin_id dm_thin_dev_id(struct dm_thin_device *td) | |||
1262 | return td->id; | 1263 | return td->id; |
1263 | } | 1264 | } |
1264 | 1265 | ||
1265 | static int __snapshotted_since(struct dm_thin_device *td, uint32_t time) | 1266 | static bool __snapshotted_since(struct dm_thin_device *td, uint32_t time) |
1266 | { | 1267 | { |
1267 | return td->snapshotted_time > time; | 1268 | return td->snapshotted_time > time; |
1268 | } | 1269 | } |
diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h index b88918ccdaf6..7b47c0a9a8e3 100644 --- a/drivers/md/dm-thin-metadata.h +++ b/drivers/md/dm-thin-metadata.h | |||
@@ -119,7 +119,7 @@ dm_thin_id dm_thin_dev_id(struct dm_thin_device *td); | |||
119 | 119 | ||
120 | struct dm_thin_lookup_result { | 120 | struct dm_thin_lookup_result { |
121 | dm_block_t block; | 121 | dm_block_t block; |
122 | int shared; | 122 | unsigned shared:1; |
123 | }; | 123 | }; |
124 | 124 | ||
125 | /* | 125 | /* |
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index ce59824fb414..93e3e542cff9 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c | |||
@@ -19,7 +19,7 @@ | |||
19 | /* | 19 | /* |
20 | * Tunable constants | 20 | * Tunable constants |
21 | */ | 21 | */ |
22 | #define ENDIO_HOOK_POOL_SIZE 10240 | 22 | #define ENDIO_HOOK_POOL_SIZE 1024 |
23 | #define DEFERRED_SET_SIZE 64 | 23 | #define DEFERRED_SET_SIZE 64 |
24 | #define MAPPING_POOL_SIZE 1024 | 24 | #define MAPPING_POOL_SIZE 1024 |
25 | #define PRISON_CELLS 1024 | 25 | #define PRISON_CELLS 1024 |
@@ -510,10 +510,9 @@ struct pool { | |||
510 | struct block_device *md_dev; | 510 | struct block_device *md_dev; |
511 | struct dm_pool_metadata *pmd; | 511 | struct dm_pool_metadata *pmd; |
512 | 512 | ||
513 | uint32_t sectors_per_block; | ||
514 | unsigned block_shift; | ||
515 | dm_block_t offset_mask; | ||
516 | dm_block_t low_water_blocks; | 513 | dm_block_t low_water_blocks; |
514 | uint32_t sectors_per_block; | ||
515 | int sectors_per_block_shift; | ||
517 | 516 | ||
518 | struct pool_features pf; | 517 | struct pool_features pf; |
519 | unsigned low_water_triggered:1; /* A dm event has been sent */ | 518 | unsigned low_water_triggered:1; /* A dm event has been sent */ |
@@ -526,8 +525,8 @@ struct pool { | |||
526 | struct work_struct worker; | 525 | struct work_struct worker; |
527 | struct delayed_work waker; | 526 | struct delayed_work waker; |
528 | 527 | ||
529 | unsigned ref_count; | ||
530 | unsigned long last_commit_jiffies; | 528 | unsigned long last_commit_jiffies; |
529 | unsigned ref_count; | ||
531 | 530 | ||
532 | spinlock_t lock; | 531 | spinlock_t lock; |
533 | struct bio_list deferred_bios; | 532 | struct bio_list deferred_bios; |
@@ -679,16 +678,28 @@ static void requeue_io(struct thin_c *tc) | |||
679 | 678 | ||
680 | static dm_block_t get_bio_block(struct thin_c *tc, struct bio *bio) | 679 | static dm_block_t get_bio_block(struct thin_c *tc, struct bio *bio) |
681 | { | 680 | { |
682 | return bio->bi_sector >> tc->pool->block_shift; | 681 | sector_t block_nr = bio->bi_sector; |
682 | |||
683 | if (tc->pool->sectors_per_block_shift < 0) | ||
684 | (void) sector_div(block_nr, tc->pool->sectors_per_block); | ||
685 | else | ||
686 | block_nr >>= tc->pool->sectors_per_block_shift; | ||
687 | |||
688 | return block_nr; | ||
683 | } | 689 | } |
684 | 690 | ||
685 | static void remap(struct thin_c *tc, struct bio *bio, dm_block_t block) | 691 | static void remap(struct thin_c *tc, struct bio *bio, dm_block_t block) |
686 | { | 692 | { |
687 | struct pool *pool = tc->pool; | 693 | struct pool *pool = tc->pool; |
694 | sector_t bi_sector = bio->bi_sector; | ||
688 | 695 | ||
689 | bio->bi_bdev = tc->pool_dev->bdev; | 696 | bio->bi_bdev = tc->pool_dev->bdev; |
690 | bio->bi_sector = (block << pool->block_shift) + | 697 | if (tc->pool->sectors_per_block_shift < 0) |
691 | (bio->bi_sector & pool->offset_mask); | 698 | bio->bi_sector = (block * pool->sectors_per_block) + |
699 | sector_div(bi_sector, pool->sectors_per_block); | ||
700 | else | ||
701 | bio->bi_sector = (block << pool->sectors_per_block_shift) | | ||
702 | (bi_sector & (pool->sectors_per_block - 1)); | ||
692 | } | 703 | } |
693 | 704 | ||
694 | static void remap_to_origin(struct thin_c *tc, struct bio *bio) | 705 | static void remap_to_origin(struct thin_c *tc, struct bio *bio) |
@@ -933,9 +944,7 @@ static void process_prepared(struct pool *pool, struct list_head *head, | |||
933 | */ | 944 | */ |
934 | static int io_overlaps_block(struct pool *pool, struct bio *bio) | 945 | static int io_overlaps_block(struct pool *pool, struct bio *bio) |
935 | { | 946 | { |
936 | return !(bio->bi_sector & pool->offset_mask) && | 947 | return bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT); |
937 | (bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT)); | ||
938 | |||
939 | } | 948 | } |
940 | 949 | ||
941 | static int io_overwrites_block(struct pool *pool, struct bio *bio) | 950 | static int io_overwrites_block(struct pool *pool, struct bio *bio) |
@@ -1218,7 +1227,7 @@ static void process_discard(struct thin_c *tc, struct bio *bio) | |||
1218 | */ | 1227 | */ |
1219 | m = get_next_mapping(pool); | 1228 | m = get_next_mapping(pool); |
1220 | m->tc = tc; | 1229 | m->tc = tc; |
1221 | m->pass_discard = (!lookup_result.shared) & pool->pf.discard_passdown; | 1230 | m->pass_discard = (!lookup_result.shared) && pool->pf.discard_passdown; |
1222 | m->virt_block = block; | 1231 | m->virt_block = block; |
1223 | m->data_block = lookup_result.block; | 1232 | m->data_block = lookup_result.block; |
1224 | m->cell = cell; | 1233 | m->cell = cell; |
@@ -1234,18 +1243,16 @@ static void process_discard(struct thin_c *tc, struct bio *bio) | |||
1234 | } | 1243 | } |
1235 | } else { | 1244 | } else { |
1236 | /* | 1245 | /* |
1237 | * This path is hit if people are ignoring | 1246 | * The DM core makes sure that the discard doesn't span |
1238 | * limits->discard_granularity. It ignores any | 1247 | * a block boundary. So we submit the discard of a |
1239 | * part of the discard that is in a subsequent | 1248 | * partial block appropriately. |
1240 | * block. | ||
1241 | */ | 1249 | */ |
1242 | sector_t offset = bio->bi_sector - (block << pool->block_shift); | ||
1243 | unsigned remaining = (pool->sectors_per_block - offset) << 9; | ||
1244 | bio->bi_size = min(bio->bi_size, remaining); | ||
1245 | |||
1246 | cell_release_singleton(cell, bio); | 1250 | cell_release_singleton(cell, bio); |
1247 | cell_release_singleton(cell2, bio); | 1251 | cell_release_singleton(cell2, bio); |
1248 | remap_and_issue(tc, bio, lookup_result.block); | 1252 | if ((!lookup_result.shared) && pool->pf.discard_passdown) |
1253 | remap_and_issue(tc, bio, lookup_result.block); | ||
1254 | else | ||
1255 | bio_endio(bio, 0); | ||
1249 | } | 1256 | } |
1250 | break; | 1257 | break; |
1251 | 1258 | ||
@@ -1719,8 +1726,10 @@ static struct pool *pool_create(struct mapped_device *pool_md, | |||
1719 | 1726 | ||
1720 | pool->pmd = pmd; | 1727 | pool->pmd = pmd; |
1721 | pool->sectors_per_block = block_size; | 1728 | pool->sectors_per_block = block_size; |
1722 | pool->block_shift = ffs(block_size) - 1; | 1729 | if (block_size & (block_size - 1)) |
1723 | pool->offset_mask = block_size - 1; | 1730 | pool->sectors_per_block_shift = -1; |
1731 | else | ||
1732 | pool->sectors_per_block_shift = __ffs(block_size); | ||
1724 | pool->low_water_blocks = 0; | 1733 | pool->low_water_blocks = 0; |
1725 | pool_features_init(&pool->pf); | 1734 | pool_features_init(&pool->pf); |
1726 | pool->prison = prison_create(PRISON_CELLS); | 1735 | pool->prison = prison_create(PRISON_CELLS); |
@@ -1825,15 +1834,19 @@ static struct pool *__pool_find(struct mapped_device *pool_md, | |||
1825 | struct pool *pool = __pool_table_lookup_metadata_dev(metadata_dev); | 1834 | struct pool *pool = __pool_table_lookup_metadata_dev(metadata_dev); |
1826 | 1835 | ||
1827 | if (pool) { | 1836 | if (pool) { |
1828 | if (pool->pool_md != pool_md) | 1837 | if (pool->pool_md != pool_md) { |
1838 | *error = "metadata device already in use by a pool"; | ||
1829 | return ERR_PTR(-EBUSY); | 1839 | return ERR_PTR(-EBUSY); |
1840 | } | ||
1830 | __pool_inc(pool); | 1841 | __pool_inc(pool); |
1831 | 1842 | ||
1832 | } else { | 1843 | } else { |
1833 | pool = __pool_table_lookup(pool_md); | 1844 | pool = __pool_table_lookup(pool_md); |
1834 | if (pool) { | 1845 | if (pool) { |
1835 | if (pool->md_dev != metadata_dev) | 1846 | if (pool->md_dev != metadata_dev) { |
1847 | *error = "different pool cannot replace a pool"; | ||
1836 | return ERR_PTR(-EINVAL); | 1848 | return ERR_PTR(-EINVAL); |
1849 | } | ||
1837 | __pool_inc(pool); | 1850 | __pool_inc(pool); |
1838 | 1851 | ||
1839 | } else { | 1852 | } else { |
@@ -1964,7 +1977,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv) | |||
1964 | if (kstrtoul(argv[2], 10, &block_size) || !block_size || | 1977 | if (kstrtoul(argv[2], 10, &block_size) || !block_size || |
1965 | block_size < DATA_DEV_BLOCK_SIZE_MIN_SECTORS || | 1978 | block_size < DATA_DEV_BLOCK_SIZE_MIN_SECTORS || |
1966 | block_size > DATA_DEV_BLOCK_SIZE_MAX_SECTORS || | 1979 | block_size > DATA_DEV_BLOCK_SIZE_MAX_SECTORS || |
1967 | !is_power_of_2(block_size)) { | 1980 | block_size & (DATA_DEV_BLOCK_SIZE_MIN_SECTORS - 1)) { |
1968 | ti->error = "Invalid block size"; | 1981 | ti->error = "Invalid block size"; |
1969 | r = -EINVAL; | 1982 | r = -EINVAL; |
1970 | goto out; | 1983 | goto out; |
@@ -2011,6 +2024,15 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv) | |||
2011 | goto out_flags_changed; | 2024 | goto out_flags_changed; |
2012 | } | 2025 | } |
2013 | 2026 | ||
2027 | /* | ||
2028 | * The block layer requires discard_granularity to be a power of 2. | ||
2029 | */ | ||
2030 | if (pf.discard_enabled && !is_power_of_2(block_size)) { | ||
2031 | ti->error = "Discard support must be disabled when the block size is not a power of 2"; | ||
2032 | r = -EINVAL; | ||
2033 | goto out_flags_changed; | ||
2034 | } | ||
2035 | |||
2014 | pt->pool = pool; | 2036 | pt->pool = pool; |
2015 | pt->ti = ti; | 2037 | pt->ti = ti; |
2016 | pt->metadata_dev = metadata_dev; | 2038 | pt->metadata_dev = metadata_dev; |
@@ -2090,7 +2112,8 @@ static int pool_preresume(struct dm_target *ti) | |||
2090 | int r; | 2112 | int r; |
2091 | struct pool_c *pt = ti->private; | 2113 | struct pool_c *pt = ti->private; |
2092 | struct pool *pool = pt->pool; | 2114 | struct pool *pool = pt->pool; |
2093 | dm_block_t data_size, sb_data_size; | 2115 | sector_t data_size = ti->len; |
2116 | dm_block_t sb_data_size; | ||
2094 | 2117 | ||
2095 | /* | 2118 | /* |
2096 | * Take control of the pool object. | 2119 | * Take control of the pool object. |
@@ -2099,7 +2122,8 @@ static int pool_preresume(struct dm_target *ti) | |||
2099 | if (r) | 2122 | if (r) |
2100 | return r; | 2123 | return r; |
2101 | 2124 | ||
2102 | data_size = ti->len >> pool->block_shift; | 2125 | (void) sector_div(data_size, pool->sectors_per_block); |
2126 | |||
2103 | r = dm_pool_get_data_dev_size(pool->pmd, &sb_data_size); | 2127 | r = dm_pool_get_data_dev_size(pool->pmd, &sb_data_size); |
2104 | if (r) { | 2128 | if (r) { |
2105 | DMERR("failed to retrieve data device size"); | 2129 | DMERR("failed to retrieve data device size"); |
@@ -2108,7 +2132,7 @@ static int pool_preresume(struct dm_target *ti) | |||
2108 | 2132 | ||
2109 | if (data_size < sb_data_size) { | 2133 | if (data_size < sb_data_size) { |
2110 | DMERR("pool target too small, is %llu blocks (expected %llu)", | 2134 | DMERR("pool target too small, is %llu blocks (expected %llu)", |
2111 | data_size, sb_data_size); | 2135 | (unsigned long long)data_size, sb_data_size); |
2112 | return -EINVAL; | 2136 | return -EINVAL; |
2113 | 2137 | ||
2114 | } else if (data_size > sb_data_size) { | 2138 | } else if (data_size > sb_data_size) { |
@@ -2489,7 +2513,8 @@ static void set_discard_limits(struct pool *pool, struct queue_limits *limits) | |||
2489 | 2513 | ||
2490 | /* | 2514 | /* |
2491 | * This is just a hint, and not enforced. We have to cope with | 2515 | * This is just a hint, and not enforced. We have to cope with |
2492 | * bios that overlap 2 blocks. | 2516 | * bios that cover a block partially. A discard that spans a block |
2517 | * boundary is not sent to this target. | ||
2493 | */ | 2518 | */ |
2494 | limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT; | 2519 | limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT; |
2495 | limits->discard_zeroes_data = pool->pf.zero_new_blocks; | 2520 | limits->discard_zeroes_data = pool->pf.zero_new_blocks; |
@@ -2621,13 +2646,19 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) | |||
2621 | goto bad_thin_open; | 2646 | goto bad_thin_open; |
2622 | } | 2647 | } |
2623 | 2648 | ||
2624 | ti->split_io = tc->pool->sectors_per_block; | 2649 | r = dm_set_target_max_io_len(ti, tc->pool->sectors_per_block); |
2650 | if (r) | ||
2651 | goto bad_thin_open; | ||
2652 | |||
2625 | ti->num_flush_requests = 1; | 2653 | ti->num_flush_requests = 1; |
2626 | 2654 | ||
2627 | /* In case the pool supports discards, pass them on. */ | 2655 | /* In case the pool supports discards, pass them on. */ |
2628 | if (tc->pool->pf.discard_enabled) { | 2656 | if (tc->pool->pf.discard_enabled) { |
2629 | ti->discards_supported = 1; | 2657 | ti->discards_supported = 1; |
2630 | ti->num_discard_requests = 1; | 2658 | ti->num_discard_requests = 1; |
2659 | ti->discard_zeroes_data_unsupported = 1; | ||
2660 | /* Discard requests must be split on a block boundary */ | ||
2661 | ti->split_discard_requests = 1; | ||
2631 | } | 2662 | } |
2632 | 2663 | ||
2633 | dm_put(pool_md); | 2664 | dm_put(pool_md); |
@@ -2753,19 +2784,21 @@ static int thin_status(struct dm_target *ti, status_type_t type, | |||
2753 | static int thin_iterate_devices(struct dm_target *ti, | 2784 | static int thin_iterate_devices(struct dm_target *ti, |
2754 | iterate_devices_callout_fn fn, void *data) | 2785 | iterate_devices_callout_fn fn, void *data) |
2755 | { | 2786 | { |
2756 | dm_block_t blocks; | 2787 | sector_t blocks; |
2757 | struct thin_c *tc = ti->private; | 2788 | struct thin_c *tc = ti->private; |
2789 | struct pool *pool = tc->pool; | ||
2758 | 2790 | ||
2759 | /* | 2791 | /* |
2760 | * We can't call dm_pool_get_data_dev_size() since that blocks. So | 2792 | * We can't call dm_pool_get_data_dev_size() since that blocks. So |
2761 | * we follow a more convoluted path through to the pool's target. | 2793 | * we follow a more convoluted path through to the pool's target. |
2762 | */ | 2794 | */ |
2763 | if (!tc->pool->ti) | 2795 | if (!pool->ti) |
2764 | return 0; /* nothing is bound */ | 2796 | return 0; /* nothing is bound */ |
2765 | 2797 | ||
2766 | blocks = tc->pool->ti->len >> tc->pool->block_shift; | 2798 | blocks = pool->ti->len; |
2799 | (void) sector_div(blocks, pool->sectors_per_block); | ||
2767 | if (blocks) | 2800 | if (blocks) |
2768 | return fn(ti, tc->pool_dev, 0, tc->pool->sectors_per_block * blocks, data); | 2801 | return fn(ti, tc->pool_dev, 0, pool->sectors_per_block * blocks, data); |
2769 | 2802 | ||
2770 | return 0; | 2803 | return 0; |
2771 | } | 2804 | } |
@@ -2782,7 +2815,7 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits) | |||
2782 | 2815 | ||
2783 | static struct target_type thin_target = { | 2816 | static struct target_type thin_target = { |
2784 | .name = "thin", | 2817 | .name = "thin", |
2785 | .version = {1, 1, 0}, | 2818 | .version = {1, 2, 0}, |
2786 | .module = THIS_MODULE, | 2819 | .module = THIS_MODULE, |
2787 | .ctr = thin_ctr, | 2820 | .ctr = thin_ctr, |
2788 | .dtr = thin_dtr, | 2821 | .dtr = thin_dtr, |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index e24143cc2040..4e09b6ff5b49 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -968,22 +968,41 @@ static sector_t max_io_len_target_boundary(sector_t sector, struct dm_target *ti | |||
968 | static sector_t max_io_len(sector_t sector, struct dm_target *ti) | 968 | static sector_t max_io_len(sector_t sector, struct dm_target *ti) |
969 | { | 969 | { |
970 | sector_t len = max_io_len_target_boundary(sector, ti); | 970 | sector_t len = max_io_len_target_boundary(sector, ti); |
971 | sector_t offset, max_len; | ||
971 | 972 | ||
972 | /* | 973 | /* |
973 | * Does the target need to split even further ? | 974 | * Does the target need to split even further? |
974 | */ | 975 | */ |
975 | if (ti->split_io) { | 976 | if (ti->max_io_len) { |
976 | sector_t boundary; | 977 | offset = dm_target_offset(ti, sector); |
977 | sector_t offset = dm_target_offset(ti, sector); | 978 | if (unlikely(ti->max_io_len & (ti->max_io_len - 1))) |
978 | boundary = ((offset + ti->split_io) & ~(ti->split_io - 1)) | 979 | max_len = sector_div(offset, ti->max_io_len); |
979 | - offset; | 980 | else |
980 | if (len > boundary) | 981 | max_len = offset & (ti->max_io_len - 1); |
981 | len = boundary; | 982 | max_len = ti->max_io_len - max_len; |
983 | |||
984 | if (len > max_len) | ||
985 | len = max_len; | ||
982 | } | 986 | } |
983 | 987 | ||
984 | return len; | 988 | return len; |
985 | } | 989 | } |
986 | 990 | ||
991 | int dm_set_target_max_io_len(struct dm_target *ti, sector_t len) | ||
992 | { | ||
993 | if (len > UINT_MAX) { | ||
994 | DMERR("Specified maximum size of target IO (%llu) exceeds limit (%u)", | ||
995 | (unsigned long long)len, UINT_MAX); | ||
996 | ti->error = "Maximum size of target IO is too large"; | ||
997 | return -EINVAL; | ||
998 | } | ||
999 | |||
1000 | ti->max_io_len = (uint32_t) len; | ||
1001 | |||
1002 | return 0; | ||
1003 | } | ||
1004 | EXPORT_SYMBOL_GPL(dm_set_target_max_io_len); | ||
1005 | |||
987 | static void __map_bio(struct dm_target *ti, struct bio *clone, | 1006 | static void __map_bio(struct dm_target *ti, struct bio *clone, |
988 | struct dm_target_io *tio) | 1007 | struct dm_target_io *tio) |
989 | { | 1008 | { |
@@ -1196,7 +1215,10 @@ static int __clone_and_map_discard(struct clone_info *ci) | |||
1196 | if (!ti->num_discard_requests) | 1215 | if (!ti->num_discard_requests) |
1197 | return -EOPNOTSUPP; | 1216 | return -EOPNOTSUPP; |
1198 | 1217 | ||
1199 | len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti)); | 1218 | if (!ti->split_discard_requests) |
1219 | len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti)); | ||
1220 | else | ||
1221 | len = min(ci->sector_count, max_io_len(ci->sector, ti)); | ||
1200 | 1222 | ||
1201 | __issue_target_requests(ci, ti, ti->num_discard_requests, len); | 1223 | __issue_target_requests(ci, ti, ti->num_discard_requests, len); |
1202 | 1224 | ||
diff --git a/drivers/md/persistent-data/Makefile b/drivers/md/persistent-data/Makefile index cfa95f662230..d8e7cb767c1e 100644 --- a/drivers/md/persistent-data/Makefile +++ b/drivers/md/persistent-data/Makefile | |||
@@ -1,7 +1,6 @@ | |||
1 | obj-$(CONFIG_DM_PERSISTENT_DATA) += dm-persistent-data.o | 1 | obj-$(CONFIG_DM_PERSISTENT_DATA) += dm-persistent-data.o |
2 | dm-persistent-data-objs := \ | 2 | dm-persistent-data-objs := \ |
3 | dm-block-manager.o \ | 3 | dm-block-manager.o \ |
4 | dm-space-map-checker.o \ | ||
5 | dm-space-map-common.o \ | 4 | dm-space-map-common.o \ |
6 | dm-space-map-disk.o \ | 5 | dm-space-map-disk.o \ |
7 | dm-space-map-metadata.o \ | 6 | dm-space-map-metadata.o \ |
diff --git a/drivers/md/persistent-data/dm-space-map-checker.c b/drivers/md/persistent-data/dm-space-map-checker.c deleted file mode 100644 index fc90c11620ad..000000000000 --- a/drivers/md/persistent-data/dm-space-map-checker.c +++ /dev/null | |||
@@ -1,446 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Red Hat, Inc. | ||
3 | * | ||
4 | * This file is released under the GPL. | ||
5 | */ | ||
6 | |||
7 | #include "dm-space-map-checker.h" | ||
8 | |||
9 | #include <linux/device-mapper.h> | ||
10 | #include <linux/export.h> | ||
11 | #include <linux/vmalloc.h> | ||
12 | |||
13 | #ifdef CONFIG_DM_DEBUG_SPACE_MAPS | ||
14 | |||
15 | #define DM_MSG_PREFIX "space map checker" | ||
16 | |||
17 | /*----------------------------------------------------------------*/ | ||
18 | |||
19 | struct count_array { | ||
20 | dm_block_t nr; | ||
21 | dm_block_t nr_free; | ||
22 | |||
23 | uint32_t *counts; | ||
24 | }; | ||
25 | |||
26 | static int ca_get_count(struct count_array *ca, dm_block_t b, uint32_t *count) | ||
27 | { | ||
28 | if (b >= ca->nr) | ||
29 | return -EINVAL; | ||
30 | |||
31 | *count = ca->counts[b]; | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static int ca_count_more_than_one(struct count_array *ca, dm_block_t b, int *r) | ||
36 | { | ||
37 | if (b >= ca->nr) | ||
38 | return -EINVAL; | ||
39 | |||
40 | *r = ca->counts[b] > 1; | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static int ca_set_count(struct count_array *ca, dm_block_t b, uint32_t count) | ||
45 | { | ||
46 | uint32_t old_count; | ||
47 | |||
48 | if (b >= ca->nr) | ||
49 | return -EINVAL; | ||
50 | |||
51 | old_count = ca->counts[b]; | ||
52 | |||
53 | if (!count && old_count) | ||
54 | ca->nr_free++; | ||
55 | |||
56 | else if (count && !old_count) | ||
57 | ca->nr_free--; | ||
58 | |||
59 | ca->counts[b] = count; | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static int ca_inc_block(struct count_array *ca, dm_block_t b) | ||
64 | { | ||
65 | if (b >= ca->nr) | ||
66 | return -EINVAL; | ||
67 | |||
68 | ca_set_count(ca, b, ca->counts[b] + 1); | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static int ca_dec_block(struct count_array *ca, dm_block_t b) | ||
73 | { | ||
74 | if (b >= ca->nr) | ||
75 | return -EINVAL; | ||
76 | |||
77 | BUG_ON(ca->counts[b] == 0); | ||
78 | ca_set_count(ca, b, ca->counts[b] - 1); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int ca_create(struct count_array *ca, struct dm_space_map *sm) | ||
83 | { | ||
84 | int r; | ||
85 | dm_block_t nr_blocks; | ||
86 | |||
87 | r = dm_sm_get_nr_blocks(sm, &nr_blocks); | ||
88 | if (r) | ||
89 | return r; | ||
90 | |||
91 | ca->nr = nr_blocks; | ||
92 | ca->nr_free = nr_blocks; | ||
93 | |||
94 | if (!nr_blocks) | ||
95 | ca->counts = NULL; | ||
96 | else { | ||
97 | ca->counts = vzalloc(sizeof(*ca->counts) * nr_blocks); | ||
98 | if (!ca->counts) | ||
99 | return -ENOMEM; | ||
100 | } | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static void ca_destroy(struct count_array *ca) | ||
106 | { | ||
107 | vfree(ca->counts); | ||
108 | } | ||
109 | |||
110 | static int ca_load(struct count_array *ca, struct dm_space_map *sm) | ||
111 | { | ||
112 | int r; | ||
113 | uint32_t count; | ||
114 | dm_block_t nr_blocks, i; | ||
115 | |||
116 | r = dm_sm_get_nr_blocks(sm, &nr_blocks); | ||
117 | if (r) | ||
118 | return r; | ||
119 | |||
120 | BUG_ON(ca->nr != nr_blocks); | ||
121 | |||
122 | DMWARN("Loading debug space map from disk. This may take some time"); | ||
123 | for (i = 0; i < nr_blocks; i++) { | ||
124 | r = dm_sm_get_count(sm, i, &count); | ||
125 | if (r) { | ||
126 | DMERR("load failed"); | ||
127 | return r; | ||
128 | } | ||
129 | |||
130 | ca_set_count(ca, i, count); | ||
131 | } | ||
132 | DMWARN("Load complete"); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int ca_extend(struct count_array *ca, dm_block_t extra_blocks) | ||
138 | { | ||
139 | dm_block_t nr_blocks = ca->nr + extra_blocks; | ||
140 | uint32_t *counts = vzalloc(sizeof(*counts) * nr_blocks); | ||
141 | if (!counts) | ||
142 | return -ENOMEM; | ||
143 | |||
144 | if (ca->counts) { | ||
145 | memcpy(counts, ca->counts, sizeof(*counts) * ca->nr); | ||
146 | ca_destroy(ca); | ||
147 | } | ||
148 | ca->nr = nr_blocks; | ||
149 | ca->nr_free += extra_blocks; | ||
150 | ca->counts = counts; | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int ca_commit(struct count_array *old, struct count_array *new) | ||
155 | { | ||
156 | if (old->nr != new->nr) { | ||
157 | BUG_ON(old->nr > new->nr); | ||
158 | ca_extend(old, new->nr - old->nr); | ||
159 | } | ||
160 | |||
161 | BUG_ON(old->nr != new->nr); | ||
162 | old->nr_free = new->nr_free; | ||
163 | memcpy(old->counts, new->counts, sizeof(*old->counts) * old->nr); | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | /*----------------------------------------------------------------*/ | ||
168 | |||
169 | struct sm_checker { | ||
170 | struct dm_space_map sm; | ||
171 | |||
172 | struct count_array old_counts; | ||
173 | struct count_array counts; | ||
174 | |||
175 | struct dm_space_map *real_sm; | ||
176 | }; | ||
177 | |||
178 | static void sm_checker_destroy(struct dm_space_map *sm) | ||
179 | { | ||
180 | struct sm_checker *smc = container_of(sm, struct sm_checker, sm); | ||
181 | |||
182 | dm_sm_destroy(smc->real_sm); | ||
183 | ca_destroy(&smc->old_counts); | ||
184 | ca_destroy(&smc->counts); | ||
185 | kfree(smc); | ||
186 | } | ||
187 | |||
188 | static int sm_checker_get_nr_blocks(struct dm_space_map *sm, dm_block_t *count) | ||
189 | { | ||
190 | struct sm_checker *smc = container_of(sm, struct sm_checker, sm); | ||
191 | int r = dm_sm_get_nr_blocks(smc->real_sm, count); | ||
192 | if (!r) | ||
193 | BUG_ON(smc->old_counts.nr != *count); | ||
194 | return r; | ||
195 | } | ||
196 | |||
197 | static int sm_checker_get_nr_free(struct dm_space_map *sm, dm_block_t *count) | ||
198 | { | ||
199 | struct sm_checker *smc = container_of(sm, struct sm_checker, sm); | ||
200 | int r = dm_sm_get_nr_free(smc->real_sm, count); | ||
201 | if (!r) { | ||
202 | /* | ||
203 | * Slow, but we know it's correct. | ||
204 | */ | ||
205 | dm_block_t b, n = 0; | ||
206 | for (b = 0; b < smc->old_counts.nr; b++) | ||
207 | if (smc->old_counts.counts[b] == 0 && | ||
208 | smc->counts.counts[b] == 0) | ||
209 | n++; | ||
210 | |||
211 | if (n != *count) | ||
212 | DMERR("free block counts differ, checker %u, sm-disk:%u", | ||
213 | (unsigned) n, (unsigned) *count); | ||
214 | } | ||
215 | return r; | ||
216 | } | ||
217 | |||
218 | static int sm_checker_new_block(struct dm_space_map *sm, dm_block_t *b) | ||
219 | { | ||
220 | struct sm_checker *smc = container_of(sm, struct sm_checker, sm); | ||
221 | int r = dm_sm_new_block(smc->real_sm, b); | ||
222 | |||
223 | if (!r) { | ||
224 | BUG_ON(*b >= smc->old_counts.nr); | ||
225 | BUG_ON(smc->old_counts.counts[*b] != 0); | ||
226 | BUG_ON(*b >= smc->counts.nr); | ||
227 | BUG_ON(smc->counts.counts[*b] != 0); | ||
228 | ca_set_count(&smc->counts, *b, 1); | ||
229 | } | ||
230 | |||
231 | return r; | ||
232 | } | ||
233 | |||
234 | static int sm_checker_inc_block(struct dm_space_map *sm, dm_block_t b) | ||
235 | { | ||
236 | struct sm_checker *smc = container_of(sm, struct sm_checker, sm); | ||
237 | int r = dm_sm_inc_block(smc->real_sm, b); | ||
238 | int r2 = ca_inc_block(&smc->counts, b); | ||
239 | BUG_ON(r != r2); | ||
240 | return r; | ||
241 | } | ||
242 | |||
243 | static int sm_checker_dec_block(struct dm_space_map *sm, dm_block_t b) | ||
244 | { | ||
245 | struct sm_checker *smc = container_of(sm, struct sm_checker, sm); | ||
246 | int r = dm_sm_dec_block(smc->real_sm, b); | ||
247 | int r2 = ca_dec_block(&smc->counts, b); | ||
248 | BUG_ON(r != r2); | ||
249 | return r; | ||
250 | } | ||
251 | |||
252 | static int sm_checker_get_count(struct dm_space_map *sm, dm_block_t b, uint32_t *result) | ||
253 | { | ||
254 | struct sm_checker *smc = container_of(sm, struct sm_checker, sm); | ||
255 | uint32_t result2 = 0; | ||
256 | int r = dm_sm_get_count(smc->real_sm, b, result); | ||
257 | int r2 = ca_get_count(&smc->counts, b, &result2); | ||
258 | |||
259 | BUG_ON(r != r2); | ||
260 | if (!r) | ||
261 | BUG_ON(*result != result2); | ||
262 | return r; | ||
263 | } | ||
264 | |||
265 | static int sm_checker_count_more_than_one(struct dm_space_map *sm, dm_block_t b, int *result) | ||
266 | { | ||
267 | struct sm_checker *smc = container_of(sm, struct sm_checker, sm); | ||
268 | int result2 = 0; | ||
269 | int r = dm_sm_count_is_more_than_one(smc->real_sm, b, result); | ||
270 | int r2 = ca_count_more_than_one(&smc->counts, b, &result2); | ||
271 | |||
272 | BUG_ON(r != r2); | ||
273 | if (!r) | ||
274 | BUG_ON(!(*result) && result2); | ||
275 | return r; | ||
276 | } | ||
277 | |||
278 | static int sm_checker_set_count(struct dm_space_map *sm, dm_block_t b, uint32_t count) | ||
279 | { | ||
280 | struct sm_checker *smc = container_of(sm, struct sm_checker, sm); | ||
281 | uint32_t old_rc; | ||
282 | int r = dm_sm_set_count(smc->real_sm, b, count); | ||
283 | int r2; | ||
284 | |||
285 | BUG_ON(b >= smc->counts.nr); | ||
286 | old_rc = smc->counts.counts[b]; | ||
287 | r2 = ca_set_count(&smc->counts, b, count); | ||
288 | BUG_ON(r != r2); | ||
289 | |||
290 | return r; | ||
291 | } | ||
292 | |||
293 | static int sm_checker_commit(struct dm_space_map *sm) | ||
294 | { | ||
295 | struct sm_checker *smc = container_of(sm, struct sm_checker, sm); | ||
296 | int r; | ||
297 | |||
298 | r = dm_sm_commit(smc->real_sm); | ||
299 | if (r) | ||
300 | return r; | ||
301 | |||
302 | r = ca_commit(&smc->old_counts, &smc->counts); | ||
303 | if (r) | ||
304 | return r; | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static int sm_checker_extend(struct dm_space_map *sm, dm_block_t extra_blocks) | ||
310 | { | ||
311 | struct sm_checker *smc = container_of(sm, struct sm_checker, sm); | ||
312 | int r = dm_sm_extend(smc->real_sm, extra_blocks); | ||
313 | if (r) | ||
314 | return r; | ||
315 | |||
316 | return ca_extend(&smc->counts, extra_blocks); | ||
317 | } | ||
318 | |||
319 | static int sm_checker_root_size(struct dm_space_map *sm, size_t *result) | ||
320 | { | ||
321 | struct sm_checker *smc = container_of(sm, struct sm_checker, sm); | ||
322 | return dm_sm_root_size(smc->real_sm, result); | ||
323 | } | ||
324 | |||
325 | static int sm_checker_copy_root(struct dm_space_map *sm, void *copy_to_here_le, size_t len) | ||
326 | { | ||
327 | struct sm_checker *smc = container_of(sm, struct sm_checker, sm); | ||
328 | return dm_sm_copy_root(smc->real_sm, copy_to_here_le, len); | ||
329 | } | ||
330 | |||
331 | /*----------------------------------------------------------------*/ | ||
332 | |||
333 | static struct dm_space_map ops_ = { | ||
334 | .destroy = sm_checker_destroy, | ||
335 | .get_nr_blocks = sm_checker_get_nr_blocks, | ||
336 | .get_nr_free = sm_checker_get_nr_free, | ||
337 | .inc_block = sm_checker_inc_block, | ||
338 | .dec_block = sm_checker_dec_block, | ||
339 | .new_block = sm_checker_new_block, | ||
340 | .get_count = sm_checker_get_count, | ||
341 | .count_is_more_than_one = sm_checker_count_more_than_one, | ||
342 | .set_count = sm_checker_set_count, | ||
343 | .commit = sm_checker_commit, | ||
344 | .extend = sm_checker_extend, | ||
345 | .root_size = sm_checker_root_size, | ||
346 | .copy_root = sm_checker_copy_root | ||
347 | }; | ||
348 | |||
349 | struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm) | ||
350 | { | ||
351 | int r; | ||
352 | struct sm_checker *smc; | ||
353 | |||
354 | if (IS_ERR_OR_NULL(sm)) | ||
355 | return ERR_PTR(-EINVAL); | ||
356 | |||
357 | smc = kmalloc(sizeof(*smc), GFP_KERNEL); | ||
358 | if (!smc) | ||
359 | return ERR_PTR(-ENOMEM); | ||
360 | |||
361 | memcpy(&smc->sm, &ops_, sizeof(smc->sm)); | ||
362 | r = ca_create(&smc->old_counts, sm); | ||
363 | if (r) { | ||
364 | kfree(smc); | ||
365 | return ERR_PTR(r); | ||
366 | } | ||
367 | |||
368 | r = ca_create(&smc->counts, sm); | ||
369 | if (r) { | ||
370 | ca_destroy(&smc->old_counts); | ||
371 | kfree(smc); | ||
372 | return ERR_PTR(r); | ||
373 | } | ||
374 | |||
375 | smc->real_sm = sm; | ||
376 | |||
377 | r = ca_load(&smc->counts, sm); | ||
378 | if (r) { | ||
379 | ca_destroy(&smc->counts); | ||
380 | ca_destroy(&smc->old_counts); | ||
381 | kfree(smc); | ||
382 | return ERR_PTR(r); | ||
383 | } | ||
384 | |||
385 | r = ca_commit(&smc->old_counts, &smc->counts); | ||
386 | if (r) { | ||
387 | ca_destroy(&smc->counts); | ||
388 | ca_destroy(&smc->old_counts); | ||
389 | kfree(smc); | ||
390 | return ERR_PTR(r); | ||
391 | } | ||
392 | |||
393 | return &smc->sm; | ||
394 | } | ||
395 | EXPORT_SYMBOL_GPL(dm_sm_checker_create); | ||
396 | |||
397 | struct dm_space_map *dm_sm_checker_create_fresh(struct dm_space_map *sm) | ||
398 | { | ||
399 | int r; | ||
400 | struct sm_checker *smc; | ||
401 | |||
402 | if (IS_ERR_OR_NULL(sm)) | ||
403 | return ERR_PTR(-EINVAL); | ||
404 | |||
405 | smc = kmalloc(sizeof(*smc), GFP_KERNEL); | ||
406 | if (!smc) | ||
407 | return ERR_PTR(-ENOMEM); | ||
408 | |||
409 | memcpy(&smc->sm, &ops_, sizeof(smc->sm)); | ||
410 | r = ca_create(&smc->old_counts, sm); | ||
411 | if (r) { | ||
412 | kfree(smc); | ||
413 | return ERR_PTR(r); | ||
414 | } | ||
415 | |||
416 | r = ca_create(&smc->counts, sm); | ||
417 | if (r) { | ||
418 | ca_destroy(&smc->old_counts); | ||
419 | kfree(smc); | ||
420 | return ERR_PTR(r); | ||
421 | } | ||
422 | |||
423 | smc->real_sm = sm; | ||
424 | return &smc->sm; | ||
425 | } | ||
426 | EXPORT_SYMBOL_GPL(dm_sm_checker_create_fresh); | ||
427 | |||
428 | /*----------------------------------------------------------------*/ | ||
429 | |||
430 | #else | ||
431 | |||
432 | struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm) | ||
433 | { | ||
434 | return sm; | ||
435 | } | ||
436 | EXPORT_SYMBOL_GPL(dm_sm_checker_create); | ||
437 | |||
438 | struct dm_space_map *dm_sm_checker_create_fresh(struct dm_space_map *sm) | ||
439 | { | ||
440 | return sm; | ||
441 | } | ||
442 | EXPORT_SYMBOL_GPL(dm_sm_checker_create_fresh); | ||
443 | |||
444 | /*----------------------------------------------------------------*/ | ||
445 | |||
446 | #endif | ||
diff --git a/drivers/md/persistent-data/dm-space-map-checker.h b/drivers/md/persistent-data/dm-space-map-checker.h deleted file mode 100644 index 444dccf6688c..000000000000 --- a/drivers/md/persistent-data/dm-space-map-checker.h +++ /dev/null | |||
@@ -1,26 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Red Hat, Inc. | ||
3 | * | ||
4 | * This file is released under the GPL. | ||
5 | */ | ||
6 | |||
7 | #ifndef SNAPSHOTS_SPACE_MAP_CHECKER_H | ||
8 | #define SNAPSHOTS_SPACE_MAP_CHECKER_H | ||
9 | |||
10 | #include "dm-space-map.h" | ||
11 | |||
12 | /*----------------------------------------------------------------*/ | ||
13 | |||
14 | /* | ||
15 | * This space map wraps a real on-disk space map, and verifies all of its | ||
16 | * operations. It uses a lot of memory, so only use if you have a specific | ||
17 | * problem that you're debugging. | ||
18 | * | ||
19 | * Ownership of @sm passes. | ||
20 | */ | ||
21 | struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm); | ||
22 | struct dm_space_map *dm_sm_checker_create_fresh(struct dm_space_map *sm); | ||
23 | |||
24 | /*----------------------------------------------------------------*/ | ||
25 | |||
26 | #endif | ||
diff --git a/drivers/md/persistent-data/dm-space-map-disk.c b/drivers/md/persistent-data/dm-space-map-disk.c index 3d0ed5332883..f6d29e614ab7 100644 --- a/drivers/md/persistent-data/dm-space-map-disk.c +++ b/drivers/md/persistent-data/dm-space-map-disk.c | |||
@@ -4,7 +4,6 @@ | |||
4 | * This file is released under the GPL. | 4 | * This file is released under the GPL. |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include "dm-space-map-checker.h" | ||
8 | #include "dm-space-map-common.h" | 7 | #include "dm-space-map-common.h" |
9 | #include "dm-space-map-disk.h" | 8 | #include "dm-space-map-disk.h" |
10 | #include "dm-space-map.h" | 9 | #include "dm-space-map.h" |
@@ -252,9 +251,8 @@ static struct dm_space_map ops = { | |||
252 | .copy_root = sm_disk_copy_root | 251 | .copy_root = sm_disk_copy_root |
253 | }; | 252 | }; |
254 | 253 | ||
255 | static struct dm_space_map *dm_sm_disk_create_real( | 254 | struct dm_space_map *dm_sm_disk_create(struct dm_transaction_manager *tm, |
256 | struct dm_transaction_manager *tm, | 255 | dm_block_t nr_blocks) |
257 | dm_block_t nr_blocks) | ||
258 | { | 256 | { |
259 | int r; | 257 | int r; |
260 | struct sm_disk *smd; | 258 | struct sm_disk *smd; |
@@ -285,27 +283,10 @@ bad: | |||
285 | kfree(smd); | 283 | kfree(smd); |
286 | return ERR_PTR(r); | 284 | return ERR_PTR(r); |
287 | } | 285 | } |
288 | |||
289 | struct dm_space_map *dm_sm_disk_create(struct dm_transaction_manager *tm, | ||
290 | dm_block_t nr_blocks) | ||
291 | { | ||
292 | struct dm_space_map *sm = dm_sm_disk_create_real(tm, nr_blocks); | ||
293 | struct dm_space_map *smc; | ||
294 | |||
295 | if (IS_ERR_OR_NULL(sm)) | ||
296 | return sm; | ||
297 | |||
298 | smc = dm_sm_checker_create_fresh(sm); | ||
299 | if (IS_ERR(smc)) | ||
300 | dm_sm_destroy(sm); | ||
301 | |||
302 | return smc; | ||
303 | } | ||
304 | EXPORT_SYMBOL_GPL(dm_sm_disk_create); | 286 | EXPORT_SYMBOL_GPL(dm_sm_disk_create); |
305 | 287 | ||
306 | static struct dm_space_map *dm_sm_disk_open_real( | 288 | struct dm_space_map *dm_sm_disk_open(struct dm_transaction_manager *tm, |
307 | struct dm_transaction_manager *tm, | 289 | void *root_le, size_t len) |
308 | void *root_le, size_t len) | ||
309 | { | 290 | { |
310 | int r; | 291 | int r; |
311 | struct sm_disk *smd; | 292 | struct sm_disk *smd; |
@@ -332,13 +313,6 @@ bad: | |||
332 | kfree(smd); | 313 | kfree(smd); |
333 | return ERR_PTR(r); | 314 | return ERR_PTR(r); |
334 | } | 315 | } |
335 | |||
336 | struct dm_space_map *dm_sm_disk_open(struct dm_transaction_manager *tm, | ||
337 | void *root_le, size_t len) | ||
338 | { | ||
339 | return dm_sm_checker_create( | ||
340 | dm_sm_disk_open_real(tm, root_le, len)); | ||
341 | } | ||
342 | EXPORT_SYMBOL_GPL(dm_sm_disk_open); | 316 | EXPORT_SYMBOL_GPL(dm_sm_disk_open); |
343 | 317 | ||
344 | /*----------------------------------------------------------------*/ | 318 | /*----------------------------------------------------------------*/ |
diff --git a/drivers/md/persistent-data/dm-transaction-manager.c b/drivers/md/persistent-data/dm-transaction-manager.c index e5604b32d91f..86c3705052a4 100644 --- a/drivers/md/persistent-data/dm-transaction-manager.c +++ b/drivers/md/persistent-data/dm-transaction-manager.c | |||
@@ -5,7 +5,6 @@ | |||
5 | */ | 5 | */ |
6 | #include "dm-transaction-manager.h" | 6 | #include "dm-transaction-manager.h" |
7 | #include "dm-space-map.h" | 7 | #include "dm-space-map.h" |
8 | #include "dm-space-map-checker.h" | ||
9 | #include "dm-space-map-disk.h" | 8 | #include "dm-space-map-disk.h" |
10 | #include "dm-space-map-metadata.h" | 9 | #include "dm-space-map-metadata.h" |
11 | #include "dm-persistent-data-internal.h" | 10 | #include "dm-persistent-data-internal.h" |
@@ -319,15 +318,14 @@ static int dm_tm_create_internal(struct dm_block_manager *bm, | |||
319 | int create) | 318 | int create) |
320 | { | 319 | { |
321 | int r; | 320 | int r; |
322 | struct dm_space_map *inner; | ||
323 | 321 | ||
324 | inner = dm_sm_metadata_init(); | 322 | *sm = dm_sm_metadata_init(); |
325 | if (IS_ERR(inner)) | 323 | if (IS_ERR(*sm)) |
326 | return PTR_ERR(inner); | 324 | return PTR_ERR(*sm); |
327 | 325 | ||
328 | *tm = dm_tm_create(bm, inner); | 326 | *tm = dm_tm_create(bm, *sm); |
329 | if (IS_ERR(*tm)) { | 327 | if (IS_ERR(*tm)) { |
330 | dm_sm_destroy(inner); | 328 | dm_sm_destroy(*sm); |
331 | return PTR_ERR(*tm); | 329 | return PTR_ERR(*tm); |
332 | } | 330 | } |
333 | 331 | ||
@@ -339,19 +337,13 @@ static int dm_tm_create_internal(struct dm_block_manager *bm, | |||
339 | goto bad1; | 337 | goto bad1; |
340 | } | 338 | } |
341 | 339 | ||
342 | r = dm_sm_metadata_create(inner, *tm, dm_bm_nr_blocks(bm), | 340 | r = dm_sm_metadata_create(*sm, *tm, dm_bm_nr_blocks(bm), |
343 | sb_location); | 341 | sb_location); |
344 | if (r) { | 342 | if (r) { |
345 | DMERR("couldn't create metadata space map"); | 343 | DMERR("couldn't create metadata space map"); |
346 | goto bad2; | 344 | goto bad2; |
347 | } | 345 | } |
348 | 346 | ||
349 | *sm = dm_sm_checker_create(inner); | ||
350 | if (IS_ERR(*sm)) { | ||
351 | r = PTR_ERR(*sm); | ||
352 | goto bad2; | ||
353 | } | ||
354 | |||
355 | } else { | 347 | } else { |
356 | r = dm_bm_write_lock(dm_tm_get_bm(*tm), sb_location, | 348 | r = dm_bm_write_lock(dm_tm_get_bm(*tm), sb_location, |
357 | sb_validator, sblock); | 349 | sb_validator, sblock); |
@@ -360,19 +352,13 @@ static int dm_tm_create_internal(struct dm_block_manager *bm, | |||
360 | goto bad1; | 352 | goto bad1; |
361 | } | 353 | } |
362 | 354 | ||
363 | r = dm_sm_metadata_open(inner, *tm, | 355 | r = dm_sm_metadata_open(*sm, *tm, |
364 | dm_block_data(*sblock) + root_offset, | 356 | dm_block_data(*sblock) + root_offset, |
365 | root_max_len); | 357 | root_max_len); |
366 | if (r) { | 358 | if (r) { |
367 | DMERR("couldn't open metadata space map"); | 359 | DMERR("couldn't open metadata space map"); |
368 | goto bad2; | 360 | goto bad2; |
369 | } | 361 | } |
370 | |||
371 | *sm = dm_sm_checker_create(inner); | ||
372 | if (IS_ERR(*sm)) { | ||
373 | r = PTR_ERR(*sm); | ||
374 | goto bad2; | ||
375 | } | ||
376 | } | 362 | } |
377 | 363 | ||
378 | return 0; | 364 | return 0; |
@@ -381,7 +367,6 @@ bad2: | |||
381 | dm_tm_unlock(*tm, *sblock); | 367 | dm_tm_unlock(*tm, *sblock); |
382 | bad1: | 368 | bad1: |
383 | dm_tm_destroy(*tm); | 369 | dm_tm_destroy(*tm); |
384 | dm_sm_destroy(inner); | ||
385 | return r; | 370 | return r; |
386 | } | 371 | } |
387 | 372 | ||