diff options
author | Jan Kara <jack@suse.cz> | 2009-10-16 13:26:15 -0400 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2009-11-11 09:22:49 -0500 |
commit | fe8bc91c4c30122b357d197117705cfd4fabaf28 (patch) | |
tree | 33e2895847d812204209444db4093af9a2c3623d /fs/ext3/inode.c | |
parent | ea0174a7137c8ca9f130ca681f3a99c872da6778 (diff) |
ext3: Wait for proper transaction commit on fsync
We cannot rely on buffer dirty bits during fsync because pdflush can come
before fsync is called and clear dirty bits without forcing a transaction
commit. What we do is that we track which transaction has last changed
the inode and which transaction last changed allocation and force it to
disk on fsync.
Signed-off-by: Jan Kara <jack@suse.cz>
Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Diffstat (limited to 'fs/ext3/inode.c')
-rw-r--r-- | fs/ext3/inode.c | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 069a163393b4..354ed3b47b30 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -699,8 +699,9 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, | |||
699 | int err = 0; | 699 | int err = 0; |
700 | struct ext3_block_alloc_info *block_i; | 700 | struct ext3_block_alloc_info *block_i; |
701 | ext3_fsblk_t current_block; | 701 | ext3_fsblk_t current_block; |
702 | struct ext3_inode_info *ei = EXT3_I(inode); | ||
702 | 703 | ||
703 | block_i = EXT3_I(inode)->i_block_alloc_info; | 704 | block_i = ei->i_block_alloc_info; |
704 | /* | 705 | /* |
705 | * If we're splicing into a [td]indirect block (as opposed to the | 706 | * If we're splicing into a [td]indirect block (as opposed to the |
706 | * inode) then we need to get write access to the [td]indirect block | 707 | * inode) then we need to get write access to the [td]indirect block |
@@ -741,6 +742,8 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, | |||
741 | 742 | ||
742 | inode->i_ctime = CURRENT_TIME_SEC; | 743 | inode->i_ctime = CURRENT_TIME_SEC; |
743 | ext3_mark_inode_dirty(handle, inode); | 744 | ext3_mark_inode_dirty(handle, inode); |
745 | /* ext3_mark_inode_dirty already updated i_sync_tid */ | ||
746 | atomic_set(&ei->i_datasync_tid, handle->h_transaction->t_tid); | ||
744 | 747 | ||
745 | /* had we spliced it onto indirect block? */ | 748 | /* had we spliced it onto indirect block? */ |
746 | if (where->bh) { | 749 | if (where->bh) { |
@@ -2754,6 +2757,8 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino) | |||
2754 | struct ext3_inode_info *ei; | 2757 | struct ext3_inode_info *ei; |
2755 | struct buffer_head *bh; | 2758 | struct buffer_head *bh; |
2756 | struct inode *inode; | 2759 | struct inode *inode; |
2760 | journal_t *journal = EXT3_SB(sb)->s_journal; | ||
2761 | transaction_t *transaction; | ||
2757 | long ret; | 2762 | long ret; |
2758 | int block; | 2763 | int block; |
2759 | 2764 | ||
@@ -2831,6 +2836,30 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino) | |||
2831 | ei->i_data[block] = raw_inode->i_block[block]; | 2836 | ei->i_data[block] = raw_inode->i_block[block]; |
2832 | INIT_LIST_HEAD(&ei->i_orphan); | 2837 | INIT_LIST_HEAD(&ei->i_orphan); |
2833 | 2838 | ||
2839 | /* | ||
2840 | * Set transaction id's of transactions that have to be committed | ||
2841 | * to finish f[data]sync. We set them to currently running transaction | ||
2842 | * as we cannot be sure that the inode or some of its metadata isn't | ||
2843 | * part of the transaction - the inode could have been reclaimed and | ||
2844 | * now it is reread from disk. | ||
2845 | */ | ||
2846 | if (journal) { | ||
2847 | tid_t tid; | ||
2848 | |||
2849 | spin_lock(&journal->j_state_lock); | ||
2850 | if (journal->j_running_transaction) | ||
2851 | transaction = journal->j_running_transaction; | ||
2852 | else | ||
2853 | transaction = journal->j_committing_transaction; | ||
2854 | if (transaction) | ||
2855 | tid = transaction->t_tid; | ||
2856 | else | ||
2857 | tid = journal->j_commit_sequence; | ||
2858 | spin_unlock(&journal->j_state_lock); | ||
2859 | atomic_set(&ei->i_sync_tid, tid); | ||
2860 | atomic_set(&ei->i_datasync_tid, tid); | ||
2861 | } | ||
2862 | |||
2834 | if (inode->i_ino >= EXT3_FIRST_INO(inode->i_sb) + 1 && | 2863 | if (inode->i_ino >= EXT3_FIRST_INO(inode->i_sb) + 1 && |
2835 | EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) { | 2864 | EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) { |
2836 | /* | 2865 | /* |
@@ -3015,6 +3044,7 @@ again: | |||
3015 | err = rc; | 3044 | err = rc; |
3016 | ei->i_state &= ~EXT3_STATE_NEW; | 3045 | ei->i_state &= ~EXT3_STATE_NEW; |
3017 | 3046 | ||
3047 | atomic_set(&ei->i_sync_tid, handle->h_transaction->t_tid); | ||
3018 | out_brelse: | 3048 | out_brelse: |
3019 | brelse (bh); | 3049 | brelse (bh); |
3020 | ext3_std_error(inode->i_sb, err); | 3050 | ext3_std_error(inode->i_sb, err); |