Commit e142d052 authored by Jan Kara's avatar Jan Kara Committed by Theodore Ts'o

ext4: use i_mutex to serialize unaligned AIO DIO

Currently we've used hashed aio_mutex to serialize unaligned AIO DIO.
However the code cleanups that happened after 2011 when the lock was
introduced made aio_mutex acquired at almost the same places where we
already have exclusion using i_mutex. So just use i_mutex for the
exclusion of unaligned AIO DIO.

The change moves waiting for pending unwritten extent conversion under
i_mutex. That makes special handling of O_APPEND writes unnecessary and
also avoids possible livelocking of unaligned AIO DIO with aligned one
(nothing was preventing contiguous stream of aligned AIO DIOs to let
unaligned AIO DIO wait forever).
Signed-off-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent 3bd6ad7b
...@@ -3285,10 +3285,7 @@ static inline void ext4_inode_resume_unlocked_dio(struct inode *inode) ...@@ -3285,10 +3285,7 @@ static inline void ext4_inode_resume_unlocked_dio(struct inode *inode)
#define EXT4_WQ_HASH_SZ 37 #define EXT4_WQ_HASH_SZ 37
#define ext4_ioend_wq(v) (&ext4__ioend_wq[((unsigned long)(v)) %\ #define ext4_ioend_wq(v) (&ext4__ioend_wq[((unsigned long)(v)) %\
EXT4_WQ_HASH_SZ]) EXT4_WQ_HASH_SZ])
#define ext4_aio_mutex(v) (&ext4__aio_mutex[((unsigned long)(v)) %\
EXT4_WQ_HASH_SZ])
extern wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ]; extern wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
extern struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ];
#define EXT4_RESIZING 0 #define EXT4_RESIZING 0
extern int ext4_resize_begin(struct super_block *sb); extern int ext4_resize_begin(struct super_block *sb);
......
...@@ -93,31 +93,29 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -93,31 +93,29 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
{ {
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct inode *inode = file_inode(iocb->ki_filp); struct inode *inode = file_inode(iocb->ki_filp);
struct mutex *aio_mutex = NULL;
struct blk_plug plug; struct blk_plug plug;
int o_direct = iocb->ki_flags & IOCB_DIRECT; int o_direct = iocb->ki_flags & IOCB_DIRECT;
int unaligned_aio = 0;
int overwrite = 0; int overwrite = 0;
ssize_t ret; ssize_t ret;
inode_lock(inode);
ret = generic_write_checks(iocb, from);
if (ret <= 0)
goto out;
/* /*
* Unaligned direct AIO must be serialized; see comment above * Unaligned direct AIO must be serialized among each other as zeroing
* In the case of O_APPEND, assume that we must always serialize * of partial blocks of two competing unaligned AIOs can result in data
* corruption.
*/ */
if (o_direct && if (o_direct && ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) &&
ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) &&
!is_sync_kiocb(iocb) && !is_sync_kiocb(iocb) &&
(iocb->ki_flags & IOCB_APPEND || ext4_unaligned_aio(inode, from, iocb->ki_pos)) {
ext4_unaligned_aio(inode, from, iocb->ki_pos))) { unaligned_aio = 1;
aio_mutex = ext4_aio_mutex(inode);
mutex_lock(aio_mutex);
ext4_unwritten_wait(inode); ext4_unwritten_wait(inode);
} }
inode_lock(inode);
ret = generic_write_checks(iocb, from);
if (ret <= 0)
goto out;
/* /*
* If we have encountered a bitmap-format file, the size limit * If we have encountered a bitmap-format file, the size limit
* is smaller than s_maxbytes, which is for extent-mapped files. * is smaller than s_maxbytes, which is for extent-mapped files.
...@@ -139,7 +137,7 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -139,7 +137,7 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
blk_start_plug(&plug); blk_start_plug(&plug);
/* check whether we do a DIO overwrite or not */ /* check whether we do a DIO overwrite or not */
if (ext4_should_dioread_nolock(inode) && !aio_mutex && if (ext4_should_dioread_nolock(inode) && !unaligned_aio &&
!file->f_mapping->nrpages && pos + length <= i_size_read(inode)) { !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) {
struct ext4_map_blocks map; struct ext4_map_blocks map;
unsigned int blkbits = inode->i_blkbits; unsigned int blkbits = inode->i_blkbits;
...@@ -181,14 +179,10 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -181,14 +179,10 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (o_direct) if (o_direct)
blk_finish_plug(&plug); blk_finish_plug(&plug);
if (aio_mutex)
mutex_unlock(aio_mutex);
return ret; return ret;
out: out:
inode_unlock(inode); inode_unlock(inode);
if (aio_mutex)
mutex_unlock(aio_mutex);
return ret; return ret;
} }
......
...@@ -5321,7 +5321,6 @@ MODULE_ALIAS_FS("ext4"); ...@@ -5321,7 +5321,6 @@ MODULE_ALIAS_FS("ext4");
/* Shared across all ext4 file systems */ /* Shared across all ext4 file systems */
wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ]; wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ];
static int __init ext4_init_fs(void) static int __init ext4_init_fs(void)
{ {
...@@ -5334,10 +5333,8 @@ static int __init ext4_init_fs(void) ...@@ -5334,10 +5333,8 @@ static int __init ext4_init_fs(void)
/* Build-time check for flags consistency */ /* Build-time check for flags consistency */
ext4_check_flag_values(); ext4_check_flag_values();
for (i = 0; i < EXT4_WQ_HASH_SZ; i++) { for (i = 0; i < EXT4_WQ_HASH_SZ; i++)
mutex_init(&ext4__aio_mutex[i]);
init_waitqueue_head(&ext4__ioend_wq[i]); init_waitqueue_head(&ext4__ioend_wq[i]);
}
err = ext4_init_es(); err = ext4_init_es();
if (err) if (err)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment