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 830e1b2bf145..792e388e7b44 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, | |||
807 | 807 | ||
808 | retry: | 808 | retry: |
809 | if (rw == READ && ext4_should_dioread_nolock(inode)) { | 809 | if (rw == READ && ext4_should_dioread_nolock(inode)) { |
810 | if (unlikely(!list_empty(&ei->i_completed_io_list))) { | 810 | if (unlikely(atomic_read(&EXT4_I(inode)->i_unwritten))) { |
811 | mutex_lock(&inode->i_mutex); | 811 | mutex_lock(&inode->i_mutex); |
812 | ext4_flush_completed_IO(inode); | 812 | ext4_flush_unwritten_io(inode); |
813 | mutex_unlock(&inode->i_mutex); | 813 | mutex_unlock(&inode->i_mutex); |
814 | } | 814 | } |
815 | /* | ||
816 | * Nolock dioread optimization may be dynamically disabled | ||
817 | * via ext4_inode_block_unlocked_dio(). Check inode's state | ||
818 | * while holding extra i_dio_count ref. | ||
819 | */ | ||
820 | atomic_inc(&inode->i_dio_count); | ||
821 | smp_mb(); | ||
822 | if (unlikely(ext4_test_inode_state(inode, | ||
823 | EXT4_STATE_DIOREAD_LOCK))) { | ||
824 | inode_dio_done(inode); | ||
825 | goto locked; | ||
826 | } | ||
815 | ret = __blockdev_direct_IO(rw, iocb, inode, | 827 | ret = __blockdev_direct_IO(rw, iocb, inode, |
816 | inode->i_sb->s_bdev, iov, | 828 | inode->i_sb->s_bdev, iov, |
817 | offset, nr_segs, | 829 | offset, nr_segs, |
818 | ext4_get_block, NULL, NULL, 0); | 830 | ext4_get_block, NULL, NULL, 0); |
831 | inode_dio_done(inode); | ||
819 | } else { | 832 | } else { |
833 | locked: | ||
820 | ret = blockdev_direct_IO(rw, iocb, inode, iov, | 834 | ret = blockdev_direct_IO(rw, iocb, inode, iov, |
821 | offset, nr_segs, ext4_get_block); | 835 | offset, nr_segs, ext4_get_block); |
822 | 836 | ||