diff options
Diffstat (limited to 'fs/ext4/fsync.c')
-rw-r--r-- | fs/ext4/fsync.c | 33 |
1 files changed, 24 insertions, 9 deletions
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 7829b287822a..e9473cbe80df 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c | |||
@@ -101,7 +101,7 @@ extern int ext4_flush_completed_IO(struct inode *inode) | |||
101 | * to the work-to-be schedule is freed. | 101 | * to the work-to-be schedule is freed. |
102 | * | 102 | * |
103 | * Thus we need to keep the io structure still valid here after | 103 | * Thus we need to keep the io structure still valid here after |
104 | * convertion finished. The io structure has a flag to | 104 | * conversion finished. The io structure has a flag to |
105 | * avoid double converting from both fsync and background work | 105 | * avoid double converting from both fsync and background work |
106 | * queue work. | 106 | * queue work. |
107 | */ | 107 | */ |
@@ -125,9 +125,11 @@ extern int ext4_flush_completed_IO(struct inode *inode) | |||
125 | * the parent directory's parent as well, and so on recursively, if | 125 | * the parent directory's parent as well, and so on recursively, if |
126 | * they are also freshly created. | 126 | * they are also freshly created. |
127 | */ | 127 | */ |
128 | static void ext4_sync_parent(struct inode *inode) | 128 | static int ext4_sync_parent(struct inode *inode) |
129 | { | 129 | { |
130 | struct writeback_control wbc; | ||
130 | struct dentry *dentry = NULL; | 131 | struct dentry *dentry = NULL; |
132 | int ret = 0; | ||
131 | 133 | ||
132 | while (inode && ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) { | 134 | while (inode && ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) { |
133 | ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY); | 135 | ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY); |
@@ -136,8 +138,17 @@ static void ext4_sync_parent(struct inode *inode) | |||
136 | if (!dentry || !dentry->d_parent || !dentry->d_parent->d_inode) | 138 | if (!dentry || !dentry->d_parent || !dentry->d_parent->d_inode) |
137 | break; | 139 | break; |
138 | inode = dentry->d_parent->d_inode; | 140 | inode = dentry->d_parent->d_inode; |
139 | sync_mapping_buffers(inode->i_mapping); | 141 | ret = sync_mapping_buffers(inode->i_mapping); |
142 | if (ret) | ||
143 | break; | ||
144 | memset(&wbc, 0, sizeof(wbc)); | ||
145 | wbc.sync_mode = WB_SYNC_ALL; | ||
146 | wbc.nr_to_write = 0; /* only write out the inode */ | ||
147 | ret = sync_inode(inode, &wbc); | ||
148 | if (ret) | ||
149 | break; | ||
140 | } | 150 | } |
151 | return ret; | ||
141 | } | 152 | } |
142 | 153 | ||
143 | /* | 154 | /* |
@@ -164,20 +175,20 @@ int ext4_sync_file(struct file *file, int datasync) | |||
164 | 175 | ||
165 | J_ASSERT(ext4_journal_current_handle() == NULL); | 176 | J_ASSERT(ext4_journal_current_handle() == NULL); |
166 | 177 | ||
167 | trace_ext4_sync_file(file, datasync); | 178 | trace_ext4_sync_file_enter(file, datasync); |
168 | 179 | ||
169 | if (inode->i_sb->s_flags & MS_RDONLY) | 180 | if (inode->i_sb->s_flags & MS_RDONLY) |
170 | return 0; | 181 | return 0; |
171 | 182 | ||
172 | ret = ext4_flush_completed_IO(inode); | 183 | ret = ext4_flush_completed_IO(inode); |
173 | if (ret < 0) | 184 | if (ret < 0) |
174 | return ret; | 185 | goto out; |
175 | 186 | ||
176 | if (!journal) { | 187 | if (!journal) { |
177 | ret = generic_file_fsync(file, datasync); | 188 | ret = generic_file_fsync(file, datasync); |
178 | if (!ret && !list_empty(&inode->i_dentry)) | 189 | if (!ret && !list_empty(&inode->i_dentry)) |
179 | ext4_sync_parent(inode); | 190 | ret = ext4_sync_parent(inode); |
180 | return ret; | 191 | goto out; |
181 | } | 192 | } |
182 | 193 | ||
183 | /* | 194 | /* |
@@ -194,8 +205,10 @@ int ext4_sync_file(struct file *file, int datasync) | |||
194 | * (they were dirtied by commit). But that's OK - the blocks are | 205 | * (they were dirtied by commit). But that's OK - the blocks are |
195 | * safe in-journal, which is all fsync() needs to ensure. | 206 | * safe in-journal, which is all fsync() needs to ensure. |
196 | */ | 207 | */ |
197 | if (ext4_should_journal_data(inode)) | 208 | if (ext4_should_journal_data(inode)) { |
198 | return ext4_force_commit(inode->i_sb); | 209 | ret = ext4_force_commit(inode->i_sb); |
210 | goto out; | ||
211 | } | ||
199 | 212 | ||
200 | commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid; | 213 | commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid; |
201 | if (jbd2_log_start_commit(journal, commit_tid)) { | 214 | if (jbd2_log_start_commit(journal, commit_tid)) { |
@@ -215,5 +228,7 @@ int ext4_sync_file(struct file *file, int datasync) | |||
215 | ret = jbd2_log_wait_commit(journal, commit_tid); | 228 | ret = jbd2_log_wait_commit(journal, commit_tid); |
216 | } else if (journal->j_flags & JBD2_BARRIER) | 229 | } else if (journal->j_flags & JBD2_BARRIER) |
217 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); | 230 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); |
231 | out: | ||
232 | trace_ext4_sync_file_exit(inode, ret); | ||
218 | return ret; | 233 | return ret; |
219 | } | 234 | } |