syzbot found that a thread can stall for minutes inside fallocate() after that thread was killed by SIGKILL [1]. While trying to allocate 64TB of disk space using fallocate() is legal, delaying termination of killed thread for minutes is bad. Thus, allow iteration functions in block/blk-lib.c to be killable. [1] https://syzkaller.appspot.com/bug?id=9386d051e11e09973d5a4cf79af5e8cedf79386d Signed-off-by: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx> Reported-by: syzbot <syzbot+b48daca8639150bc5e73@xxxxxxxxxxxxxxxxxxxxxxxxx> --- block/blk-lib.c | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/block/blk-lib.c b/block/blk-lib.c index 5f2c429..6ca7cae 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -7,9 +7,22 @@ #include <linux/bio.h> #include <linux/blkdev.h> #include <linux/scatterlist.h> +#include <linux/sched/signal.h> #include "blk.h" +static int blk_should_abort(struct bio *bio) +{ + int ret; + + cond_resched(); + if (!fatal_signal_pending(current)) + return 0; + ret = submit_bio_wait(bio); + bio_put(bio); + return ret ? ret : -EINTR; +} + struct bio *blk_next_bio(struct bio *bio, unsigned int nr_pages, gfp_t gfp) { struct bio *new = bio_alloc(gfp, nr_pages); @@ -55,6 +68,7 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, return -EINVAL; while (nr_sects) { + int ret; sector_t req_sects = min_t(sector_t, nr_sects, bio_allowed_max_sectors(q)); @@ -75,7 +89,11 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, * us to schedule out to avoid softlocking if preempt * is disabled. */ - cond_resched(); + ret = blk_should_abort(bio); + if (ret) { + *biop = NULL; + return ret; + } } *biop = bio; @@ -154,6 +172,8 @@ static int __blkdev_issue_write_same(struct block_device *bdev, sector_t sector, max_write_same_sectors = bio_allowed_max_sectors(q); while (nr_sects) { + int ret; + bio = blk_next_bio(bio, 1, gfp_mask); bio->bi_iter.bi_sector = sector; bio_set_dev(bio, bdev); @@ -171,7 +191,11 @@ static int __blkdev_issue_write_same(struct block_device *bdev, sector_t sector, bio->bi_iter.bi_size = nr_sects << 9; nr_sects = 0; } - cond_resched(); + ret = blk_should_abort(bio); + if (ret) { + *biop = NULL; + return ret; + } } *biop = bio; @@ -230,6 +254,8 @@ static int __blkdev_issue_write_zeroes(struct block_device *bdev, return -EOPNOTSUPP; while (nr_sects) { + int ret; + bio = blk_next_bio(bio, 0, gfp_mask); bio->bi_iter.bi_sector = sector; bio_set_dev(bio, bdev); @@ -245,7 +271,11 @@ static int __blkdev_issue_write_zeroes(struct block_device *bdev, bio->bi_iter.bi_size = nr_sects << 9; nr_sects = 0; } - cond_resched(); + ret = blk_should_abort(bio); + if (ret) { + *biop = NULL; + return ret; + } } *biop = bio; @@ -281,6 +311,8 @@ static int __blkdev_issue_zero_pages(struct block_device *bdev, return -EPERM; while (nr_sects != 0) { + int ret; + bio = blk_next_bio(bio, __blkdev_sectors_to_bio_pages(nr_sects), gfp_mask); bio->bi_iter.bi_sector = sector; @@ -295,7 +327,11 @@ static int __blkdev_issue_zero_pages(struct block_device *bdev, if (bi_size < sz) break; } - cond_resched(); + ret = blk_should_abort(bio); + if (ret) { + *biop = NULL; + return ret; + } } *biop = bio; -- 1.8.3.1