diff options
-rw-r--r-- | fs/buffer.c | 5 | ||||
-rw-r--r-- | fs/ext3/file.c | 4 | ||||
-rw-r--r-- | fs/ext3/inode.c | 3 | ||||
-rw-r--r-- | fs/ext3/namei.c | 6 | ||||
-rw-r--r-- | fs/jbd/commit.c | 23 | ||||
-rw-r--r-- | fs/jbd/transaction.c | 2 | ||||
-rw-r--r-- | include/linux/ext3_fs.h | 1 | ||||
-rw-r--r-- | include/linux/jbd.h | 5 |
8 files changed, 38 insertions, 11 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index c2fa1be4923d..5d55a896ff78 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -1595,6 +1595,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page, | |||
1595 | struct buffer_head *bh, *head; | 1595 | struct buffer_head *bh, *head; |
1596 | const unsigned blocksize = 1 << inode->i_blkbits; | 1596 | const unsigned blocksize = 1 << inode->i_blkbits; |
1597 | int nr_underway = 0; | 1597 | int nr_underway = 0; |
1598 | int write_op = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE); | ||
1598 | 1599 | ||
1599 | BUG_ON(!PageLocked(page)); | 1600 | BUG_ON(!PageLocked(page)); |
1600 | 1601 | ||
@@ -1686,7 +1687,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page, | |||
1686 | do { | 1687 | do { |
1687 | struct buffer_head *next = bh->b_this_page; | 1688 | struct buffer_head *next = bh->b_this_page; |
1688 | if (buffer_async_write(bh)) { | 1689 | if (buffer_async_write(bh)) { |
1689 | submit_bh(WRITE, bh); | 1690 | submit_bh(write_op, bh); |
1690 | nr_underway++; | 1691 | nr_underway++; |
1691 | } | 1692 | } |
1692 | bh = next; | 1693 | bh = next; |
@@ -1740,7 +1741,7 @@ recover: | |||
1740 | struct buffer_head *next = bh->b_this_page; | 1741 | struct buffer_head *next = bh->b_this_page; |
1741 | if (buffer_async_write(bh)) { | 1742 | if (buffer_async_write(bh)) { |
1742 | clear_buffer_dirty(bh); | 1743 | clear_buffer_dirty(bh); |
1743 | submit_bh(WRITE, bh); | 1744 | submit_bh(write_op, bh); |
1744 | nr_underway++; | 1745 | nr_underway++; |
1745 | } | 1746 | } |
1746 | bh = next; | 1747 | bh = next; |
diff --git a/fs/ext3/file.c b/fs/ext3/file.c index 521f8238b2fa..5b49704b231b 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c | |||
@@ -33,6 +33,10 @@ | |||
33 | */ | 33 | */ |
34 | static int ext3_release_file (struct inode * inode, struct file * filp) | 34 | static int ext3_release_file (struct inode * inode, struct file * filp) |
35 | { | 35 | { |
36 | if (EXT3_I(inode)->i_state & EXT3_STATE_FLUSH_ON_CLOSE) { | ||
37 | filemap_flush(inode->i_mapping); | ||
38 | EXT3_I(inode)->i_state &= ~EXT3_STATE_FLUSH_ON_CLOSE; | ||
39 | } | ||
36 | /* if we are the last writer on the inode, drop the block reservation */ | 40 | /* if we are the last writer on the inode, drop the block reservation */ |
37 | if ((filp->f_mode & FMODE_WRITE) && | 41 | if ((filp->f_mode & FMODE_WRITE) && |
38 | (atomic_read(&inode->i_writecount) == 1)) | 42 | (atomic_read(&inode->i_writecount) == 1)) |
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index d3ef6566b019..466a332e0bd1 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -2363,6 +2363,9 @@ void ext3_truncate(struct inode *inode) | |||
2363 | if (!ext3_can_truncate(inode)) | 2363 | if (!ext3_can_truncate(inode)) |
2364 | return; | 2364 | return; |
2365 | 2365 | ||
2366 | if (inode->i_size == 0 && ext3_should_writeback_data(inode)) | ||
2367 | ei->i_state |= EXT3_STATE_FLUSH_ON_CLOSE; | ||
2368 | |||
2366 | /* | 2369 | /* |
2367 | * We have to lock the EOF page here, because lock_page() nests | 2370 | * We have to lock the EOF page here, because lock_page() nests |
2368 | * outside journal_start(). | 2371 | * outside journal_start(). |
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 6ddaa0a42b24..6ff7b9730234 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c | |||
@@ -2274,7 +2274,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2274 | struct inode * old_inode, * new_inode; | 2274 | struct inode * old_inode, * new_inode; |
2275 | struct buffer_head * old_bh, * new_bh, * dir_bh; | 2275 | struct buffer_head * old_bh, * new_bh, * dir_bh; |
2276 | struct ext3_dir_entry_2 * old_de, * new_de; | 2276 | struct ext3_dir_entry_2 * old_de, * new_de; |
2277 | int retval; | 2277 | int retval, flush_file = 0; |
2278 | 2278 | ||
2279 | old_bh = new_bh = dir_bh = NULL; | 2279 | old_bh = new_bh = dir_bh = NULL; |
2280 | 2280 | ||
@@ -2410,6 +2410,8 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2410 | ext3_mark_inode_dirty(handle, new_inode); | 2410 | ext3_mark_inode_dirty(handle, new_inode); |
2411 | if (!new_inode->i_nlink) | 2411 | if (!new_inode->i_nlink) |
2412 | ext3_orphan_add(handle, new_inode); | 2412 | ext3_orphan_add(handle, new_inode); |
2413 | if (ext3_should_writeback_data(new_inode)) | ||
2414 | flush_file = 1; | ||
2413 | } | 2415 | } |
2414 | retval = 0; | 2416 | retval = 0; |
2415 | 2417 | ||
@@ -2418,6 +2420,8 @@ end_rename: | |||
2418 | brelse (old_bh); | 2420 | brelse (old_bh); |
2419 | brelse (new_bh); | 2421 | brelse (new_bh); |
2420 | ext3_journal_stop(handle); | 2422 | ext3_journal_stop(handle); |
2423 | if (retval == 0 && flush_file) | ||
2424 | filemap_flush(old_inode->i_mapping); | ||
2421 | return retval; | 2425 | return retval; |
2422 | } | 2426 | } |
2423 | 2427 | ||
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 3fbffb1ea714..f8077b9c8981 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/mm.h> | 21 | #include <linux/mm.h> |
22 | #include <linux/pagemap.h> | 22 | #include <linux/pagemap.h> |
23 | #include <linux/bio.h> | ||
23 | 24 | ||
24 | /* | 25 | /* |
25 | * Default IO end handler for temporary BJ_IO buffer_heads. | 26 | * Default IO end handler for temporary BJ_IO buffer_heads. |
@@ -171,14 +172,15 @@ static int journal_write_commit_record(journal_t *journal, | |||
171 | return (ret == -EIO); | 172 | return (ret == -EIO); |
172 | } | 173 | } |
173 | 174 | ||
174 | static void journal_do_submit_data(struct buffer_head **wbuf, int bufs) | 175 | static void journal_do_submit_data(struct buffer_head **wbuf, int bufs, |
176 | int write_op) | ||
175 | { | 177 | { |
176 | int i; | 178 | int i; |
177 | 179 | ||
178 | for (i = 0; i < bufs; i++) { | 180 | for (i = 0; i < bufs; i++) { |
179 | wbuf[i]->b_end_io = end_buffer_write_sync; | 181 | wbuf[i]->b_end_io = end_buffer_write_sync; |
180 | /* We use-up our safety reference in submit_bh() */ | 182 | /* We use-up our safety reference in submit_bh() */ |
181 | submit_bh(WRITE, wbuf[i]); | 183 | submit_bh(write_op, wbuf[i]); |
182 | } | 184 | } |
183 | } | 185 | } |
184 | 186 | ||
@@ -186,7 +188,8 @@ static void journal_do_submit_data(struct buffer_head **wbuf, int bufs) | |||
186 | * Submit all the data buffers to disk | 188 | * Submit all the data buffers to disk |
187 | */ | 189 | */ |
188 | static int journal_submit_data_buffers(journal_t *journal, | 190 | static int journal_submit_data_buffers(journal_t *journal, |
189 | transaction_t *commit_transaction) | 191 | transaction_t *commit_transaction, |
192 | int write_op) | ||
190 | { | 193 | { |
191 | struct journal_head *jh; | 194 | struct journal_head *jh; |
192 | struct buffer_head *bh; | 195 | struct buffer_head *bh; |
@@ -225,7 +228,7 @@ write_out_data: | |||
225 | BUFFER_TRACE(bh, "needs blocking lock"); | 228 | BUFFER_TRACE(bh, "needs blocking lock"); |
226 | spin_unlock(&journal->j_list_lock); | 229 | spin_unlock(&journal->j_list_lock); |
227 | /* Write out all data to prevent deadlocks */ | 230 | /* Write out all data to prevent deadlocks */ |
228 | journal_do_submit_data(wbuf, bufs); | 231 | journal_do_submit_data(wbuf, bufs, write_op); |
229 | bufs = 0; | 232 | bufs = 0; |
230 | lock_buffer(bh); | 233 | lock_buffer(bh); |
231 | spin_lock(&journal->j_list_lock); | 234 | spin_lock(&journal->j_list_lock); |
@@ -256,7 +259,7 @@ write_out_data: | |||
256 | jbd_unlock_bh_state(bh); | 259 | jbd_unlock_bh_state(bh); |
257 | if (bufs == journal->j_wbufsize) { | 260 | if (bufs == journal->j_wbufsize) { |
258 | spin_unlock(&journal->j_list_lock); | 261 | spin_unlock(&journal->j_list_lock); |
259 | journal_do_submit_data(wbuf, bufs); | 262 | journal_do_submit_data(wbuf, bufs, write_op); |
260 | bufs = 0; | 263 | bufs = 0; |
261 | goto write_out_data; | 264 | goto write_out_data; |
262 | } | 265 | } |
@@ -286,7 +289,7 @@ write_out_data: | |||
286 | } | 289 | } |
287 | } | 290 | } |
288 | spin_unlock(&journal->j_list_lock); | 291 | spin_unlock(&journal->j_list_lock); |
289 | journal_do_submit_data(wbuf, bufs); | 292 | journal_do_submit_data(wbuf, bufs, write_op); |
290 | 293 | ||
291 | return err; | 294 | return err; |
292 | } | 295 | } |
@@ -315,6 +318,7 @@ void journal_commit_transaction(journal_t *journal) | |||
315 | int first_tag = 0; | 318 | int first_tag = 0; |
316 | int tag_flag; | 319 | int tag_flag; |
317 | int i; | 320 | int i; |
321 | int write_op = WRITE; | ||
318 | 322 | ||
319 | /* | 323 | /* |
320 | * First job: lock down the current transaction and wait for | 324 | * First job: lock down the current transaction and wait for |
@@ -347,6 +351,8 @@ void journal_commit_transaction(journal_t *journal) | |||
347 | spin_lock(&journal->j_state_lock); | 351 | spin_lock(&journal->j_state_lock); |
348 | commit_transaction->t_state = T_LOCKED; | 352 | commit_transaction->t_state = T_LOCKED; |
349 | 353 | ||
354 | if (commit_transaction->t_synchronous_commit) | ||
355 | write_op = WRITE_SYNC; | ||
350 | spin_lock(&commit_transaction->t_handle_lock); | 356 | spin_lock(&commit_transaction->t_handle_lock); |
351 | while (commit_transaction->t_updates) { | 357 | while (commit_transaction->t_updates) { |
352 | DEFINE_WAIT(wait); | 358 | DEFINE_WAIT(wait); |
@@ -431,7 +437,8 @@ void journal_commit_transaction(journal_t *journal) | |||
431 | * Now start flushing things to disk, in the order they appear | 437 | * Now start flushing things to disk, in the order they appear |
432 | * on the transaction lists. Data blocks go first. | 438 | * on the transaction lists. Data blocks go first. |
433 | */ | 439 | */ |
434 | err = journal_submit_data_buffers(journal, commit_transaction); | 440 | err = journal_submit_data_buffers(journal, commit_transaction, |
441 | write_op); | ||
435 | 442 | ||
436 | /* | 443 | /* |
437 | * Wait for all previously submitted IO to complete. | 444 | * Wait for all previously submitted IO to complete. |
@@ -660,7 +667,7 @@ start_journal_io: | |||
660 | clear_buffer_dirty(bh); | 667 | clear_buffer_dirty(bh); |
661 | set_buffer_uptodate(bh); | 668 | set_buffer_uptodate(bh); |
662 | bh->b_end_io = journal_end_buffer_io_sync; | 669 | bh->b_end_io = journal_end_buffer_io_sync; |
663 | submit_bh(WRITE, bh); | 670 | submit_bh(write_op, bh); |
664 | } | 671 | } |
665 | cond_resched(); | 672 | cond_resched(); |
666 | 673 | ||
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index e6a117431277..ed886e6db399 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c | |||
@@ -1440,6 +1440,8 @@ int journal_stop(handle_t *handle) | |||
1440 | } | 1440 | } |
1441 | } | 1441 | } |
1442 | 1442 | ||
1443 | if (handle->h_sync) | ||
1444 | transaction->t_synchronous_commit = 1; | ||
1443 | current->journal_info = NULL; | 1445 | current->journal_info = NULL; |
1444 | spin_lock(&journal->j_state_lock); | 1446 | spin_lock(&journal->j_state_lock); |
1445 | spin_lock(&transaction->t_handle_lock); | 1447 | spin_lock(&transaction->t_handle_lock); |
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index e263acaa405b..634a5e5aba3e 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h | |||
@@ -208,6 +208,7 @@ static inline __u32 ext3_mask_flags(umode_t mode, __u32 flags) | |||
208 | #define EXT3_STATE_JDATA 0x00000001 /* journaled data exists */ | 208 | #define EXT3_STATE_JDATA 0x00000001 /* journaled data exists */ |
209 | #define EXT3_STATE_NEW 0x00000002 /* inode is newly created */ | 209 | #define EXT3_STATE_NEW 0x00000002 /* inode is newly created */ |
210 | #define EXT3_STATE_XATTR 0x00000004 /* has in-inode xattrs */ | 210 | #define EXT3_STATE_XATTR 0x00000004 /* has in-inode xattrs */ |
211 | #define EXT3_STATE_FLUSH_ON_CLOSE 0x00000008 | ||
211 | 212 | ||
212 | /* Used to pass group descriptor data when online resize is done */ | 213 | /* Used to pass group descriptor data when online resize is done */ |
213 | struct ext3_new_group_input { | 214 | struct ext3_new_group_input { |
diff --git a/include/linux/jbd.h b/include/linux/jbd.h index 64246dce5663..2c6943152c21 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h | |||
@@ -552,6 +552,11 @@ struct transaction_s | |||
552 | */ | 552 | */ |
553 | int t_handle_count; | 553 | int t_handle_count; |
554 | 554 | ||
555 | /* | ||
556 | * This transaction is being forced and some process is | ||
557 | * waiting for it to finish. | ||
558 | */ | ||
559 | int t_synchronous_commit:1; | ||
555 | }; | 560 | }; |
556 | 561 | ||
557 | /** | 562 | /** |