diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-10-09 19:58:11 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-10-09 19:58:11 -0400 |
| commit | 0444555670350b419496686f4012b9cef808c105 (patch) | |
| tree | e9f20837bc0772829c6585ef21d70ee510a0e172 | |
| parent | 175d58cfed70f132b8d4df39e19267ad6094bd16 (diff) | |
| parent | b0d3cc011e532d8c9db76cf717bcafa53c135595 (diff) | |
Merge tag 'dm-4.3-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm
Pull dm fixes from Mike Snitzer:
"Three stable fixes:
- DM core AB-BA deadlock fix in the device destruction path (vs
device creation's DM table swap).
- DM raid fix to properly round up the region_size to the next
power-of-2.
- DM cache fix for a NULL pointer seen while switching from the
"cleaner" cache policy.
Two fixes for regressions introduced during the 4.3 merge:
- request-based DM error propagation regressed due to incorrect
changes introduced when adding the bi_error field to bio.
- DM snapshot fix to only support snapshots that overflow if the
client (e.g. lvm2) is prepared to deal with the associated
snapshot status interface change"
* tag 'dm-4.3-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
dm snapshot: add new persistent store option to support overflow
dm cache: fix NULL pointer when switching from cleaner policy
dm: fix request-based dm error reporting
dm raid: fix round up of default region size
dm: fix AB-BA deadlock in __dm_destroy()
| -rw-r--r-- | Documentation/device-mapper/snapshot.txt | 10 | ||||
| -rw-r--r-- | drivers/md/dm-cache-policy-cleaner.c | 2 | ||||
| -rw-r--r-- | drivers/md/dm-exception-store.c | 6 | ||||
| -rw-r--r-- | drivers/md/dm-exception-store.h | 5 | ||||
| -rw-r--r-- | drivers/md/dm-raid.c | 3 | ||||
| -rw-r--r-- | drivers/md/dm-snap-persistent.c | 17 | ||||
| -rw-r--r-- | drivers/md/dm-snap-transient.c | 3 | ||||
| -rw-r--r-- | drivers/md/dm-snap.c | 14 | ||||
| -rw-r--r-- | drivers/md/dm.c | 11 |
9 files changed, 44 insertions, 27 deletions
diff --git a/Documentation/device-mapper/snapshot.txt b/Documentation/device-mapper/snapshot.txt index 0d5bc46dc167..ad6949bff2e3 100644 --- a/Documentation/device-mapper/snapshot.txt +++ b/Documentation/device-mapper/snapshot.txt | |||
| @@ -41,9 +41,13 @@ useless and be disabled, returning errors. So it is important to monitor | |||
| 41 | the amount of free space and expand the <COW device> before it fills up. | 41 | the amount of free space and expand the <COW device> before it fills up. |
| 42 | 42 | ||
| 43 | <persistent?> is P (Persistent) or N (Not persistent - will not survive | 43 | <persistent?> is P (Persistent) or N (Not persistent - will not survive |
| 44 | after reboot). | 44 | after reboot). O (Overflow) can be added as a persistent store option |
| 45 | The difference is that for transient snapshots less metadata must be | 45 | to allow userspace to advertise its support for seeing "Overflow" in the |
| 46 | saved on disk - they can be kept in memory by the kernel. | 46 | snapshot status. So supported store types are "P", "PO" and "N". |
| 47 | |||
| 48 | The difference between persistent and transient is with transient | ||
| 49 | snapshots less metadata must be saved on disk - they can be kept in | ||
| 50 | memory by the kernel. | ||
| 47 | 51 | ||
| 48 | 52 | ||
| 49 | * snapshot-merge <origin> <COW device> <persistent> <chunksize> | 53 | * snapshot-merge <origin> <COW device> <persistent> <chunksize> |
diff --git a/drivers/md/dm-cache-policy-cleaner.c b/drivers/md/dm-cache-policy-cleaner.c index 240c9f0e85e7..8a096456579b 100644 --- a/drivers/md/dm-cache-policy-cleaner.c +++ b/drivers/md/dm-cache-policy-cleaner.c | |||
| @@ -436,7 +436,7 @@ static struct dm_cache_policy *wb_create(dm_cblock_t cache_size, | |||
| 436 | static struct dm_cache_policy_type wb_policy_type = { | 436 | static struct dm_cache_policy_type wb_policy_type = { |
| 437 | .name = "cleaner", | 437 | .name = "cleaner", |
| 438 | .version = {1, 0, 0}, | 438 | .version = {1, 0, 0}, |
| 439 | .hint_size = 0, | 439 | .hint_size = 4, |
| 440 | .owner = THIS_MODULE, | 440 | .owner = THIS_MODULE, |
| 441 | .create = wb_create | 441 | .create = wb_create |
| 442 | }; | 442 | }; |
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index ebaa4f803eec..192bb8beeb6b 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c | |||
| @@ -203,7 +203,7 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv, | |||
| 203 | return -EINVAL; | 203 | return -EINVAL; |
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL); | 206 | tmp_store = kzalloc(sizeof(*tmp_store), GFP_KERNEL); |
| 207 | if (!tmp_store) { | 207 | if (!tmp_store) { |
| 208 | ti->error = "Exception store allocation failed"; | 208 | ti->error = "Exception store allocation failed"; |
| 209 | return -ENOMEM; | 209 | return -ENOMEM; |
| @@ -215,7 +215,7 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv, | |||
| 215 | else if (persistent == 'N') | 215 | else if (persistent == 'N') |
| 216 | type = get_type("N"); | 216 | type = get_type("N"); |
| 217 | else { | 217 | else { |
| 218 | ti->error = "Persistent flag is not P or N"; | 218 | ti->error = "Exception store type is not P or N"; |
| 219 | r = -EINVAL; | 219 | r = -EINVAL; |
| 220 | goto bad_type; | 220 | goto bad_type; |
| 221 | } | 221 | } |
| @@ -233,7 +233,7 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv, | |||
| 233 | if (r) | 233 | if (r) |
| 234 | goto bad; | 234 | goto bad; |
| 235 | 235 | ||
| 236 | r = type->ctr(tmp_store, 0, NULL); | 236 | r = type->ctr(tmp_store, (strlen(argv[0]) > 1 ? &argv[0][1] : NULL)); |
| 237 | if (r) { | 237 | if (r) { |
| 238 | ti->error = "Exception store type constructor failed"; | 238 | ti->error = "Exception store type constructor failed"; |
| 239 | goto bad; | 239 | goto bad; |
diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h index 0b2536247cf5..fae34e7a0b1e 100644 --- a/drivers/md/dm-exception-store.h +++ b/drivers/md/dm-exception-store.h | |||
| @@ -42,8 +42,7 @@ struct dm_exception_store_type { | |||
| 42 | const char *name; | 42 | const char *name; |
| 43 | struct module *module; | 43 | struct module *module; |
| 44 | 44 | ||
| 45 | int (*ctr) (struct dm_exception_store *store, | 45 | int (*ctr) (struct dm_exception_store *store, char *options); |
| 46 | unsigned argc, char **argv); | ||
| 47 | 46 | ||
| 48 | /* | 47 | /* |
| 49 | * Destroys this object when you've finished with it. | 48 | * Destroys this object when you've finished with it. |
| @@ -123,6 +122,8 @@ struct dm_exception_store { | |||
| 123 | unsigned chunk_shift; | 122 | unsigned chunk_shift; |
| 124 | 123 | ||
| 125 | void *context; | 124 | void *context; |
| 125 | |||
| 126 | bool userspace_supports_overflow; | ||
| 126 | }; | 127 | }; |
| 127 | 128 | ||
| 128 | /* | 129 | /* |
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 97e165183e79..a0901214aef5 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c | |||
| @@ -329,8 +329,7 @@ static int validate_region_size(struct raid_set *rs, unsigned long region_size) | |||
| 329 | */ | 329 | */ |
| 330 | if (min_region_size > (1 << 13)) { | 330 | if (min_region_size > (1 << 13)) { |
| 331 | /* If not a power of 2, make it the next power of 2 */ | 331 | /* If not a power of 2, make it the next power of 2 */ |
| 332 | if (min_region_size & (min_region_size - 1)) | 332 | region_size = roundup_pow_of_two(min_region_size); |
| 333 | region_size = 1 << fls(region_size); | ||
| 334 | DMINFO("Choosing default region size of %lu sectors", | 333 | DMINFO("Choosing default region size of %lu sectors", |
| 335 | region_size); | 334 | region_size); |
| 336 | } else { | 335 | } else { |
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index bf71583296f7..aeacad9be51d 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | #include "dm-exception-store.h" | 8 | #include "dm-exception-store.h" |
| 9 | 9 | ||
| 10 | #include <linux/ctype.h> | ||
| 10 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
| 11 | #include <linux/pagemap.h> | 12 | #include <linux/pagemap.h> |
| 12 | #include <linux/vmalloc.h> | 13 | #include <linux/vmalloc.h> |
| @@ -843,8 +844,7 @@ static void persistent_drop_snapshot(struct dm_exception_store *store) | |||
| 843 | DMWARN("write header failed"); | 844 | DMWARN("write header failed"); |
| 844 | } | 845 | } |
| 845 | 846 | ||
| 846 | static int persistent_ctr(struct dm_exception_store *store, | 847 | static int persistent_ctr(struct dm_exception_store *store, char *options) |
| 847 | unsigned argc, char **argv) | ||
| 848 | { | 848 | { |
| 849 | struct pstore *ps; | 849 | struct pstore *ps; |
| 850 | 850 | ||
| @@ -873,6 +873,16 @@ static int persistent_ctr(struct dm_exception_store *store, | |||
| 873 | return -ENOMEM; | 873 | return -ENOMEM; |
| 874 | } | 874 | } |
| 875 | 875 | ||
| 876 | if (options) { | ||
| 877 | char overflow = toupper(options[0]); | ||
| 878 | if (overflow == 'O') | ||
| 879 | store->userspace_supports_overflow = true; | ||
| 880 | else { | ||
| 881 | DMERR("Unsupported persistent store option: %s", options); | ||
| 882 | return -EINVAL; | ||
| 883 | } | ||
| 884 | } | ||
| 885 | |||
| 876 | store->context = ps; | 886 | store->context = ps; |
| 877 | 887 | ||
| 878 | return 0; | 888 | return 0; |
| @@ -888,7 +898,8 @@ static unsigned persistent_status(struct dm_exception_store *store, | |||
| 888 | case STATUSTYPE_INFO: | 898 | case STATUSTYPE_INFO: |
| 889 | break; | 899 | break; |
| 890 | case STATUSTYPE_TABLE: | 900 | case STATUSTYPE_TABLE: |
| 891 | DMEMIT(" P %llu", (unsigned long long)store->chunk_size); | 901 | DMEMIT(" %s %llu", store->userspace_supports_overflow ? "PO" : "P", |
| 902 | (unsigned long long)store->chunk_size); | ||
| 892 | } | 903 | } |
| 893 | 904 | ||
| 894 | return sz; | 905 | return sz; |
diff --git a/drivers/md/dm-snap-transient.c b/drivers/md/dm-snap-transient.c index 1ce9a2586e41..9b7c8c8049d6 100644 --- a/drivers/md/dm-snap-transient.c +++ b/drivers/md/dm-snap-transient.c | |||
| @@ -70,8 +70,7 @@ static void transient_usage(struct dm_exception_store *store, | |||
| 70 | *metadata_sectors = 0; | 70 | *metadata_sectors = 0; |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | static int transient_ctr(struct dm_exception_store *store, | 73 | static int transient_ctr(struct dm_exception_store *store, char *options) |
| 74 | unsigned argc, char **argv) | ||
| 75 | { | 74 | { |
| 76 | struct transient_c *tc; | 75 | struct transient_c *tc; |
| 77 | 76 | ||
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index c0bcd6516dfe..c06b74e91cd6 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
| @@ -1098,7 +1098,7 @@ static void stop_merge(struct dm_snapshot *s) | |||
| 1098 | } | 1098 | } |
| 1099 | 1099 | ||
| 1100 | /* | 1100 | /* |
| 1101 | * Construct a snapshot mapping: <origin_dev> <COW-dev> <p/n> <chunk-size> | 1101 | * Construct a snapshot mapping: <origin_dev> <COW-dev> <p|po|n> <chunk-size> |
| 1102 | */ | 1102 | */ |
| 1103 | static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | 1103 | static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) |
| 1104 | { | 1104 | { |
| @@ -1302,6 +1302,7 @@ static void __handover_exceptions(struct dm_snapshot *snap_src, | |||
| 1302 | 1302 | ||
| 1303 | u.store_swap = snap_dest->store; | 1303 | u.store_swap = snap_dest->store; |
| 1304 | snap_dest->store = snap_src->store; | 1304 | snap_dest->store = snap_src->store; |
| 1305 | snap_dest->store->userspace_supports_overflow = u.store_swap->userspace_supports_overflow; | ||
| 1305 | snap_src->store = u.store_swap; | 1306 | snap_src->store = u.store_swap; |
| 1306 | 1307 | ||
| 1307 | snap_dest->store->snap = snap_dest; | 1308 | snap_dest->store->snap = snap_dest; |
| @@ -1739,8 +1740,11 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) | |||
| 1739 | 1740 | ||
| 1740 | pe = __find_pending_exception(s, pe, chunk); | 1741 | pe = __find_pending_exception(s, pe, chunk); |
| 1741 | if (!pe) { | 1742 | if (!pe) { |
| 1742 | s->snapshot_overflowed = 1; | 1743 | if (s->store->userspace_supports_overflow) { |
| 1743 | DMERR("Snapshot overflowed: Unable to allocate exception."); | 1744 | s->snapshot_overflowed = 1; |
| 1745 | DMERR("Snapshot overflowed: Unable to allocate exception."); | ||
| 1746 | } else | ||
| 1747 | __invalidate_snapshot(s, -ENOMEM); | ||
| 1744 | r = -EIO; | 1748 | r = -EIO; |
| 1745 | goto out_unlock; | 1749 | goto out_unlock; |
| 1746 | } | 1750 | } |
| @@ -2365,7 +2369,7 @@ static struct target_type origin_target = { | |||
| 2365 | 2369 | ||
| 2366 | static struct target_type snapshot_target = { | 2370 | static struct target_type snapshot_target = { |
| 2367 | .name = "snapshot", | 2371 | .name = "snapshot", |
| 2368 | .version = {1, 14, 0}, | 2372 | .version = {1, 15, 0}, |
| 2369 | .module = THIS_MODULE, | 2373 | .module = THIS_MODULE, |
| 2370 | .ctr = snapshot_ctr, | 2374 | .ctr = snapshot_ctr, |
| 2371 | .dtr = snapshot_dtr, | 2375 | .dtr = snapshot_dtr, |
| @@ -2379,7 +2383,7 @@ static struct target_type snapshot_target = { | |||
| 2379 | 2383 | ||
| 2380 | static struct target_type merge_target = { | 2384 | static struct target_type merge_target = { |
| 2381 | .name = dm_snapshot_merge_target_name, | 2385 | .name = dm_snapshot_merge_target_name, |
| 2382 | .version = {1, 3, 0}, | 2386 | .version = {1, 4, 0}, |
| 2383 | .module = THIS_MODULE, | 2387 | .module = THIS_MODULE, |
| 2384 | .ctr = snapshot_ctr, | 2388 | .ctr = snapshot_ctr, |
| 2385 | .dtr = snapshot_dtr, | 2389 | .dtr = snapshot_dtr, |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 6264781dc69a..1b5c6047e4f1 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
| @@ -1001,6 +1001,7 @@ static void end_clone_bio(struct bio *clone) | |||
| 1001 | struct dm_rq_target_io *tio = info->tio; | 1001 | struct dm_rq_target_io *tio = info->tio; |
| 1002 | struct bio *bio = info->orig; | 1002 | struct bio *bio = info->orig; |
| 1003 | unsigned int nr_bytes = info->orig->bi_iter.bi_size; | 1003 | unsigned int nr_bytes = info->orig->bi_iter.bi_size; |
| 1004 | int error = clone->bi_error; | ||
| 1004 | 1005 | ||
| 1005 | bio_put(clone); | 1006 | bio_put(clone); |
| 1006 | 1007 | ||
| @@ -1011,13 +1012,13 @@ static void end_clone_bio(struct bio *clone) | |||
| 1011 | * the remainder. | 1012 | * the remainder. |
| 1012 | */ | 1013 | */ |
| 1013 | return; | 1014 | return; |
| 1014 | else if (bio->bi_error) { | 1015 | else if (error) { |
| 1015 | /* | 1016 | /* |
| 1016 | * Don't notice the error to the upper layer yet. | 1017 | * Don't notice the error to the upper layer yet. |
| 1017 | * The error handling decision is made by the target driver, | 1018 | * The error handling decision is made by the target driver, |
| 1018 | * when the request is completed. | 1019 | * when the request is completed. |
| 1019 | */ | 1020 | */ |
| 1020 | tio->error = bio->bi_error; | 1021 | tio->error = error; |
| 1021 | return; | 1022 | return; |
| 1022 | } | 1023 | } |
| 1023 | 1024 | ||
| @@ -2837,8 +2838,6 @@ static void __dm_destroy(struct mapped_device *md, bool wait) | |||
| 2837 | 2838 | ||
| 2838 | might_sleep(); | 2839 | might_sleep(); |
| 2839 | 2840 | ||
| 2840 | map = dm_get_live_table(md, &srcu_idx); | ||
| 2841 | |||
| 2842 | spin_lock(&_minor_lock); | 2841 | spin_lock(&_minor_lock); |
| 2843 | idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md)))); | 2842 | idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md)))); |
| 2844 | set_bit(DMF_FREEING, &md->flags); | 2843 | set_bit(DMF_FREEING, &md->flags); |
| @@ -2852,14 +2851,14 @@ static void __dm_destroy(struct mapped_device *md, bool wait) | |||
| 2852 | * do not race with internal suspend. | 2851 | * do not race with internal suspend. |
| 2853 | */ | 2852 | */ |
| 2854 | mutex_lock(&md->suspend_lock); | 2853 | mutex_lock(&md->suspend_lock); |
| 2854 | map = dm_get_live_table(md, &srcu_idx); | ||
| 2855 | if (!dm_suspended_md(md)) { | 2855 | if (!dm_suspended_md(md)) { |
| 2856 | dm_table_presuspend_targets(map); | 2856 | dm_table_presuspend_targets(map); |
| 2857 | dm_table_postsuspend_targets(map); | 2857 | dm_table_postsuspend_targets(map); |
| 2858 | } | 2858 | } |
| 2859 | mutex_unlock(&md->suspend_lock); | ||
| 2860 | |||
| 2861 | /* dm_put_live_table must be before msleep, otherwise deadlock is possible */ | 2859 | /* dm_put_live_table must be before msleep, otherwise deadlock is possible */ |
| 2862 | dm_put_live_table(md, srcu_idx); | 2860 | dm_put_live_table(md, srcu_idx); |
| 2861 | mutex_unlock(&md->suspend_lock); | ||
| 2863 | 2862 | ||
| 2864 | /* | 2863 | /* |
| 2865 | * Rare, but there may be I/O requests still going to complete, | 2864 | * Rare, but there may be I/O requests still going to complete, |
