diff options
| -rw-r--r-- | fs/ext4/fsync.c | 16 | ||||
| -rw-r--r-- | fs/jbd2/checkpoint.c | 15 | ||||
| -rw-r--r-- | fs/jbd2/commit.c | 19 | ||||
| -rw-r--r-- | include/linux/jbd2.h | 1 |
4 files changed, 41 insertions, 10 deletions
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 0b22497d92e1..98bd140aad01 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c | |||
| @@ -88,9 +88,21 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) | |||
| 88 | return ext4_force_commit(inode->i_sb); | 88 | return ext4_force_commit(inode->i_sb); |
| 89 | 89 | ||
| 90 | commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid; | 90 | commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid; |
| 91 | if (jbd2_log_start_commit(journal, commit_tid)) | 91 | if (jbd2_log_start_commit(journal, commit_tid)) { |
| 92 | /* | ||
| 93 | * When the journal is on a different device than the | ||
| 94 | * fs data disk, we need to issue the barrier in | ||
| 95 | * writeback mode. (In ordered mode, the jbd2 layer | ||
| 96 | * will take care of issuing the barrier. In | ||
| 97 | * data=journal, all of the data blocks are written to | ||
| 98 | * the journal device.) | ||
| 99 | */ | ||
| 100 | if (ext4_should_writeback_data(inode) && | ||
| 101 | (journal->j_fs_dev != journal->j_dev) && | ||
| 102 | (journal->j_flags & JBD2_BARRIER)) | ||
| 103 | blkdev_issue_flush(inode->i_sb->s_bdev, NULL); | ||
| 92 | jbd2_log_wait_commit(journal, commit_tid); | 104 | jbd2_log_wait_commit(journal, commit_tid); |
| 93 | else if (journal->j_flags & JBD2_BARRIER) | 105 | } else if (journal->j_flags & JBD2_BARRIER) |
| 94 | blkdev_issue_flush(inode->i_sb->s_bdev, NULL); | 106 | blkdev_issue_flush(inode->i_sb->s_bdev, NULL); |
| 95 | return ret; | 107 | return ret; |
| 96 | } | 108 | } |
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index ca0f5eb62b20..886849370950 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/jbd2.h> | 22 | #include <linux/jbd2.h> |
| 23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
| 24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
| 25 | #include <linux/blkdev.h> | ||
| 25 | #include <trace/events/jbd2.h> | 26 | #include <trace/events/jbd2.h> |
| 26 | 27 | ||
| 27 | /* | 28 | /* |
| @@ -515,6 +516,20 @@ int jbd2_cleanup_journal_tail(journal_t *journal) | |||
| 515 | journal->j_tail_sequence = first_tid; | 516 | journal->j_tail_sequence = first_tid; |
| 516 | journal->j_tail = blocknr; | 517 | journal->j_tail = blocknr; |
| 517 | spin_unlock(&journal->j_state_lock); | 518 | spin_unlock(&journal->j_state_lock); |
| 519 | |||
| 520 | /* | ||
| 521 | * If there is an external journal, we need to make sure that | ||
| 522 | * any data blocks that were recently written out --- perhaps | ||
| 523 | * by jbd2_log_do_checkpoint() --- are flushed out before we | ||
| 524 | * drop the transactions from the external journal. It's | ||
| 525 | * unlikely this will be necessary, especially with a | ||
| 526 | * appropriately sized journal, but we need this to guarantee | ||
| 527 | * correctness. Fortunately jbd2_cleanup_journal_tail() | ||
| 528 | * doesn't get called all that often. | ||
| 529 | */ | ||
| 530 | if ((journal->j_fs_dev != journal->j_dev) && | ||
| 531 | (journal->j_flags & JBD2_BARRIER)) | ||
| 532 | blkdev_issue_flush(journal->j_fs_dev, NULL); | ||
| 518 | if (!(journal->j_flags & JBD2_ABORT)) | 533 | if (!(journal->j_flags & JBD2_ABORT)) |
| 519 | jbd2_journal_update_superblock(journal, 1); | 534 | jbd2_journal_update_superblock(journal, 1); |
| 520 | return 0; | 535 | return 0; |
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 6a10238d2c63..1bc74b6f26d2 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
| @@ -259,6 +259,7 @@ static int journal_submit_data_buffers(journal_t *journal, | |||
| 259 | ret = err; | 259 | ret = err; |
| 260 | spin_lock(&journal->j_list_lock); | 260 | spin_lock(&journal->j_list_lock); |
| 261 | J_ASSERT(jinode->i_transaction == commit_transaction); | 261 | J_ASSERT(jinode->i_transaction == commit_transaction); |
| 262 | commit_transaction->t_flushed_data_blocks = 1; | ||
| 262 | jinode->i_flags &= ~JI_COMMIT_RUNNING; | 263 | jinode->i_flags &= ~JI_COMMIT_RUNNING; |
| 263 | wake_up_bit(&jinode->i_flags, __JI_COMMIT_RUNNING); | 264 | wake_up_bit(&jinode->i_flags, __JI_COMMIT_RUNNING); |
| 264 | } | 265 | } |
| @@ -708,8 +709,17 @@ start_journal_io: | |||
| 708 | } | 709 | } |
| 709 | } | 710 | } |
| 710 | 711 | ||
| 711 | /* Done it all: now write the commit record asynchronously. */ | 712 | /* |
| 713 | * If the journal is not located on the file system device, | ||
| 714 | * then we must flush the file system device before we issue | ||
| 715 | * the commit record | ||
| 716 | */ | ||
| 717 | if (commit_transaction->t_flushed_data_blocks && | ||
| 718 | (journal->j_fs_dev != journal->j_dev) && | ||
| 719 | (journal->j_flags & JBD2_BARRIER)) | ||
| 720 | blkdev_issue_flush(journal->j_fs_dev, NULL); | ||
| 712 | 721 | ||
| 722 | /* Done it all: now write the commit record asynchronously. */ | ||
| 713 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, | 723 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, |
| 714 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) { | 724 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) { |
| 715 | err = journal_submit_commit_record(journal, commit_transaction, | 725 | err = journal_submit_commit_record(journal, commit_transaction, |
| @@ -720,13 +730,6 @@ start_journal_io: | |||
| 720 | blkdev_issue_flush(journal->j_dev, NULL); | 730 | blkdev_issue_flush(journal->j_dev, NULL); |
| 721 | } | 731 | } |
| 722 | 732 | ||
| 723 | /* | ||
| 724 | * This is the right place to wait for data buffers both for ASYNC | ||
| 725 | * and !ASYNC commit. If commit is ASYNC, we need to wait only after | ||
| 726 | * the commit block went to disk (which happens above). If commit is | ||
| 727 | * SYNC, we need to wait for data buffers before we start writing | ||
| 728 | * commit block, which happens below in such setting. | ||
| 729 | */ | ||
| 730 | err = journal_finish_inode_data_buffers(journal, commit_transaction); | 733 | err = journal_finish_inode_data_buffers(journal, commit_transaction); |
| 731 | if (err) { | 734 | if (err) { |
| 732 | printk(KERN_WARNING | 735 | printk(KERN_WARNING |
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index f1011f7f3d41..638ce4554c76 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h | |||
| @@ -653,6 +653,7 @@ struct transaction_s | |||
| 653 | * waiting for it to finish. | 653 | * waiting for it to finish. |
| 654 | */ | 654 | */ |
| 655 | unsigned int t_synchronous_commit:1; | 655 | unsigned int t_synchronous_commit:1; |
| 656 | unsigned int t_flushed_data_blocks:1; | ||
| 656 | 657 | ||
| 657 | /* | 658 | /* |
| 658 | * For use by the filesystem to store fs-specific data | 659 | * For use by the filesystem to store fs-specific data |
