Skip to content

Commit f278eb3

Browse files
Ming Leiaxboe
authored andcommitted
block: hold ->invalidate_lock in blkdev_fallocate
When running ->fallocate(), blkdev_fallocate() should hold mapping->invalidate_lock to prevent page cache from being accessed, otherwise stale data may be read in page cache. Without this patch, blktests block/009 fails sometimes. With this patch, block/009 can pass always. Also as Jan pointed out, no pages can be created in the discarded area while you are holding the invalidate_lock, so remove the 2nd truncate_bdev_range(). Cc: Jan Kara <[email protected]> Signed-off-by: Ming Lei <[email protected]> Reviewed-by: Jan Kara <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 5afedf6 commit f278eb3

File tree

1 file changed

+10
-11
lines changed

1 file changed

+10
-11
lines changed

block/fops.c

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/task_io_accounting_ops.h>
1515
#include <linux/falloc.h>
1616
#include <linux/suspend.h>
17+
#include <linux/fs.h>
1718
#include "blk.h"
1819

1920
static struct inode *bdev_file_inode(struct file *file)
@@ -553,7 +554,8 @@ static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
553554
static long blkdev_fallocate(struct file *file, int mode, loff_t start,
554555
loff_t len)
555556
{
556-
struct block_device *bdev = I_BDEV(bdev_file_inode(file));
557+
struct inode *inode = bdev_file_inode(file);
558+
struct block_device *bdev = I_BDEV(inode);
557559
loff_t end = start + len - 1;
558560
loff_t isize;
559561
int error;
@@ -580,10 +582,12 @@ static long blkdev_fallocate(struct file *file, int mode, loff_t start,
580582
if ((start | len) & (bdev_logical_block_size(bdev) - 1))
581583
return -EINVAL;
582584

585+
filemap_invalidate_lock(inode->i_mapping);
586+
583587
/* Invalidate the page cache, including dirty pages. */
584588
error = truncate_bdev_range(bdev, file->f_mode, start, end);
585589
if (error)
586-
return error;
590+
goto fail;
587591

588592
switch (mode) {
589593
case FALLOC_FL_ZERO_RANGE:
@@ -600,17 +604,12 @@ static long blkdev_fallocate(struct file *file, int mode, loff_t start,
600604
GFP_KERNEL, 0);
601605
break;
602606
default:
603-
return -EOPNOTSUPP;
607+
error = -EOPNOTSUPP;
604608
}
605-
if (error)
606-
return error;
607609

608-
/*
609-
* Invalidate the page cache again; if someone wandered in and dirtied
610-
* a page, we just discard it - userspace has no way of knowing whether
611-
* the write happened before or after discard completing...
612-
*/
613-
return truncate_bdev_range(bdev, file->f_mode, start, end);
610+
fail:
611+
filemap_invalidate_unlock(inode->i_mapping);
612+
return error;
614613
}
615614

616615
const struct file_operations def_blk_fops = {

0 commit comments

Comments
 (0)