aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2015-02-26 11:41:28 -0500
committerMike Snitzer <snitzer@redhat.com>2015-02-27 14:53:16 -0500
commit09ee96b21456883e108c3b00597bb37ec512151b (patch)
tree76127a2e0766158b04c2b764e9e23fcd49127ccc
parentb735fede8d957d9d255e9c5cf3964cfa59799637 (diff)
dm snapshot: suspend merging snapshot when doing exception handover
The "dm snapshot: suspend origin when doing exception handover" commit fixed a exception store handover bug associated with pending exceptions to the "snapshot-origin" target. However, a similar problem exists in snapshot merging. When snapshot merging is in progress, we use the target "snapshot-merge" instead of "snapshot-origin". Consequently, during exception store handover, we must find the snapshot-merge target and suspend its associated mapped_device. To avoid lockdep warnings, the target must be suspended and resumed without holding _origins_lock. Introduce a dm_hold() function that grabs a reference on a mapped_device, but unlike dm_get(), it doesn't crash if the device has the DMF_FREEING flag set, it returns an error in this case. In snapshot_resume() we grab the reference to the origin device using dm_hold() while holding _origins_lock (_origins_lock guarantees that the device won't disappear). Then we release _origins_lock, suspend the device and grab _origins_lock again. NOTE to stable@ people: When backporting to kernels 3.18 and older, use dm_internal_suspend and dm_internal_resume instead of dm_internal_suspend_fast and dm_internal_resume_fast. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com> Cc: stable@vger.kernel.org
-rw-r--r--drivers/md/dm-snap.c35
-rw-r--r--drivers/md/dm.c13
-rw-r--r--include/linux/device-mapper.h1
3 files changed, 43 insertions, 6 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index c2bf822bad6f..f83a0f3fc365 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -1888,20 +1888,39 @@ static int snapshot_preresume(struct dm_target *ti)
1888static void snapshot_resume(struct dm_target *ti) 1888static void snapshot_resume(struct dm_target *ti)
1889{ 1889{
1890 struct dm_snapshot *s = ti->private; 1890 struct dm_snapshot *s = ti->private;
1891 struct dm_snapshot *snap_src = NULL, *snap_dest = NULL; 1891 struct dm_snapshot *snap_src = NULL, *snap_dest = NULL, *snap_merging = NULL;
1892 struct dm_origin *o; 1892 struct dm_origin *o;
1893 struct mapped_device *origin_md = NULL; 1893 struct mapped_device *origin_md = NULL;
1894 bool must_restart_merging = false;
1894 1895
1895 down_read(&_origins_lock); 1896 down_read(&_origins_lock);
1896 1897
1897 o = __lookup_dm_origin(s->origin->bdev); 1898 o = __lookup_dm_origin(s->origin->bdev);
1898 if (o) 1899 if (o)
1899 origin_md = dm_table_get_md(o->ti->table); 1900 origin_md = dm_table_get_md(o->ti->table);
1901 if (!origin_md) {
1902 (void) __find_snapshots_sharing_cow(s, NULL, NULL, &snap_merging);
1903 if (snap_merging)
1904 origin_md = dm_table_get_md(snap_merging->ti->table);
1905 }
1900 if (origin_md == dm_table_get_md(ti->table)) 1906 if (origin_md == dm_table_get_md(ti->table))
1901 origin_md = NULL; 1907 origin_md = NULL;
1908 if (origin_md) {
1909 if (dm_hold(origin_md))
1910 origin_md = NULL;
1911 }
1902 1912
1903 if (origin_md) 1913 up_read(&_origins_lock);
1914
1915 if (origin_md) {
1904 dm_internal_suspend_fast(origin_md); 1916 dm_internal_suspend_fast(origin_md);
1917 if (snap_merging && test_bit(RUNNING_MERGE, &snap_merging->state_bits)) {
1918 must_restart_merging = true;
1919 stop_merge(snap_merging);
1920 }
1921 }
1922
1923 down_read(&_origins_lock);
1905 1924
1906 (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL); 1925 (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
1907 if (snap_src && snap_dest) { 1926 if (snap_src && snap_dest) {
@@ -1912,11 +1931,15 @@ static void snapshot_resume(struct dm_target *ti)
1912 up_write(&snap_src->lock); 1931 up_write(&snap_src->lock);
1913 } 1932 }
1914 1933
1915 if (origin_md)
1916 dm_internal_resume_fast(origin_md);
1917
1918 up_read(&_origins_lock); 1934 up_read(&_origins_lock);
1919 1935
1936 if (origin_md) {
1937 if (must_restart_merging)
1938 start_merge(snap_merging);
1939 dm_internal_resume_fast(origin_md);
1940 dm_put(origin_md);
1941 }
1942
1920 /* Now we have correct chunk size, reregister */ 1943 /* Now we have correct chunk size, reregister */
1921 reregister_snapshot(s); 1944 reregister_snapshot(s);
1922 1945
@@ -2360,7 +2383,7 @@ static struct target_type snapshot_target = {
2360 2383
2361static struct target_type merge_target = { 2384static struct target_type merge_target = {
2362 .name = dm_snapshot_merge_target_name, 2385 .name = dm_snapshot_merge_target_name,
2363 .version = {1, 2, 0}, 2386 .version = {1, 3, 0},
2364 .module = THIS_MODULE, 2387 .module = THIS_MODULE,
2365 .ctr = snapshot_ctr, 2388 .ctr = snapshot_ctr,
2366 .dtr = snapshot_dtr, 2389 .dtr = snapshot_dtr,
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 6e2b2e97abe9..9b641b38b857 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -2616,6 +2616,19 @@ void dm_get(struct mapped_device *md)
2616 BUG_ON(test_bit(DMF_FREEING, &md->flags)); 2616 BUG_ON(test_bit(DMF_FREEING, &md->flags));
2617} 2617}
2618 2618
2619int dm_hold(struct mapped_device *md)
2620{
2621 spin_lock(&_minor_lock);
2622 if (test_bit(DMF_FREEING, &md->flags)) {
2623 spin_unlock(&_minor_lock);
2624 return -EBUSY;
2625 }
2626 dm_get(md);
2627 spin_unlock(&_minor_lock);
2628 return 0;
2629}
2630EXPORT_SYMBOL_GPL(dm_hold);
2631
2619const char *dm_device_name(struct mapped_device *md) 2632const char *dm_device_name(struct mapped_device *md)
2620{ 2633{
2621 return md->name; 2634 return md->name;
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 2646aed1d3fe..fd23978d93fe 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -375,6 +375,7 @@ int dm_create(int minor, struct mapped_device **md);
375 */ 375 */
376struct mapped_device *dm_get_md(dev_t dev); 376struct mapped_device *dm_get_md(dev_t dev);
377void dm_get(struct mapped_device *md); 377void dm_get(struct mapped_device *md);
378int dm_hold(struct mapped_device *md);
378void dm_put(struct mapped_device *md); 379void dm_put(struct mapped_device *md);
379 380
380/* 381/*