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/fsync.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/fsync.c')
-rw-r--r-- | fs/ext3/fsync.c | 36 |
1 files changed, 16 insertions, 20 deletions
diff --git a/fs/ext3/fsync.c b/fs/ext3/fsync.c index 451d166bbe93..8209f266e9ad 100644 --- a/fs/ext3/fsync.c +++ b/fs/ext3/fsync.c | |||
@@ -46,19 +46,21 @@ | |||
46 | int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync) | 46 | int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync) |
47 | { | 47 | { |
48 | struct inode *inode = dentry->d_inode; | 48 | struct inode *inode = dentry->d_inode; |
49 | struct ext3_inode_info *ei = EXT3_I(inode); | ||
50 | journal_t *journal = EXT3_SB(inode->i_sb)->s_journal; | ||
49 | int ret = 0; | 51 | int ret = 0; |
52 | tid_t commit_tid; | ||
53 | |||
54 | if (inode->i_sb->s_flags & MS_RDONLY) | ||
55 | return 0; | ||
50 | 56 | ||
51 | J_ASSERT(ext3_journal_current_handle() == NULL); | 57 | J_ASSERT(ext3_journal_current_handle() == NULL); |
52 | 58 | ||
53 | /* | 59 | /* |
54 | * data=writeback: | 60 | * data=writeback,ordered: |
55 | * The caller's filemap_fdatawrite()/wait will sync the data. | 61 | * The caller's filemap_fdatawrite()/wait will sync the data. |
56 | * sync_inode() will sync the metadata | 62 | * Metadata is in the journal, we wait for a proper transaction |
57 | * | 63 | * to commit here. |
58 | * data=ordered: | ||
59 | * The caller's filemap_fdatawrite() will write the data and | ||
60 | * sync_inode() will write the inode if it is dirty. Then the caller's | ||
61 | * filemap_fdatawait() will wait on the pages. | ||
62 | * | 64 | * |
63 | * data=journal: | 65 | * data=journal: |
64 | * filemap_fdatawrite won't do anything (the buffers are clean). | 66 | * filemap_fdatawrite won't do anything (the buffers are clean). |
@@ -73,22 +75,16 @@ int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync) | |||
73 | goto out; | 75 | goto out; |
74 | } | 76 | } |
75 | 77 | ||
76 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | 78 | if (datasync) |
77 | goto flush; | 79 | commit_tid = atomic_read(&ei->i_datasync_tid); |
80 | else | ||
81 | commit_tid = atomic_read(&ei->i_sync_tid); | ||
78 | 82 | ||
79 | /* | 83 | if (log_start_commit(journal, commit_tid)) { |
80 | * The VFS has written the file data. If the inode is unaltered | 84 | log_wait_commit(journal, commit_tid); |
81 | * then we need not start a commit. | ||
82 | */ | ||
83 | if (inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC)) { | ||
84 | struct writeback_control wbc = { | ||
85 | .sync_mode = WB_SYNC_ALL, | ||
86 | .nr_to_write = 0, /* sys_fsync did this */ | ||
87 | }; | ||
88 | ret = sync_inode(inode, &wbc); | ||
89 | goto out; | 85 | goto out; |
90 | } | 86 | } |
91 | flush: | 87 | |
92 | /* | 88 | /* |
93 | * In case we didn't commit a transaction, we have to flush | 89 | * In case we didn't commit a transaction, we have to flush |
94 | * disk caches manually so that data really is on persistent | 90 | * disk caches manually so that data really is on persistent |