Commit b55d3305 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] JBD: journal_try_to_free_buffers race fix

There is a race between transaction commit's attempt to free journal_heads
and journal_try_to_free_buffers' attempt.

Fix that by taking a ref against the journal_head in
journal_try_to_free_buffers().
parent de285c52
...@@ -1679,6 +1679,23 @@ struct journal_head *journal_add_journal_head(struct buffer_head *bh) ...@@ -1679,6 +1679,23 @@ struct journal_head *journal_add_journal_head(struct buffer_head *bh)
return bh->b_private; return bh->b_private;
} }
/*
* Grab a ref against this buffer_head's journal_head. If it ended up not
* having a journal_head, return NULL
*/
struct journal_head *journal_grab_journal_head(struct buffer_head *bh)
{
struct journal_head *jh = NULL;
jbd_lock_bh_journal_head(bh);
if (buffer_jbd(bh)) {
jh = bh2jh(bh);
jh->b_jcount++;
}
jbd_unlock_bh_journal_head(bh);
return jh;
}
static void __journal_remove_journal_head(struct buffer_head *bh) static void __journal_remove_journal_head(struct buffer_head *bh)
{ {
struct journal_head *jh = bh2jh(bh); struct journal_head *jh = bh2jh(bh);
......
...@@ -1553,10 +1553,8 @@ void journal_unfile_buffer(journal_t *journal, struct journal_head *jh) ...@@ -1553,10 +1553,8 @@ void journal_unfile_buffer(journal_t *journal, struct journal_head *jh)
* Called from journal_try_to_free_buffers(). * Called from journal_try_to_free_buffers().
* *
* Called under jbd_lock_bh_state(bh) * Called under jbd_lock_bh_state(bh)
*
* Returns non-zero iff we were able to free the journal_head.
*/ */
static inline int static void
__journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh) __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
{ {
struct journal_head *jh; struct journal_head *jh;
...@@ -1589,10 +1587,8 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh) ...@@ -1589,10 +1587,8 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
} }
} }
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
return !buffer_jbd(bh);
out: out:
return 0; return;
} }
...@@ -1642,18 +1638,23 @@ int journal_try_to_free_buffers(journal_t *journal, ...@@ -1642,18 +1638,23 @@ int journal_try_to_free_buffers(journal_t *journal,
head = page_buffers(page); head = page_buffers(page);
bh = head; bh = head;
do { do {
jbd_lock_bh_state(bh); struct journal_head *jh;
/* /*
* We don't have to worry about the buffer being pulled off its * We take our own ref against the journal_head here to avoid
* journal_head in here, because __try_to_free_cp_buf runs * having to add tons of locking around each instance of
* under jbd_lock_bh_state() * journal_remove_journal_head() and journal_put_journal_head().
*/ */
if (buffer_jbd(bh) && jh = journal_grab_journal_head(bh);
!__journal_try_to_free_buffer(journal, bh)) { if (!jh)
jbd_unlock_bh_state(bh); continue;
goto busy;
} jbd_lock_bh_state(bh);
__journal_try_to_free_buffer(journal, bh);
journal_put_journal_head(jh);
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
if (buffer_jbd(bh))
goto busy;
} while ((bh = bh->b_this_page) != head); } while ((bh = bh->b_this_page) != head);
ret = try_to_free_buffers(page); ret = try_to_free_buffers(page);
busy: busy:
......
...@@ -943,10 +943,10 @@ extern int journal_force_commit(journal_t *); ...@@ -943,10 +943,10 @@ extern int journal_force_commit(journal_t *);
/* /*
* journal_head management * journal_head management
*/ */
extern struct journal_head struct journal_head *journal_add_journal_head(struct buffer_head *bh);
*journal_add_journal_head(struct buffer_head *bh); struct journal_head *journal_grab_journal_head(struct buffer_head *bh);
extern void journal_remove_journal_head(struct buffer_head *bh); void journal_remove_journal_head(struct buffer_head *bh);
extern void journal_put_journal_head(struct journal_head *jh); void journal_put_journal_head(struct journal_head *jh);
/* /*
* handle management * handle management
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment