|
@@ -810,11 +810,25 @@ retry:
|
|
if (unlikely(!list_empty(&ei->i_completed_io_list)))
|
|
if (unlikely(!list_empty(&ei->i_completed_io_list)))
|
|
ext4_flush_completed_IO(inode);
|
|
ext4_flush_completed_IO(inode);
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * 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,
|
|
ret = __blockdev_direct_IO(rw, iocb, inode,
|
|
inode->i_sb->s_bdev, iov,
|
|
inode->i_sb->s_bdev, iov,
|
|
offset, nr_segs,
|
|
offset, nr_segs,
|
|
ext4_get_block, NULL, NULL, 0);
|
|
ext4_get_block, NULL, NULL, 0);
|
|
|
|
+ inode_dio_done(inode);
|
|
} else {
|
|
} else {
|
|
|
|
+locked:
|
|
ret = blockdev_direct_IO(rw, iocb, inode, iov,
|
|
ret = blockdev_direct_IO(rw, iocb, inode, iov,
|
|
offset, nr_segs, ext4_get_block);
|
|
offset, nr_segs, ext4_get_block);
|
|
|
|
|