Skip to content

Commit 09ee96b

Browse files
Mikulas Patockasnitm
authored andcommitted
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
1 parent b735fed commit 09ee96b

File tree

3 files changed

+43
-6
lines changed

3 files changed

+43
-6
lines changed

drivers/md/dm-snap.c

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1888,20 +1888,39 @@ static int snapshot_preresume(struct dm_target *ti)
18881888
static void snapshot_resume(struct dm_target *ti)
18891889
{
18901890
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;
18921892
struct dm_origin *o;
18931893
struct mapped_device *origin_md = NULL;
1894+
bool must_restart_merging = false;
18941895

18951896
down_read(&_origins_lock);
18961897

18971898
o = __lookup_dm_origin(s->origin->bdev);
18981899
if (o)
18991900
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+
}
19001906
if (origin_md == dm_table_get_md(ti->table))
19011907
origin_md = NULL;
1908+
if (origin_md) {
1909+
if (dm_hold(origin_md))
1910+
origin_md = NULL;
1911+
}
19021912

1903-
if (origin_md)
1913+
up_read(&_origins_lock);
1914+
1915+
if (origin_md) {
19041916
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);
19051924

19061925
(void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
19071926
if (snap_src && snap_dest) {
@@ -1912,11 +1931,15 @@ static void snapshot_resume(struct dm_target *ti)
19121931
up_write(&snap_src->lock);
19131932
}
19141933

1915-
if (origin_md)
1916-
dm_internal_resume_fast(origin_md);
1917-
19181934
up_read(&_origins_lock);
19191935

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+
19201943
/* Now we have correct chunk size, reregister */
19211944
reregister_snapshot(s);
19221945

@@ -2360,7 +2383,7 @@ static struct target_type snapshot_target = {
23602383

23612384
static struct target_type merge_target = {
23622385
.name = dm_snapshot_merge_target_name,
2363-
.version = {1, 2, 0},
2386+
.version = {1, 3, 0},
23642387
.module = THIS_MODULE,
23652388
.ctr = snapshot_ctr,
23662389
.dtr = snapshot_dtr,

drivers/md/dm.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2616,6 +2616,19 @@ void dm_get(struct mapped_device *md)
26162616
BUG_ON(test_bit(DMF_FREEING, &md->flags));
26172617
}
26182618

2619+
int 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+
}
2630+
EXPORT_SYMBOL_GPL(dm_hold);
2631+
26192632
const char *dm_device_name(struct mapped_device *md)
26202633
{
26212634
return md->name;

include/linux/device-mapper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ int dm_create(int minor, struct mapped_device **md);
375375
*/
376376
struct mapped_device *dm_get_md(dev_t dev);
377377
void dm_get(struct mapped_device *md);
378+
int dm_hold(struct mapped_device *md);
378379
void dm_put(struct mapped_device *md);
379380

380381
/*

0 commit comments

Comments
 (0)