Align start and end on page boundaries before calling invalidate_inode_pages2_range. This might allow us to miss a collision if the write and the discard were done to the same page and do overlap but it is still better than returning -EBUSY if those writes didn't overlap. Signed-off-by: Maxim Levitsky <mlevitsk@xxxxxxxxxx> --- fs/block_dev.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/fs/block_dev.c b/fs/block_dev.c index 9e84b1928b94..97f0d16661b5 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1970,6 +1970,7 @@ static long blkdev_fallocate(struct file *file, int mode, loff_t start, loff_t end = start + len - 1; loff_t isize; int error; + pgoff_t invalidate_first_page, invalidate_last_page; /* Fail if we don't recognize the flags. */ if (mode & ~BLKDEV_FALLOC_FL_SUPPORTED) @@ -2020,12 +2021,23 @@ static long blkdev_fallocate(struct file *file, int mode, loff_t start, /* * Invalidate again; if someone wandered in and dirtied a page, - * the caller will be given -EBUSY. The third argument is - * inclusive, so the rounding here is safe. + * the caller will be given -EBUSY. + * + * If the start/end of the range is not page aligned, exclude the + * non aligned regions to avoid false positives. */ + invalidate_first_page = DIV_ROUND_UP(start, PAGE_SIZE); + invalidate_last_page = end >> PAGE_SHIFT; + + if ((end + 1) & PAGE_MASK) + invalidate_last_page--; + + if (invalidate_last_page < invalidate_first_page) + return 0; + return invalidate_inode_pages2_range(bdev->bd_inode->i_mapping, - start >> PAGE_SHIFT, - end >> PAGE_SHIFT); + invalidate_first_page, + invalidate_last_page); } const struct file_operations def_blk_fops = { -- 2.26.2