diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 20f1c03b6077..3736d9dfe325 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -97,8 +97,9 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, { struct file *file = iocb->ki_filp; struct inode *inode = file_inode(iocb->ki_filp); + struct mutex *aio_mutex = NULL; struct blk_plug plug; - int unaligned_aio = 0; + int o_direct = file->f_flags & O_DIRECT; int overwrite = 0; size_t length = iov_length(iov, nr_segs); ssize_t ret; @@ -123,15 +124,13 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, } } - if (unlikely(iocb->ki_filp->f_flags & O_DIRECT)) { - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && - !is_sync_kiocb(iocb)) - unaligned_aio = ext4_unaligned_aio(inode, iov, - nr_segs, pos); - + if (o_direct) { /* Unaligned direct AIO must be serialized; see comment above */ - if (unaligned_aio) { - mutex_lock(ext4_aio_mutex(inode)); + if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && + !is_sync_kiocb(iocb) && + ext4_unaligned_aio(inode, iov, nr_segs, pos)) { + aio_mutex = ext4_aio_mutex(inode); + mutex_lock(aio_mutex); ext4_unwritten_wait(inode); } @@ -141,7 +140,7 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, iocb->private = &overwrite; /* check whether we do a DIO overwrite or not */ - if (ext4_should_dioread_nolock(inode) && !unaligned_aio && + if (ext4_should_dioread_nolock(inode) && !aio_mutex && !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) { struct ext4_map_blocks map; unsigned int blkbits = inode->i_blkbits; @@ -168,35 +167,24 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, if (err == len && (map.m_flags & EXT4_MAP_MAPPED)) overwrite = 1; } + } else + mutex_lock(&inode->i_mutex); - ret = __generic_file_aio_write(iocb, iov, nr_segs); - mutex_unlock(&inode->i_mutex); + ret = __generic_file_aio_write(iocb, iov, nr_segs); + mutex_unlock(&inode->i_mutex); - if (ret > 0) { - ssize_t err; + if (ret > 0) { + ssize_t err; - err = generic_write_sync(file, iocb->ki_pos - ret, ret); - if (err < 0) - ret = err; - } + err = generic_write_sync(file, iocb->ki_pos - ret, ret); + if (err < 0) + ret = err; + } + if (o_direct) blk_finish_plug(&plug); - if (unaligned_aio) - mutex_unlock(ext4_aio_mutex(inode)); - } else { - mutex_lock(&inode->i_mutex); - ret = __generic_file_aio_write(iocb, iov, nr_segs); - mutex_unlock(&inode->i_mutex); - - if (ret > 0) { - ssize_t err; - - err = generic_write_sync(file, iocb->ki_pos - ret, ret); - if (err < 0) - ret = err; - } - } - + if (aio_mutex) + mutex_unlock(aio_mutex); return ret; }