|
@@ -30,6 +30,7 @@
|
|
|
#include <linux/module.h>
|
|
|
|
|
|
static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh);
|
|
|
+static void __jbd2_journal_unfile_buffer(struct journal_head *jh);
|
|
|
|
|
|
/*
|
|
|
* jbd2_get_transaction: obtain a new transaction_t object.
|
|
@@ -764,7 +765,6 @@ repeat:
|
|
|
if (!jh->b_transaction) {
|
|
|
JBUFFER_TRACE(jh, "no transaction");
|
|
|
J_ASSERT_JH(jh, !jh->b_next_transaction);
|
|
|
- jh->b_transaction = transaction;
|
|
|
JBUFFER_TRACE(jh, "file as BJ_Reserved");
|
|
|
spin_lock(&journal->j_list_lock);
|
|
|
__jbd2_journal_file_buffer(jh, transaction, BJ_Reserved);
|
|
@@ -895,8 +895,6 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
|
|
|
* committed and so it's safe to clear the dirty bit.
|
|
|
*/
|
|
|
clear_buffer_dirty(jh2bh(jh));
|
|
|
- jh->b_transaction = transaction;
|
|
|
-
|
|
|
/* first access by this transaction */
|
|
|
jh->b_modified = 0;
|
|
|
|
|
@@ -1230,8 +1228,6 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
|
|
|
__jbd2_journal_file_buffer(jh, transaction, BJ_Forget);
|
|
|
} else {
|
|
|
__jbd2_journal_unfile_buffer(jh);
|
|
|
- jbd2_journal_remove_journal_head(bh);
|
|
|
- __brelse(bh);
|
|
|
if (!buffer_jbd(bh)) {
|
|
|
spin_unlock(&journal->j_list_lock);
|
|
|
jbd_unlock_bh_state(bh);
|
|
@@ -1554,19 +1550,32 @@ void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh)
|
|
|
mark_buffer_dirty(bh); /* Expose it to the VM */
|
|
|
}
|
|
|
|
|
|
-void __jbd2_journal_unfile_buffer(struct journal_head *jh)
|
|
|
+/*
|
|
|
+ * Remove buffer from all transactions.
|
|
|
+ *
|
|
|
+ * Called with bh_state lock and j_list_lock
|
|
|
+ *
|
|
|
+ * jh and bh may be already freed when this function returns.
|
|
|
+ */
|
|
|
+static void __jbd2_journal_unfile_buffer(struct journal_head *jh)
|
|
|
{
|
|
|
__jbd2_journal_temp_unlink_buffer(jh);
|
|
|
jh->b_transaction = NULL;
|
|
|
+ jbd2_journal_put_journal_head(jh);
|
|
|
}
|
|
|
|
|
|
void jbd2_journal_unfile_buffer(journal_t *journal, struct journal_head *jh)
|
|
|
{
|
|
|
- jbd_lock_bh_state(jh2bh(jh));
|
|
|
+ struct buffer_head *bh = jh2bh(jh);
|
|
|
+
|
|
|
+ /* Get reference so that buffer cannot be freed before we unlock it */
|
|
|
+ get_bh(bh);
|
|
|
+ jbd_lock_bh_state(bh);
|
|
|
spin_lock(&journal->j_list_lock);
|
|
|
__jbd2_journal_unfile_buffer(jh);
|
|
|
spin_unlock(&journal->j_list_lock);
|
|
|
- jbd_unlock_bh_state(jh2bh(jh));
|
|
|
+ jbd_unlock_bh_state(bh);
|
|
|
+ __brelse(bh);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1593,8 +1602,6 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
|
|
|
if (jh->b_jlist == BJ_None) {
|
|
|
JBUFFER_TRACE(jh, "remove from checkpoint list");
|
|
|
__jbd2_journal_remove_checkpoint(jh);
|
|
|
- jbd2_journal_remove_journal_head(bh);
|
|
|
- __brelse(bh);
|
|
|
}
|
|
|
}
|
|
|
spin_unlock(&journal->j_list_lock);
|
|
@@ -1657,7 +1664,6 @@ 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().
|
|
|
*/
|
|
|
jh = jbd2_journal_grab_journal_head(bh);
|
|
@@ -1695,10 +1701,9 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
|
|
|
int may_free = 1;
|
|
|
struct buffer_head *bh = jh2bh(jh);
|
|
|
|
|
|
- __jbd2_journal_unfile_buffer(jh);
|
|
|
-
|
|
|
if (jh->b_cp_transaction) {
|
|
|
JBUFFER_TRACE(jh, "on running+cp transaction");
|
|
|
+ __jbd2_journal_temp_unlink_buffer(jh);
|
|
|
/*
|
|
|
* We don't want to write the buffer anymore, clear the
|
|
|
* bit so that we don't confuse checks in
|
|
@@ -1709,8 +1714,7 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
|
|
|
may_free = 0;
|
|
|
} else {
|
|
|
JBUFFER_TRACE(jh, "on running transaction");
|
|
|
- jbd2_journal_remove_journal_head(bh);
|
|
|
- __brelse(bh);
|
|
|
+ __jbd2_journal_unfile_buffer(jh);
|
|
|
}
|
|
|
return may_free;
|
|
|
}
|
|
@@ -1988,6 +1992,8 @@ void __jbd2_journal_file_buffer(struct journal_head *jh,
|
|
|
|
|
|
if (jh->b_transaction)
|
|
|
__jbd2_journal_temp_unlink_buffer(jh);
|
|
|
+ else
|
|
|
+ jbd2_journal_grab_journal_head(bh);
|
|
|
jh->b_transaction = transaction;
|
|
|
|
|
|
switch (jlist) {
|
|
@@ -2039,9 +2045,10 @@ void jbd2_journal_file_buffer(struct journal_head *jh,
|
|
|
* already started to be used by a subsequent transaction, refile the
|
|
|
* buffer on that transaction's metadata list.
|
|
|
*
|
|
|
- * Called under journal->j_list_lock
|
|
|
- *
|
|
|
+ * Called under j_list_lock
|
|
|
* Called under jbd_lock_bh_state(jh2bh(jh))
|
|
|
+ *
|
|
|
+ * jh and bh may be already free when this function returns
|
|
|
*/
|
|
|
void __jbd2_journal_refile_buffer(struct journal_head *jh)
|
|
|
{
|
|
@@ -2065,6 +2072,11 @@ void __jbd2_journal_refile_buffer(struct journal_head *jh)
|
|
|
|
|
|
was_dirty = test_clear_buffer_jbddirty(bh);
|
|
|
__jbd2_journal_temp_unlink_buffer(jh);
|
|
|
+ /*
|
|
|
+ * We set b_transaction here because b_next_transaction will inherit
|
|
|
+ * our jh reference and thus __jbd2_journal_file_buffer() must not
|
|
|
+ * take a new one.
|
|
|
+ */
|
|
|
jh->b_transaction = jh->b_next_transaction;
|
|
|
jh->b_next_transaction = NULL;
|
|
|
if (buffer_freed(bh))
|
|
@@ -2081,30 +2093,21 @@ void __jbd2_journal_refile_buffer(struct journal_head *jh)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * For the unlocked version of this call, also make sure that any
|
|
|
- * hanging journal_head is cleaned up if necessary.
|
|
|
- *
|
|
|
- * __jbd2_journal_refile_buffer is usually called as part of a single locked
|
|
|
- * operation on a buffer_head, in which the caller is probably going to
|
|
|
- * be hooking the journal_head onto other lists. In that case it is up
|
|
|
- * to the caller to remove the journal_head if necessary. For the
|
|
|
- * unlocked jbd2_journal_refile_buffer call, the caller isn't going to be
|
|
|
- * doing anything else to the buffer so we need to do the cleanup
|
|
|
- * ourselves to avoid a jh leak.
|
|
|
- *
|
|
|
- * *** The journal_head may be freed by this call! ***
|
|
|
+ * __jbd2_journal_refile_buffer() with necessary locking added. We take our
|
|
|
+ * bh reference so that we can safely unlock bh.
|
|
|
+ *
|
|
|
+ * The jh and bh may be freed by this call.
|
|
|
*/
|
|
|
void jbd2_journal_refile_buffer(journal_t *journal, struct journal_head *jh)
|
|
|
{
|
|
|
struct buffer_head *bh = jh2bh(jh);
|
|
|
|
|
|
+ /* Get reference so that buffer cannot be freed before we unlock it */
|
|
|
+ get_bh(bh);
|
|
|
jbd_lock_bh_state(bh);
|
|
|
spin_lock(&journal->j_list_lock);
|
|
|
-
|
|
|
__jbd2_journal_refile_buffer(jh);
|
|
|
jbd_unlock_bh_state(bh);
|
|
|
- jbd2_journal_remove_journal_head(bh);
|
|
|
-
|
|
|
spin_unlock(&journal->j_list_lock);
|
|
|
__brelse(bh);
|
|
|
}
|