Skip to content

Commit 5df96f2

Browse files
Mikulas Patockasnitm
authored andcommitted
dm integrity: fix integrity recalculation that is improperly skipped
Commit adc0daa ("dm: report suspended device during destroy") broke integrity recalculation. The problem is dm_suspended() returns true not only during suspend, but also during resume. So this race condition could occur: 1. dm_integrity_resume calls queue_work(ic->recalc_wq, &ic->recalc_work) 2. integrity_recalc (&ic->recalc_work) preempts the current thread 3. integrity_recalc calls if (unlikely(dm_suspended(ic->ti))) goto unlock_ret; 4. integrity_recalc exits and no recalculating is done. To fix this race condition, add a function dm_post_suspending that is only true during the postsuspend phase and use it instead of dm_suspended(). Signed-off-by: Mikulas Patocka <mpatocka redhat com> Fixes: adc0daa ("dm: report suspended device during destroy") Cc: stable vger kernel org # v4.18+ Signed-off-by: Mike Snitzer <[email protected]>
1 parent 6958c1c commit 5df96f2

File tree

3 files changed

+20
-2
lines changed

3 files changed

+20
-2
lines changed

drivers/md/dm-integrity.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2420,7 +2420,7 @@ static void integrity_writer(struct work_struct *w)
24202420
unsigned prev_free_sectors;
24212421

24222422
/* the following test is not needed, but it tests the replay code */
2423-
if (unlikely(dm_suspended(ic->ti)) && !ic->meta_dev)
2423+
if (unlikely(dm_post_suspending(ic->ti)) && !ic->meta_dev)
24242424
return;
24252425

24262426
spin_lock_irq(&ic->endio_wait.lock);
@@ -2481,7 +2481,7 @@ static void integrity_recalc(struct work_struct *w)
24812481

24822482
next_chunk:
24832483

2484-
if (unlikely(dm_suspended(ic->ti)))
2484+
if (unlikely(dm_post_suspending(ic->ti)))
24852485
goto unlock_ret;
24862486

24872487
range.logical_sector = le64_to_cpu(ic->sb->recalc_sector);

drivers/md/dm.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ EXPORT_SYMBOL_GPL(dm_bio_get_target_bio_nr);
143143
#define DMF_NOFLUSH_SUSPENDING 5
144144
#define DMF_DEFERRED_REMOVE 6
145145
#define DMF_SUSPENDED_INTERNALLY 7
146+
#define DMF_POST_SUSPENDING 8
146147

147148
#define DM_NUMA_NODE NUMA_NO_NODE
148149
static int dm_numa_node = DM_NUMA_NODE;
@@ -2408,6 +2409,7 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
24082409
if (!dm_suspended_md(md)) {
24092410
dm_table_presuspend_targets(map);
24102411
set_bit(DMF_SUSPENDED, &md->flags);
2412+
set_bit(DMF_POST_SUSPENDING, &md->flags);
24112413
dm_table_postsuspend_targets(map);
24122414
}
24132415
/* dm_put_live_table must be before msleep, otherwise deadlock is possible */
@@ -2766,7 +2768,9 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
27662768
if (r)
27672769
goto out_unlock;
27682770

2771+
set_bit(DMF_POST_SUSPENDING, &md->flags);
27692772
dm_table_postsuspend_targets(map);
2773+
clear_bit(DMF_POST_SUSPENDING, &md->flags);
27702774

27712775
out_unlock:
27722776
mutex_unlock(&md->suspend_lock);
@@ -2863,7 +2867,9 @@ static void __dm_internal_suspend(struct mapped_device *md, unsigned suspend_fla
28632867
(void) __dm_suspend(md, map, suspend_flags, TASK_UNINTERRUPTIBLE,
28642868
DMF_SUSPENDED_INTERNALLY);
28652869

2870+
set_bit(DMF_POST_SUSPENDING, &md->flags);
28662871
dm_table_postsuspend_targets(map);
2872+
clear_bit(DMF_POST_SUSPENDING, &md->flags);
28672873
}
28682874

28692875
static void __dm_internal_resume(struct mapped_device *md)
@@ -3024,6 +3030,11 @@ int dm_suspended_md(struct mapped_device *md)
30243030
return test_bit(DMF_SUSPENDED, &md->flags);
30253031
}
30263032

3033+
static int dm_post_suspending_md(struct mapped_device *md)
3034+
{
3035+
return test_bit(DMF_POST_SUSPENDING, &md->flags);
3036+
}
3037+
30273038
int dm_suspended_internally_md(struct mapped_device *md)
30283039
{
30293040
return test_bit(DMF_SUSPENDED_INTERNALLY, &md->flags);
@@ -3040,6 +3051,12 @@ int dm_suspended(struct dm_target *ti)
30403051
}
30413052
EXPORT_SYMBOL_GPL(dm_suspended);
30423053

3054+
int dm_post_suspending(struct dm_target *ti)
3055+
{
3056+
return dm_post_suspending_md(dm_table_get_md(ti->table));
3057+
}
3058+
EXPORT_SYMBOL_GPL(dm_post_suspending);
3059+
30433060
int dm_noflush_suspending(struct dm_target *ti)
30443061
{
30453062
return __noflush_suspending(dm_table_get_md(ti->table));

include/linux/device-mapper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ const char *dm_device_name(struct mapped_device *md);
426426
int dm_copy_name_and_uuid(struct mapped_device *md, char *name, char *uuid);
427427
struct gendisk *dm_disk(struct mapped_device *md);
428428
int dm_suspended(struct dm_target *ti);
429+
int dm_post_suspending(struct dm_target *ti);
429430
int dm_noflush_suspending(struct dm_target *ti);
430431
void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors);
431432
union map_info *dm_get_rq_mapinfo(struct request *rq);

0 commit comments

Comments
 (0)