diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 6e3de50eae47..7b277b18a8fe 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1780,12 +1780,29 @@ static inline bool dm_zone_bio_needs_split(struct mapped_device *md, struct bio *bio) { /* - * For mapped device that need zone append emulation, we must - * split any large BIO that straddles zone boundaries. + * Special case the zone operations that cannot or should not be split. */ - return dm_emulate_zone_append(md) && bio_straddles_zones(bio) && - !bio_flagged(bio, BIO_ZONE_WRITE_PLUGGING); + switch (bio_op(bio)) { + case REQ_OP_ZONE_APPEND: + case REQ_OP_ZONE_FINISH: + case REQ_OP_ZONE_RESET: + case REQ_OP_ZONE_RESET_ALL: + return false; + default: + break; + } + + /* + * Mapped devices that require zone append emulation will use the block + * layer zone write plugging. In such case, we must split any large BIO + * to the mapped device limits to avoid potential deadlocks with queue + * freeze operations. + */ + if (!dm_emulate_zone_append(md)) + return false; + return bio_needs_zone_write_plugging(bio) || bio_straddles_zones(bio); } + static inline bool dm_zone_plug_bio(struct mapped_device *md, struct bio *bio) { if (!bio_needs_zone_write_plugging(bio)) @@ -1934,9 +1951,7 @@ static void dm_split_and_process_bio(struct mapped_device *md, is_abnormal = is_abnormal_io(bio); if (static_branch_unlikely(&zoned_enabled)) { - /* Special case REQ_OP_ZONE_RESET_ALL as it cannot be split. */ - need_split = (bio_op(bio) != REQ_OP_ZONE_RESET_ALL) && - (is_abnormal || dm_zone_bio_needs_split(md, bio)); + need_split = is_abnormal || dm_zone_bio_needs_split(md, bio); } else { need_split = is_abnormal; }