Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 105846
b: refs/heads/master
c: 3f31fdd
h: refs/heads/master
v: v3
  • Loading branch information
Mingming Cao authored and Linus Torvalds committed Jul 25, 2008
1 parent 442ae0c commit f066838
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9ebfbe9f926553eabc21b4400918d1216b27ed0c
refs/heads/master: 3f31fddfa26b7594b44ff2b34f9a04ba409e0f91
57 changes: 55 additions & 2 deletions trunk/fs/jbd/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -1648,12 +1648,42 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
return;
}

/*
* journal_try_to_free_buffers() could race with journal_commit_transaction()
* The latter might still hold the a count on buffers when inspecting
* them on t_syncdata_list or t_locked_list.
*
* journal_try_to_free_buffers() will call this function to
* wait for the current transaction to finish syncing data buffers, before
* tryinf to free that buffer.
*
* Called with journal->j_state_lock held.
*/
static void 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);
log_wait_commit(journal, tid);
}

/**
* int 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,
Expand Down Expand Up @@ -1682,9 +1712,11 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
* 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 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;
Expand Down Expand Up @@ -1713,7 +1745,28 @@ int 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 journal_try_to_free_buffers()
* could race with 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)) {
journal_wait_for_transaction_sync_data(journal);
ret = try_to_free_buffers(page);
}

busy:
return ret;
}
Expand Down
3 changes: 1 addition & 2 deletions trunk/mm/filemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -2563,9 +2563,8 @@ EXPORT_SYMBOL(generic_file_aio_write);
* Otherwise return zero.
*
* The @gfp_mask argument specifies whether I/O may be performed to release
* this page (__GFP_IO), and whether the call may block (__GFP_WAIT).
* this page (__GFP_IO), and whether the call may block (__GFP_WAIT & __GFP_FS).
*
* NOTE: @gfp_mask may go away, and this function may become non-blocking.
*/
int try_to_release_page(struct page *page, gfp_t gfp_mask)
{
Expand Down

0 comments on commit f066838

Please sign in to comment.