Skip to content

Commit 74dae42

Browse files
jankaratytso
authored andcommitted
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: [email protected] Signed-off-by: Jan Kara <[email protected]> Signed-off-by: Theodore Ts'o <[email protected]>
1 parent ed8ad83 commit 74dae42

File tree

1 file changed

+20
-20
lines changed

1 file changed

+20
-20
lines changed

fs/ext4/inode.c

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3281,29 +3281,29 @@ static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
32813281
* case, we allocate an io_end structure to hook to the iocb.
32823282
*/
32833283
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-
33043284
if (overwrite) {
33053285
get_block_func = ext4_get_block_overwrite;
33063286
} 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+
}
33073307
get_block_func = ext4_get_block_write;
33083308
dio_flags = DIO_LOCKING;
33093309
}

0 commit comments

Comments
 (0)