diff options
author | Jan Kara <jack@suse.cz> | 2016-02-19 00:33:21 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2016-02-19 00:33:21 -0500 |
commit | 74dae4278546b897eb81784fdfcce872ddd8b2b8 (patch) | |
tree | 1f8933f3ec2715cdfcbac993cf0409e884caf11c | |
parent | ed8ad83808f009ade97ebbf6519bc3a97fefbc0c (diff) |
ext4: fix crashes in dioread_nolock mode
Competing overwrite DIO in dioread_nolock mode will just overwrite
pointer to io_end in the inode. This may result in data corruption or
extent conversion happening from IO completion interrupt because we
don't properly set buffer_defer_completion() when unlocked DIO races
with locked DIO to unwritten extent.
Since unlocked DIO doesn't need io_end for anything, just avoid
allocating it and corrupting pointer from inode for locked DIO.
A cleaner fix would be to avoid these games with io_end pointer from the
inode but that requires more intrusive changes so we leave that for
later.
Cc: stable@vger.kernel.org
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r-- | fs/ext4/inode.c | 40 |
1 files changed, 20 insertions, 20 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index d6674479269d..9cc57c3b4661 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -3281,29 +3281,29 @@ static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter, | |||
3281 | * case, we allocate an io_end structure to hook to the iocb. | 3281 | * case, we allocate an io_end structure to hook to the iocb. |
3282 | */ | 3282 | */ |
3283 | iocb->private = NULL; | 3283 | iocb->private = NULL; |
3284 | ext4_inode_aio_set(inode, NULL); | ||
3285 | if (!is_sync_kiocb(iocb)) { | ||
3286 | io_end = ext4_init_io_end(inode, GFP_NOFS); | ||
3287 | if (!io_end) { | ||
3288 | ret = -ENOMEM; | ||
3289 | goto retake_lock; | ||
3290 | } | ||
3291 | /* | ||
3292 | * Grab reference for DIO. Will be dropped in ext4_end_io_dio() | ||
3293 | */ | ||
3294 | iocb->private = ext4_get_io_end(io_end); | ||
3295 | /* | ||
3296 | * we save the io structure for current async direct | ||
3297 | * IO, so that later ext4_map_blocks() could flag the | ||
3298 | * io structure whether there is a unwritten extents | ||
3299 | * needs to be converted when IO is completed. | ||
3300 | */ | ||
3301 | ext4_inode_aio_set(inode, io_end); | ||
3302 | } | ||
3303 | |||
3304 | if (overwrite) { | 3284 | if (overwrite) { |
3305 | get_block_func = ext4_get_block_overwrite; | 3285 | get_block_func = ext4_get_block_overwrite; |
3306 | } else { | 3286 | } else { |
3287 | ext4_inode_aio_set(inode, NULL); | ||
3288 | if (!is_sync_kiocb(iocb)) { | ||
3289 | io_end = ext4_init_io_end(inode, GFP_NOFS); | ||
3290 | if (!io_end) { | ||
3291 | ret = -ENOMEM; | ||
3292 | goto retake_lock; | ||
3293 | } | ||
3294 | /* | ||
3295 | * Grab reference for DIO. Will be dropped in | ||
3296 | * ext4_end_io_dio() | ||
3297 | */ | ||
3298 | iocb->private = ext4_get_io_end(io_end); | ||
3299 | /* | ||
3300 | * we save the io structure for current async direct | ||
3301 | * IO, so that later ext4_map_blocks() could flag the | ||
3302 | * io structure whether there is a unwritten extents | ||
3303 | * needs to be converted when IO is completed. | ||
3304 | */ | ||
3305 | ext4_inode_aio_set(inode, io_end); | ||
3306 | } | ||
3307 | get_block_func = ext4_get_block_write; | 3307 | get_block_func = ext4_get_block_write; |
3308 | dio_flags = DIO_LOCKING; | 3308 | dio_flags = DIO_LOCKING; |
3309 | } | 3309 | } |