aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/ext4.h17
-rw-r--r--fs/ext4/indirect.c14
-rw-r--r--fs/ext4/inode.c5
-rw-r--r--fs/ext4/move_extent.c8
4 files changed, 44 insertions, 0 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index edb049579420..1be2b4472a83 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1358,6 +1358,8 @@ enum {
1358 EXT4_STATE_DIO_UNWRITTEN, /* need convert on dio done*/ 1358 EXT4_STATE_DIO_UNWRITTEN, /* need convert on dio done*/
1359 EXT4_STATE_NEWENTRY, /* File just added to dir */ 1359 EXT4_STATE_NEWENTRY, /* File just added to dir */
1360 EXT4_STATE_DELALLOC_RESERVED, /* blks already reserved for delalloc */ 1360 EXT4_STATE_DELALLOC_RESERVED, /* blks already reserved for delalloc */
1361 EXT4_STATE_DIOREAD_LOCK, /* Disable support for dio read
1362 nolocking */
1361}; 1363};
1362 1364
1363#define EXT4_INODE_BIT_FNS(name, field, offset) \ 1365#define EXT4_INODE_BIT_FNS(name, field, offset) \
@@ -2469,6 +2471,21 @@ static inline void set_bitmap_uptodate(struct buffer_head *bh)
2469 set_bit(BH_BITMAP_UPTODATE, &(bh)->b_state); 2471 set_bit(BH_BITMAP_UPTODATE, &(bh)->b_state);
2470} 2472}
2471 2473
2474/*
2475 * Disable DIO read nolock optimization, so new dioreaders will be forced
2476 * to grab i_mutex
2477 */
2478static inline void ext4_inode_block_unlocked_dio(struct inode *inode)
2479{
2480 ext4_set_inode_state(inode, EXT4_STATE_DIOREAD_LOCK);
2481 smp_mb();
2482}
2483static inline void ext4_inode_resume_unlocked_dio(struct inode *inode)
2484{
2485 smp_mb();
2486 ext4_clear_inode_state(inode, EXT4_STATE_DIOREAD_LOCK);
2487}
2488
2472#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) 2489#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
2473 2490
2474/* For ioend & aio unwritten conversion wait queues */ 2491/* For ioend & aio unwritten conversion wait queues */
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
index 61f13e57975e..8d849dae8428 100644
--- a/fs/ext4/indirect.c
+++ b/fs/ext4/indirect.c
@@ -810,11 +810,25 @@ retry:
810 if (unlikely(!list_empty(&ei->i_completed_io_list))) 810 if (unlikely(!list_empty(&ei->i_completed_io_list)))
811 ext4_flush_completed_IO(inode); 811 ext4_flush_completed_IO(inode);
812 812
813 /*
814 * Nolock dioread optimization may be dynamically disabled
815 * via ext4_inode_block_unlocked_dio(). Check inode's state
816 * while holding extra i_dio_count ref.
817 */
818 atomic_inc(&inode->i_dio_count);
819 smp_mb();
820 if (unlikely(ext4_test_inode_state(inode,
821 EXT4_STATE_DIOREAD_LOCK))) {
822 inode_dio_done(inode);
823 goto locked;
824 }
813 ret = __blockdev_direct_IO(rw, iocb, inode, 825 ret = __blockdev_direct_IO(rw, iocb, inode,
814 inode->i_sb->s_bdev, iov, 826 inode->i_sb->s_bdev, iov,
815 offset, nr_segs, 827 offset, nr_segs,
816 ext4_get_block, NULL, NULL, 0); 828 ext4_get_block, NULL, NULL, 0);
829 inode_dio_done(inode);
817 } else { 830 } else {
831locked:
818 ret = blockdev_direct_IO(rw, iocb, inode, iov, 832 ret = blockdev_direct_IO(rw, iocb, inode, iov,
819 offset, nr_segs, ext4_get_block); 833 offset, nr_segs, ext4_get_block);
820 834
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 09d0488e9a15..bdd399bc2abf 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4720,6 +4720,10 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
4720 return err; 4720 return err;
4721 } 4721 }
4722 4722
4723 /* Wait for all existing dio workers */
4724 ext4_inode_block_unlocked_dio(inode);
4725 inode_dio_wait(inode);
4726
4723 jbd2_journal_lock_updates(journal); 4727 jbd2_journal_lock_updates(journal);
4724 4728
4725 /* 4729 /*
@@ -4739,6 +4743,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
4739 ext4_set_aops(inode); 4743 ext4_set_aops(inode);
4740 4744
4741 jbd2_journal_unlock_updates(journal); 4745 jbd2_journal_unlock_updates(journal);
4746 ext4_inode_resume_unlocked_dio(inode);
4742 4747
4743 /* Finally we can mark the inode as dirty. */ 4748 /* Finally we can mark the inode as dirty. */
4744 4749
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
index 8076b96b5299..292daeeed455 100644
--- a/fs/ext4/move_extent.c
+++ b/fs/ext4/move_extent.c
@@ -1323,6 +1323,12 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
1323 /* Protect orig and donor inodes against a truncate */ 1323 /* Protect orig and donor inodes against a truncate */
1324 mext_inode_double_lock(orig_inode, donor_inode); 1324 mext_inode_double_lock(orig_inode, donor_inode);
1325 1325
1326 /* Wait for all existing dio workers */
1327 ext4_inode_block_unlocked_dio(orig_inode);
1328 ext4_inode_block_unlocked_dio(donor_inode);
1329 inode_dio_wait(orig_inode);
1330 inode_dio_wait(donor_inode);
1331
1326 /* Protect extent tree against block allocations via delalloc */ 1332 /* Protect extent tree against block allocations via delalloc */
1327 double_down_write_data_sem(orig_inode, donor_inode); 1333 double_down_write_data_sem(orig_inode, donor_inode);
1328 /* Check the filesystem environment whether move_extent can be done */ 1334 /* Check the filesystem environment whether move_extent can be done */
@@ -1521,6 +1527,8 @@ out:
1521 kfree(holecheck_path); 1527 kfree(holecheck_path);
1522 } 1528 }
1523 double_up_write_data_sem(orig_inode, donor_inode); 1529 double_up_write_data_sem(orig_inode, donor_inode);
1530 ext4_inode_resume_unlocked_dio(orig_inode);
1531 ext4_inode_resume_unlocked_dio(donor_inode);
1524 mext_inode_double_unlock(orig_inode, donor_inode); 1532 mext_inode_double_unlock(orig_inode, donor_inode);
1525 1533
1526 return ret; 1534 return ret;