Commit 7dd06a25 authored by Mike Snitzer's avatar Mike Snitzer

dm: allow dm_accept_partial_bio() for dm_io without duplicate bios

The intent behind commit e6fc9f62 ("dm: flag clones created by
__send_duplicate_bios") was to formally disallow the use of
dm_accept_partial_bio() where it simply isn't possible -- due to
constraint that multiple bios cannot meaningfully update a shared
tio->len_ptr.

But that commit went too far and disallowed the case where "abormal"
IO (e.g. WRITE_ZEROES) is only using a single bio.  Fix this by
not marking a dm_io with a single dm_target_io (and bio), that happens
to be created by __send_duplicate_bios, as DM_TIO_IS_DUPLICATE_BIO.
Also remove 'unsigned *len' parameter from alloc_multiple_bios().

This commit fixes a dm_accept_partial_bio() BUG_ON() with dm-zoned
when a WRITE_ZEROES bio is issued.

Fixes: 655f3aad ("dm: switch dm_target_io booleans over to proper flags")
Reported-by: default avatarShinichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Reviewed-by: default avatarDamien Le Moal <damien.lemoal@opensource.wdc.com>
Signed-off-by: default avatarMike Snitzer <snitzer@kernel.org>
parent 73d7b06e
...@@ -1323,8 +1323,7 @@ static void __map_bio(struct bio *clone) ...@@ -1323,8 +1323,7 @@ static void __map_bio(struct bio *clone)
} }
static void alloc_multiple_bios(struct bio_list *blist, struct clone_info *ci, static void alloc_multiple_bios(struct bio_list *blist, struct clone_info *ci,
struct dm_target *ti, unsigned num_bios, struct dm_target *ti, unsigned num_bios)
unsigned *len)
{ {
struct bio *bio; struct bio *bio;
int try; int try;
...@@ -1335,7 +1334,7 @@ static void alloc_multiple_bios(struct bio_list *blist, struct clone_info *ci, ...@@ -1335,7 +1334,7 @@ static void alloc_multiple_bios(struct bio_list *blist, struct clone_info *ci,
if (try) if (try)
mutex_lock(&ci->io->md->table_devices_lock); mutex_lock(&ci->io->md->table_devices_lock);
for (bio_nr = 0; bio_nr < num_bios; bio_nr++) { for (bio_nr = 0; bio_nr < num_bios; bio_nr++) {
bio = alloc_tio(ci, ti, bio_nr, len, bio = alloc_tio(ci, ti, bio_nr, NULL,
try ? GFP_NOIO : GFP_NOWAIT); try ? GFP_NOIO : GFP_NOWAIT);
if (!bio) if (!bio)
break; break;
...@@ -1363,11 +1362,11 @@ static void __send_duplicate_bios(struct clone_info *ci, struct dm_target *ti, ...@@ -1363,11 +1362,11 @@ static void __send_duplicate_bios(struct clone_info *ci, struct dm_target *ti,
break; break;
case 1: case 1:
clone = alloc_tio(ci, ti, 0, len, GFP_NOIO); clone = alloc_tio(ci, ti, 0, len, GFP_NOIO);
dm_tio_set_flag(clone_to_tio(clone), DM_TIO_IS_DUPLICATE_BIO);
__map_bio(clone); __map_bio(clone);
break; break;
default: default:
alloc_multiple_bios(&blist, ci, ti, num_bios, len); /* dm_accept_partial_bio() is not supported with shared tio->len_ptr */
alloc_multiple_bios(&blist, ci, ti, num_bios);
while ((clone = bio_list_pop(&blist))) { while ((clone = bio_list_pop(&blist))) {
dm_tio_set_flag(clone_to_tio(clone), DM_TIO_IS_DUPLICATE_BIO); dm_tio_set_flag(clone_to_tio(clone), DM_TIO_IS_DUPLICATE_BIO);
__map_bio(clone); __map_bio(clone);
...@@ -1407,14 +1406,10 @@ static void __send_changing_extent_only(struct clone_info *ci, struct dm_target ...@@ -1407,14 +1406,10 @@ static void __send_changing_extent_only(struct clone_info *ci, struct dm_target
len = min_t(sector_t, ci->sector_count, len = min_t(sector_t, ci->sector_count,
max_io_len_target_boundary(ti, dm_target_offset(ti, ci->sector))); max_io_len_target_boundary(ti, dm_target_offset(ti, ci->sector)));
/* __send_duplicate_bios(ci, ti, num_bios, &len);
* dm_accept_partial_bio cannot be used with duplicate bios,
* so update clone_info cursor before __send_duplicate_bios().
*/
ci->sector += len; ci->sector += len;
ci->sector_count -= len; ci->sector_count -= len;
__send_duplicate_bios(ci, ti, num_bios, &len);
} }
static bool is_abnormal_io(struct bio *bio) static bool is_abnormal_io(struct bio *bio)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment