diff options
Diffstat (limited to 'fs/ext4/indirect.c')
-rw-r--r-- | fs/ext4/indirect.c | 18 |
1 files changed, 16 insertions, 2 deletions
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index 830e1b2bf14..792e388e7b4 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c @@ -807,16 +807,30 @@ ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, retry: if (rw == READ && ext4_should_dioread_nolock(inode)) { - if (unlikely(!list_empty(&ei->i_completed_io_list))) { + if (unlikely(atomic_read(&EXT4_I(inode)->i_unwritten))) { mutex_lock(&inode->i_mutex); - ext4_flush_completed_IO(inode); + ext4_flush_unwritten_io(inode); mutex_unlock(&inode->i_mutex); } + /* + * Nolock dioread optimization may be dynamically disabled + * via ext4_inode_block_unlocked_dio(). Check inode's state + * while holding extra i_dio_count ref. + */ + atomic_inc(&inode->i_dio_count); + smp_mb(); + if (unlikely(ext4_test_inode_state(inode, + EXT4_STATE_DIOREAD_LOCK))) { + inode_dio_done(inode); + goto locked; + } ret = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, ext4_get_block, NULL, NULL, 0); + inode_dio_done(inode); } else { +locked: ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, ext4_get_block); |