From: "Theodore Ts'o" <tytso@mit.edu>
To: Ext4 Developers List <linux-ext4@vger.kernel.org>,
Linux Kernel Developers List <linux-kernel@vger.kernel.org>
Cc: Mingming Cao <cmm@us.ibm.com>, "Theodore Ts'o" <tytso@mit.edu>
Subject: [PATCH 14/52] jbd2: fix race between jbd2_journal_try_to_free_buffers() and jbd2 commit transaction
Date: Sat, 5 Jul 2008 13:35:40 -0400 [thread overview]
Message-ID: <1215279378-30504-15-git-send-email-tytso@mit.edu> (raw)
In-Reply-To: <1215279378-30504-14-git-send-email-tytso@mit.edu>
From: Mingming Cao <cmm@us.ibm.com>
journal_try_to_free_buffers() could race with jbd commit transaction
when the later is holding the buffer reference while waiting for the
data buffer to flush to disk. If the caller of
journal_try_to_free_buffers() request tries hard to release the buffers,
it will treat the failure as error and return back to the caller. We
have seen the directo IO failed due to this race. Some of the caller of
releasepage() also expecting the buffer to be dropped when passed with
GFP_KERNEL mask to the releasepage()->journal_try_to_free_buffers().
With this patch, if the caller is passing the GFP_KERNEL to indicating
this call could wait, in case of try_to_free_buffers() failed, let's
waiting for journal_commit_transaction() to finish commit the current
committing transaction , then try to free those buffers again with
journal locked.
Signed-off-by: Mingming Cao <cmm@us.ibm.com>
Reviewed-by: Badari Pulavarty <pbadari@us.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
---
fs/jbd2/transaction.c | 62 +++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 58 insertions(+), 4 deletions(-)
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index d6e006e..8525dff 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -41,7 +41,6 @@ static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh);
* new transaction and we can't block without protecting against other
* processes trying to touch the journal while it is in transition.
*
- * Called under j_state_lock
*/
static transaction_t *
@@ -1656,12 +1655,43 @@ out:
return;
}
+/*
+ * jbd2_journal_try_to_free_buffers() could race with
+ * jbd2_journal_commit_transaction(). The later might still hold the
+ * reference count to the buffers when inspecting them on
+ * t_syncdata_list or t_locked_list.
+ *
+ * jbd2_journal_try_to_free_buffers() will call this function to
+ * wait for the current transaction to finish syncing data buffers, before
+ * try to free that buffer.
+ *
+ * Called with journal->j_state_lock hold.
+ */
+static void jbd2_journal_wait_for_transaction_sync_data(journal_t *journal)
+{
+ transaction_t *transaction = NULL;
+ tid_t tid;
+
+ spin_lock(&journal->j_state_lock);
+ transaction = journal->j_committing_transaction;
+
+ if (!transaction) {
+ spin_unlock(&journal->j_state_lock);
+ return;
+ }
+
+ tid = transaction->t_tid;
+ spin_unlock(&journal->j_state_lock);
+ jbd2_log_wait_commit(journal, tid);
+}
/**
* int jbd2_journal_try_to_free_buffers() - try to free page buffers.
* @journal: journal for operation
* @page: to try and free
- * @unused_gfp_mask: unused
+ * @gfp_mask: we use the mask to detect how hard should we try to release
+ * buffers. If __GFP_WAIT and __GFP_FS is set, we wait for commit code to
+ * release the buffers.
*
*
* For all the buffers on this page,
@@ -1690,9 +1720,11 @@ out:
* journal_try_to_free_buffer() is changing its state. But that
* cannot happen because we never reallocate freed data as metadata
* while the data is part of a transaction. Yes?
+ *
+ * Return 0 on failure, 1 on success
*/
int jbd2_journal_try_to_free_buffers(journal_t *journal,
- struct page *page, gfp_t unused_gfp_mask)
+ struct page *page, gfp_t gfp_mask)
{
struct buffer_head *head;
struct buffer_head *bh;
@@ -1708,7 +1740,8 @@ int jbd2_journal_try_to_free_buffers(journal_t *journal,
/*
* We take our own ref against the journal_head here to avoid
* having to add tons of locking around each instance of
- * jbd2_journal_remove_journal_head() and jbd2_journal_put_journal_head().
+ * jbd2_journal_remove_journal_head() and
+ * jbd2_journal_put_journal_head().
*/
jh = jbd2_journal_grab_journal_head(bh);
if (!jh)
@@ -1721,7 +1754,28 @@ int jbd2_journal_try_to_free_buffers(journal_t *journal,
if (buffer_jbd(bh))
goto busy;
} while ((bh = bh->b_this_page) != head);
+
ret = try_to_free_buffers(page);
+
+ /*
+ * There are a number of places where jbd2_journal_try_to_free_buffers()
+ * could race with jbd2_journal_commit_transaction(), the later still
+ * holds the reference to the buffers to free while processing them.
+ * try_to_free_buffers() failed to free those buffers. Some of the
+ * caller of releasepage() request page buffers to be dropped, otherwise
+ * treat the fail-to-free as errors (such as generic_file_direct_IO())
+ *
+ * So, if the caller of try_to_release_page() wants the synchronous
+ * behaviour(i.e make sure buffers are dropped upon return),
+ * let's wait for the current transaction to finish flush of
+ * dirty data buffers, then try to free those buffers again,
+ * with the journal locked.
+ */
+ if (ret == 0 && (gfp_mask & __GFP_WAIT) && (gfp_mask & __GFP_FS)) {
+ jbd2_journal_wait_for_transaction_sync_data(journal);
+ ret = try_to_free_buffers(page);
+ }
+
busy:
return ret;
}
--
1.5.6.rc3.1.g36b7.dirty
next prev parent reply other threads:[~2008-07-05 17:49 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-07-05 17:35 Ext4 patches for the next merge window Theodore Ts'o
2008-07-05 17:35 ` [PATCH 01/52] ext4: fix comments to say "ext4" Theodore Ts'o
2008-07-05 17:35 ` [PATCH 02/52] ext4: start searching for the right extent from the goal group Theodore Ts'o
2008-07-05 17:35 ` [PATCH 03/52] ext4: Use BUG_ON() instead of BUG() Theodore Ts'o
2008-07-05 17:35 ` [PATCH 04/52] ext4: switch to seq_files Theodore Ts'o
2008-07-05 17:35 ` [PATCH 05/52] ext4: improve some code in rb tree part of dir.c Theodore Ts'o
2008-07-05 17:35 ` [PATCH 06/52] ext4: Fix ext4_mb_init_cache return error Theodore Ts'o
2008-07-05 17:35 ` [PATCH 07/52] ext4: add error processing when calling ext4_mb_init_cache in mballoc Theodore Ts'o
2008-07-05 17:35 ` [PATCH 08/52] ext4: miscellaneous error checks and coding cleanups for mballoc Theodore Ts'o
2008-07-05 17:35 ` [PATCH 09/52] ext4: remove double definitions of xattr macros Theodore Ts'o
2008-07-05 17:35 ` [PATCH 10/52] ext4: Rename read_block_bitmap() to ext4_read_block_bitmap() Theodore Ts'o
2008-07-05 17:35 ` [PATCH 11/52] ext4: Remove unused variable from ext4_show_options Theodore Ts'o
2008-07-05 17:35 ` [PATCH 12/52] jbd2: Add commit time into the commit block Theodore Ts'o
2008-07-05 17:35 ` [PATCH 13/52] ext4: New inode allocation for FLEX_BG meta-data groups Theodore Ts'o
2008-07-05 17:35 ` Theodore Ts'o [this message]
2008-07-05 17:35 ` [PATCH 15/52] ext4: remove redundant code in ext4_fill_super() Theodore Ts'o
2008-07-05 17:35 ` [PATCH 16/52] ext4: remove quota allocation when ext4_mb_new_blocks fails Theodore Ts'o
2008-07-05 17:35 ` [PATCH 17/52] ext4: Update i_disksize properly when allocating from fallocate area Theodore Ts'o
2008-07-05 17:35 ` [PATCH 18/52] ext4: return error when calling ext4_ext_split failed Theodore Ts'o
2008-07-05 17:35 ` [PATCH 19/52] ext4: Make ext4_ext_find_extent fills ext_path completely Theodore Ts'o
2008-07-05 17:35 ` [PATCH 20/52] ext4: Fix ext4_ext_journal_restart() to reflect errors up to the caller Theodore Ts'o
2008-07-05 17:35 ` [PATCH 21/52] ext4: cleanup never-used magic numbers from htree code Theodore Ts'o
2008-07-05 17:35 ` [PATCH 22/52] ext4: Fix sparse warning Theodore Ts'o
2008-07-05 17:35 ` [PATCH 23/52] ext4: fix ext4_init_block_bitmap() for metablock block group Theodore Ts'o
2008-07-05 17:35 ` [PATCH 24/52] ext4: Use inode preallocation with -o noextents Theodore Ts'o
2008-07-05 17:35 ` [PATCH 25/52] ext4: cleanup block allocator Theodore Ts'o
2008-07-05 17:35 ` [PATCH 26/52] ext4: call blkdev_issue_flush on fsync Theodore Ts'o
2008-07-05 17:35 ` [PATCH 27/52] ext4: mballoc avoid use root reserved blocks for non root allocation Theodore Ts'o
2008-07-05 17:35 ` [PATCH 28/52] ext4: Set journal pointer to NULL when journal is released Theodore Ts'o
2008-07-05 17:35 ` [PATCH 29/52] ext4: use atomic functions to set bh_state Theodore Ts'o
2008-07-05 17:35 ` [PATCH 30/52] ext4: Add missing unlock to an error path in ext4_quota_write() Theodore Ts'o
2008-07-05 17:35 ` [PATCH 31/52] ext4: fix online resize with mballoc Theodore Ts'o
2008-07-05 17:35 ` [PATCH 32/52] ext4: Documentation updates Theodore Ts'o
2008-07-05 17:35 ` [PATCH 33/52] ext4: Use page_mkwrite vma_operations to get mmap write notification Theodore Ts'o
2008-07-05 17:36 ` [PATCH 34/52] vfs: Move mark_inode_dirty() from under page lock in generic_write_end() Theodore Ts'o
2008-07-05 17:36 ` [PATCH 35/52] ext4: Invert the locking order of page_lock and transaction start Theodore Ts'o
2008-07-05 17:36 ` [PATCH 36/52] ext4: Fix lock inversion in ext4_ext_truncate() Theodore Ts'o
2008-07-05 17:36 ` [PATCH 37/52] vfs: export filemap_fdatawrite_range() Theodore Ts'o
2008-07-05 17:36 ` [PATCH 38/52] jbd2: Implement data=ordered mode handling via inodes Theodore Ts'o
2008-07-05 17:36 ` [PATCH 39/52] ext4: Use new framework for data=ordered mode in JBD2 Theodore Ts'o
2008-07-05 17:36 ` [PATCH 40/52] jbd2: Remove data=ordered mode support using jbd buffer heads Theodore Ts'o
2008-07-05 17:36 ` [PATCH 41/52] vfs: add basic delayed allocation support Theodore Ts'o
2008-07-05 17:36 ` [PATCH 42/52] ext4: Add " Theodore Ts'o
2008-07-05 17:36 ` [PATCH 43/52] percpu_counter: new function percpu_counter_sum_and_set Theodore Ts'o
2008-07-05 17:36 ` [PATCH 44/52] ext4: delayed allocation ENOSPC handling Theodore Ts'o
2008-07-05 17:36 ` [PATCH 45/52] mm: Add range_cont mode for writeback Theodore Ts'o
2008-07-05 17:36 ` [PATCH 46/52] ext4: Invert lock ordering of page_lock and transaction start in delalloc Theodore Ts'o
2008-07-05 17:36 ` [PATCH 47/52] ext4: Add ordered mode support for delalloc Theodore Ts'o
2008-07-05 17:36 ` [PATCH 48/52] ext4: Handle page without buffers in ext4_*_writepage() Theodore Ts'o
2008-07-05 17:36 ` [PATCH 49/52] ext4: fix delalloc i_disksize early update issue Theodore Ts'o
2008-07-05 17:36 ` [PATCH 50/52] ext4: Enable delalloc by default Theodore Ts'o
2008-07-05 17:36 ` [PATCH 51/52] ext4: Don't allow nonextenst mount option for large filesystem Theodore Ts'o
2008-07-05 17:36 ` [PATCH 52/52] ext4: Documention update for new ordered mode and delayed allocation Theodore Ts'o
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1215279378-30504-15-git-send-email-tytso@mit.edu \
--to=tytso@mit.edu \
--cc=cmm@us.ibm.com \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®