mirror of
https://github.com/torvalds/linux.git
synced 2024-12-24 11:51:27 +00:00
dm: fix narrow race for REQ_NOWAIT bios being issued despite no support
Starting with the commit 63a225c9fd20, device mapper has an optimization
that it will take cheaper table lock (dm_get_live_table_fast instead of
dm_get_live_table) if the bio has REQ_NOWAIT. The bios with REQ_NOWAIT
must not block in the target request routine, if they did, we would be
blocking while holding rcu_read_lock, which is prohibited.
The targets that are suitable for REQ_NOWAIT optimization (and that don't
block in the map routine) have the flag DM_TARGET_NOWAIT set. Device
mapper will test if all the targets and all the devices in a table
support nowait (see the function dm_table_supports_nowait) and it will set
or clear the QUEUE_FLAG_NOWAIT flag on its request queue according to
this check.
There's a test in submit_bio_noacct: "if ((bio->bi_opf & REQ_NOWAIT) &&
!blk_queue_nowait(q)) goto not_supported" - this will make sure that
REQ_NOWAIT bios can't enter a request queue that doesn't support them.
This mechanism works to prevent REQ_NOWAIT bios from reaching dm targets
that don't support the REQ_NOWAIT flag (and that may block in the map
routine) - except that there is a small race condition:
submit_bio_noacct checks if the queue has the QUEUE_FLAG_NOWAIT without
holding any locks. Immediatelly after this check, the device mapper table
may be reloaded with a table that doesn't support REQ_NOWAIT (for example,
if we start moving the logical volume or if we activate a snapshot).
However the REQ_NOWAIT bio that already passed the check in
submit_bio_noacct would be sent to device mapper, where it could be
redirected to a dm target that doesn't support REQ_NOWAIT - the result is
sleeping while we hold rcu_read_lock.
In order to fix this race, we double-check if the target supports
REQ_NOWAIT while we hold the table lock (so that the table can't change
under us).
Fixes: 563a225c9f
("dm: introduce dm_{get,put}_live_table_bio called from dm_submit_bio")
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
This commit is contained in:
parent
5d7362d0d5
commit
1ee88de395
@ -1613,7 +1613,12 @@ static blk_status_t __split_and_process_bio(struct clone_info *ci)
|
||||
ti = dm_table_find_target(ci->map, ci->sector);
|
||||
if (unlikely(!ti))
|
||||
return BLK_STS_IOERR;
|
||||
else if (unlikely(ci->is_abnormal_io))
|
||||
|
||||
if (unlikely((ci->bio->bi_opf & REQ_NOWAIT) != 0) &&
|
||||
unlikely(!dm_target_supports_nowait(ti->type)))
|
||||
return BLK_STS_NOTSUPP;
|
||||
|
||||
if (unlikely(ci->is_abnormal_io))
|
||||
return __process_abnormal_io(ci, ti);
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user