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)
{
struct journal_head *jh = bh2jh(bh);
* Called from journal_try_to_free_buffers().
*
* 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)
{
struct journal_head *jh;
}
}
spin_unlock(&journal->j_list_lock);
- return !buffer_jbd(bh);
-
out:
- return 0;
+ return;
}
head = page_buffers(page);
bh = head;
do {
- jbd_lock_bh_state(bh);
+ struct journal_head *jh;
+
/*
- * We don't have to worry about the buffer being pulled off its
- * journal_head in here, because __try_to_free_cp_buf runs
- * under jbd_lock_bh_state()
+ * We take our own ref against the journal_head here to avoid
+ * having to add tons of locking around each instance of
+ * journal_remove_journal_head() and journal_put_journal_head().
*/
- if (buffer_jbd(bh) &&
- !__journal_try_to_free_buffer(journal, bh)) {
- jbd_unlock_bh_state(bh);
- goto busy;
- }
+ jh = journal_grab_journal_head(bh);
+ if (!jh)
+ continue;
+
+ jbd_lock_bh_state(bh);
+ __journal_try_to_free_buffer(journal, bh);
+ journal_put_journal_head(jh);
jbd_unlock_bh_state(bh);
+ if (buffer_jbd(bh))
+ goto busy;
} while ((bh = bh->b_this_page) != head);
ret = try_to_free_buffers(page);
busy:
/*
* journal_head management
*/
-extern struct journal_head
- *journal_add_journal_head(struct buffer_head *bh);
-extern void journal_remove_journal_head(struct buffer_head *bh);
-extern void journal_put_journal_head(struct journal_head *jh);
+struct journal_head *journal_add_journal_head(struct buffer_head *bh);
+struct journal_head *journal_grab_journal_head(struct buffer_head *bh);
+void journal_remove_journal_head(struct buffer_head *bh);
+void journal_put_journal_head(struct journal_head *jh);
/*
* handle management