Skip to content

Commit e142d05

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

File tree

3 files changed

+14
-26
lines changed

3 files changed

+14
-26
lines changed

fs/ext4/ext4.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3285,10 +3285,7 @@ static inline void ext4_inode_resume_unlocked_dio(struct inode *inode)
32853285
#define EXT4_WQ_HASH_SZ 37
32863286
#define ext4_ioend_wq(v) (&ext4__ioend_wq[((unsigned long)(v)) %\
32873287
EXT4_WQ_HASH_SZ])
3288-
#define ext4_aio_mutex(v) (&ext4__aio_mutex[((unsigned long)(v)) %\
3289-
EXT4_WQ_HASH_SZ])
32903288
extern wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
3291-
extern struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ];
32923289

32933290
#define EXT4_RESIZING 0
32943291
extern int ext4_resize_begin(struct super_block *sb);

fs/ext4/file.c

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -93,31 +93,29 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
9393
{
9494
struct file *file = iocb->ki_filp;
9595
struct inode *inode = file_inode(iocb->ki_filp);
96-
struct mutex *aio_mutex = NULL;
9796
struct blk_plug plug;
9897
int o_direct = iocb->ki_flags & IOCB_DIRECT;
98+
int unaligned_aio = 0;
9999
int overwrite = 0;
100100
ssize_t ret;
101101

102+
inode_lock(inode);
103+
ret = generic_write_checks(iocb, from);
104+
if (ret <= 0)
105+
goto out;
106+
102107
/*
103-
* Unaligned direct AIO must be serialized; see comment above
104-
* In the case of O_APPEND, assume that we must always serialize
108+
* Unaligned direct AIO must be serialized among each other as zeroing
109+
* of partial blocks of two competing unaligned AIOs can result in data
110+
* corruption.
105111
*/
106-
if (o_direct &&
107-
ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) &&
112+
if (o_direct && ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) &&
108113
!is_sync_kiocb(iocb) &&
109-
(iocb->ki_flags & IOCB_APPEND ||
110-
ext4_unaligned_aio(inode, from, iocb->ki_pos))) {
111-
aio_mutex = ext4_aio_mutex(inode);
112-
mutex_lock(aio_mutex);
114+
ext4_unaligned_aio(inode, from, iocb->ki_pos)) {
115+
unaligned_aio = 1;
113116
ext4_unwritten_wait(inode);
114117
}
115118

116-
inode_lock(inode);
117-
ret = generic_write_checks(iocb, from);
118-
if (ret <= 0)
119-
goto out;
120-
121119
/*
122120
* If we have encountered a bitmap-format file, the size limit
123121
* 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)
139137
blk_start_plug(&plug);
140138

141139
/* check whether we do a DIO overwrite or not */
142-
if (ext4_should_dioread_nolock(inode) && !aio_mutex &&
140+
if (ext4_should_dioread_nolock(inode) && !unaligned_aio &&
143141
!file->f_mapping->nrpages && pos + length <= i_size_read(inode)) {
144142
struct ext4_map_blocks map;
145143
unsigned int blkbits = inode->i_blkbits;
@@ -181,14 +179,10 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
181179
if (o_direct)
182180
blk_finish_plug(&plug);
183181

184-
if (aio_mutex)
185-
mutex_unlock(aio_mutex);
186182
return ret;
187183

188184
out:
189185
inode_unlock(inode);
190-
if (aio_mutex)
191-
mutex_unlock(aio_mutex);
192186
return ret;
193187
}
194188

fs/ext4/super.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5321,7 +5321,6 @@ MODULE_ALIAS_FS("ext4");
53215321

53225322
/* Shared across all ext4 file systems */
53235323
wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
5324-
struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ];
53255324

53265325
static int __init ext4_init_fs(void)
53275326
{
@@ -5334,10 +5333,8 @@ static int __init ext4_init_fs(void)
53345333
/* Build-time check for flags consistency */
53355334
ext4_check_flag_values();
53365335

5337-
for (i = 0; i < EXT4_WQ_HASH_SZ; i++) {
5338-
mutex_init(&ext4__aio_mutex[i]);
5336+
for (i = 0; i < EXT4_WQ_HASH_SZ; i++)
53395337
init_waitqueue_head(&ext4__ioend_wq[i]);
5340-
}
53415338

53425339
err = ext4_init_es();
53435340
if (err)

0 commit comments

Comments
 (0)