File system won't to handle fatal signals themselves and are generally not prepared for EINTR errors from (__)blkdev_issue_discard. Remove the logic from the generic helpers and instead open code the discard bio submission in the ioctl handler that wants it. Fixes: 8a08c5fd89b4 ("blk-lib: check for kill signal") Signed-off-by: Christoph Hellwig <hch@xxxxxx> --- block/blk-lib.c | 12 +++--------- block/ioctl.c | 24 ++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/block/blk-lib.c b/block/blk-lib.c index 8021bc3831d56a..90b75605299b9c 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -65,16 +65,10 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, { struct bio *bio; - while (!fatal_signal_pending(current)) { - bio = blk_alloc_discard_bio(bdev, §or, &nr_sects, gfp_mask); - if (!bio) - return 0; + while ((bio = blk_alloc_discard_bio(bdev, §or, &nr_sects, + gfp_mask))) *biop = bio_chain_and_submit(*biop, bio); - } - - if (*biop) - bio_await_chain(*biop); - return -EINTR; + return 0; } EXPORT_SYMBOL(__blkdev_issue_discard); diff --git a/block/ioctl.c b/block/ioctl.c index 57c8171fda93c5..32bbdba77d6941 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -96,10 +96,12 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode, unsigned long arg) { sector_t bs_mask = (bdev_logical_block_size(bdev) >> SECTOR_SHIFT) - 1; + struct inode *inode = bdev->bd_inode; sector_t sector, nr_sects; + struct bio *bio = NULL, *new; + struct blk_plug plug; uint64_t range[2]; uint64_t start, len; - struct inode *inode = bdev->bd_inode; int err; if (!(mode & BLK_OPEN_WRITE)) @@ -129,7 +131,25 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode, err = truncate_bdev_range(bdev, mode, start, start + len - 1); if (err) goto fail; - err = blkdev_issue_discard(bdev, sector, nr_sects, GFP_KERNEL); + blk_start_plug(&plug); + while (!fatal_signal_pending(current)) { + new = blk_alloc_discard_bio(bdev, §or, &nr_sects, + GFP_KERNEL); + if (!new) + break; + bio = bio_chain_and_submit(bio, new); + } + if (fatal_signal_pending(current)) { + if (bio) + bio_await_chain(bio); + err = -EINTR; + } else if (bio) { + err = submit_bio_wait(bio); + if (err == -EOPNOTSUPP) + err = 0; + bio_put(bio); + } + blk_finish_plug(&plug); fail: filemap_invalidate_unlock(inode->i_mapping); return err; -- 2.39.2