Commit 1c394c8b authored by Li Nan's avatar Li Nan
Browse files

block: check io size before submit discard

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I9K0H6



--------------------------------

In __blkdev_issue_discard(), q->limits.discard_granularity is read
multi times.

  WARN_ON_ONCE(!q->limits.discard_granularity) [1]
  ...
  q->limits.discard_granularity >> SECTOR_SHIFT [2]
  ...
  bio_aligned_discard_max_sectors [3]

It can be changed to 0 after check [1], such as submitting ioctl
'LOOP_SET_STATUS'. This is undesirable. If 'discard_granularity' is set
to 0, BUG_ON might be triggered and the loop of 'while(nr_sects)' will
never exit(see fixes commit). Fix it by checking 'req_sects' before
submit io, return error code directly if it is 0.

Fixes: b35fd742 ("block: check queue's limits.discard_granularity in __blkdev_issue_discard()")
Signed-off-by: default avatarLi Nan <linan122@huawei.com>
parent 440327f4
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ static sector_t bio_discard_limit(struct block_device *bdev, sector_t sector)
int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
		sector_t nr_sects, gfp_t gfp_mask, struct bio **biop)
{
	struct bio *bio = *biop;
	struct bio *bio = NULL;
	sector_t bs_mask;

	if (bdev_read_only(bdev))
@@ -64,6 +64,17 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
		sector_t req_sects =
			min(nr_sects, bio_discard_limit(bdev, sector));

		if (!req_sects) {
			/* just put the bio allocated in this function */
			if (bio) {
				bio_io_error(bio);
				bio_put(bio);
			}
			return -EOPNOTSUPP;
		}
		if (!bio)
			bio = *biop;

		bio = blk_next_bio(bio, bdev, 0, REQ_OP_DISCARD, gfp_mask);
		bio->bi_iter.bi_sector = sector;
		bio->bi_iter.bi_size = req_sects << 9;