Skip to content

Commit

Permalink
jbd2: Remove data=ordered mode support using jbd buffer heads
Browse files Browse the repository at this point in the history
Signed-off-by: Jan Kara <jack@suse.cz>
  • Loading branch information
Jan Kara authored and Theodore Ts'o committed Jul 11, 2008
1 parent 678aaf4 commit 87c89c2
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 448 deletions.
1 change: 0 additions & 1 deletion fs/jbd2/checkpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,6 @@ void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transact

J_ASSERT(transaction->t_state == T_FINISHED);
J_ASSERT(transaction->t_buffers == NULL);
J_ASSERT(transaction->t_sync_datalist == NULL);
J_ASSERT(transaction->t_forget == NULL);
J_ASSERT(transaction->t_iobuf_list == NULL);
J_ASSERT(transaction->t_shadow_list == NULL);
Expand Down
221 changes: 8 additions & 213 deletions fs/jbd2/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate)
}

/*
* When an ext3-ordered file is truncated, it is possible that many pages are
* not sucessfully freed, because they are attached to a committing transaction.
* When an ext4 file is truncated, it is possible that some pages are not
* successfully freed, because they are attached to a committing transaction.
* After the transaction commits, these pages are left on the LRU, with no
* ->mapping, and with attached buffers. These pages are trivially reclaimable
* by the VM, but their apparent absence upsets the VM accounting, and it makes
Expand Down Expand Up @@ -79,21 +79,6 @@ static void release_buffer_page(struct buffer_head *bh)
__brelse(bh);
}

/*
* Try to acquire jbd_lock_bh_state() against the buffer, when j_list_lock is
* held. For ranking reasons we must trylock. If we lose, schedule away and
* return 0. j_list_lock is dropped in this case.
*/
static int inverted_lock(journal_t *journal, struct buffer_head *bh)
{
if (!jbd_trylock_bh_state(bh)) {
spin_unlock(&journal->j_list_lock);
schedule();
return 0;
}
return 1;
}

/*
* Done it all: now submit the commit record. We should have
* cleaned up our previous buffers by now, so if we are in abort
Expand Down Expand Up @@ -199,162 +184,6 @@ static int journal_wait_on_commit_record(struct buffer_head *bh)
return ret;
}

/*
* Wait for all submitted IO to complete.
*/
static int journal_wait_on_locked_list(journal_t *journal,
transaction_t *commit_transaction)
{
int ret = 0;
struct journal_head *jh;

while (commit_transaction->t_locked_list) {
struct buffer_head *bh;

jh = commit_transaction->t_locked_list->b_tprev;
bh = jh2bh(jh);
get_bh(bh);
if (buffer_locked(bh)) {
spin_unlock(&journal->j_list_lock);
wait_on_buffer(bh);
if (unlikely(!buffer_uptodate(bh)))
ret = -EIO;
spin_lock(&journal->j_list_lock);
}
if (!inverted_lock(journal, bh)) {
put_bh(bh);
spin_lock(&journal->j_list_lock);
continue;
}
if (buffer_jbd(bh) && jh->b_jlist == BJ_Locked) {
__jbd2_journal_unfile_buffer(jh);
jbd_unlock_bh_state(bh);
jbd2_journal_remove_journal_head(bh);
put_bh(bh);
} else {
jbd_unlock_bh_state(bh);
}
put_bh(bh);
cond_resched_lock(&journal->j_list_lock);
}
return ret;
}

static void journal_do_submit_data(struct buffer_head **wbuf, int bufs)
{
int i;

for (i = 0; i < bufs; i++) {
wbuf[i]->b_end_io = end_buffer_write_sync;
/* We use-up our safety reference in submit_bh() */
submit_bh(WRITE, wbuf[i]);
}
}

/*
* Submit all the data buffers to disk
*/
static void journal_submit_data_buffers(journal_t *journal,
transaction_t *commit_transaction)
{
struct journal_head *jh;
struct buffer_head *bh;
int locked;
int bufs = 0;
struct buffer_head **wbuf = journal->j_wbuf;

/*
* Whenever we unlock the journal and sleep, things can get added
* onto ->t_sync_datalist, so we have to keep looping back to
* write_out_data until we *know* that the list is empty.
*
* Cleanup any flushed data buffers from the data list. Even in
* abort mode, we want to flush this out as soon as possible.
*/
write_out_data:
cond_resched();
spin_lock(&journal->j_list_lock);

while (commit_transaction->t_sync_datalist) {
jh = commit_transaction->t_sync_datalist;
bh = jh2bh(jh);
locked = 0;

/* Get reference just to make sure buffer does not disappear
* when we are forced to drop various locks */
get_bh(bh);
/* If the buffer is dirty, we need to submit IO and hence
* we need the buffer lock. We try to lock the buffer without
* blocking. If we fail, we need to drop j_list_lock and do
* blocking lock_buffer().
*/
if (buffer_dirty(bh)) {
if (test_set_buffer_locked(bh)) {
BUFFER_TRACE(bh, "needs blocking lock");
spin_unlock(&journal->j_list_lock);
/* Write out all data to prevent deadlocks */
journal_do_submit_data(wbuf, bufs);
bufs = 0;
lock_buffer(bh);
spin_lock(&journal->j_list_lock);
}
locked = 1;
}
/* We have to get bh_state lock. Again out of order, sigh. */
if (!inverted_lock(journal, bh)) {
jbd_lock_bh_state(bh);
spin_lock(&journal->j_list_lock);
}
/* Someone already cleaned up the buffer? */
if (!buffer_jbd(bh)
|| jh->b_transaction != commit_transaction
|| jh->b_jlist != BJ_SyncData) {
jbd_unlock_bh_state(bh);
if (locked)
unlock_buffer(bh);
BUFFER_TRACE(bh, "already cleaned up");
put_bh(bh);
continue;
}
if (locked && test_clear_buffer_dirty(bh)) {
BUFFER_TRACE(bh, "needs writeout, adding to array");
wbuf[bufs++] = bh;
__jbd2_journal_file_buffer(jh, commit_transaction,
BJ_Locked);
jbd_unlock_bh_state(bh);
if (bufs == journal->j_wbufsize) {
spin_unlock(&journal->j_list_lock);
journal_do_submit_data(wbuf, bufs);
bufs = 0;
goto write_out_data;
}
} else if (!locked && buffer_locked(bh)) {
__jbd2_journal_file_buffer(jh, commit_transaction,
BJ_Locked);
jbd_unlock_bh_state(bh);
put_bh(bh);
} else {
BUFFER_TRACE(bh, "writeout complete: unfile");
__jbd2_journal_unfile_buffer(jh);
jbd_unlock_bh_state(bh);
if (locked)
unlock_buffer(bh);
jbd2_journal_remove_journal_head(bh);
/* Once for our safety reference, once for
* jbd2_journal_remove_journal_head() */
put_bh(bh);
put_bh(bh);
}

if (need_resched() || spin_needbreak(&journal->j_list_lock)) {
spin_unlock(&journal->j_list_lock);
goto write_out_data;
}
}
spin_unlock(&journal->j_list_lock);
journal_do_submit_data(wbuf, bufs);
}

/*
* Submit all the data buffers of inode associated with the transaction to
* disk.
Expand Down Expand Up @@ -602,41 +431,14 @@ void jbd2_journal_commit_transaction(journal_t *journal)
* Now start flushing things to disk, in the order they appear
* on the transaction lists. Data blocks go first.
*/
err = 0;
journal_submit_data_buffers(journal, commit_transaction);
err = journal_submit_inode_data_buffers(journal, commit_transaction);
if (err)
jbd2_journal_abort(journal, err);

/*
* Wait for all previously submitted IO to complete if commit
* record is to be written synchronously.
*/
spin_lock(&journal->j_list_lock);
if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT))
err = journal_wait_on_locked_list(journal,
commit_transaction);

spin_unlock(&journal->j_list_lock);

if (err)
jbd2_journal_abort(journal, err);

jbd2_journal_write_revoke_records(journal, commit_transaction);

jbd_debug(3, "JBD: commit phase 2\n");

/*
* If we found any dirty or locked buffers, then we should have
* looped back up to the write_out_data label. If there weren't
* any then journal_clean_data_list should have wiped the list
* clean by now, so check that it is in fact empty.
*/
J_ASSERT (commit_transaction->t_sync_datalist == NULL);

jbd_debug (3, "JBD: commit phase 3\n");

/*
* Way to go: we have now written out all of the data for a
* transaction! Now comes the tricky part: we need to write out
Expand All @@ -655,6 +457,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
J_ASSERT(commit_transaction->t_nr_buffers <=
commit_transaction->t_outstanding_credits);

err = 0;
descriptor = NULL;
bufs = 0;
while (commit_transaction->t_buffers) {
Expand Down Expand Up @@ -829,13 +632,6 @@ void jbd2_journal_commit_transaction(journal_t *journal)
&cbh, crc32_sum);
if (err)
__jbd2_journal_abort_hard(journal);

spin_lock(&journal->j_list_lock);
err = journal_wait_on_locked_list(journal,
commit_transaction);
spin_unlock(&journal->j_list_lock);
if (err)
__jbd2_journal_abort_hard(journal);
}

/*
Expand All @@ -860,7 +656,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
so we incur less scheduling load.
*/

jbd_debug(3, "JBD: commit phase 4\n");
jbd_debug(3, "JBD: commit phase 3\n");

/*
* akpm: these are BJ_IO, and j_list_lock is not needed.
Expand Down Expand Up @@ -919,7 +715,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)

J_ASSERT (commit_transaction->t_shadow_list == NULL);

jbd_debug(3, "JBD: commit phase 5\n");
jbd_debug(3, "JBD: commit phase 4\n");

/* Here we wait for the revoke record and descriptor record buffers */
wait_for_ctlbuf:
Expand All @@ -946,7 +742,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
/* AKPM: bforget here */
}

jbd_debug(3, "JBD: commit phase 6\n");
jbd_debug(3, "JBD: commit phase 5\n");

if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
Expand All @@ -966,9 +762,8 @@ void jbd2_journal_commit_transaction(journal_t *journal)
transaction can be removed from any checkpoint list it was on
before. */

jbd_debug(3, "JBD: commit phase 7\n");
jbd_debug(3, "JBD: commit phase 6\n");

J_ASSERT(commit_transaction->t_sync_datalist == NULL);
J_ASSERT(list_empty(&commit_transaction->t_inode_list));
J_ASSERT(commit_transaction->t_buffers == NULL);
J_ASSERT(commit_transaction->t_checkpoint_list == NULL);
Expand Down Expand Up @@ -1090,7 +885,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)

/* Done with this transaction! */

jbd_debug(3, "JBD: commit phase 8\n");
jbd_debug(3, "JBD: commit phase 7\n");

J_ASSERT(commit_transaction->t_state == T_COMMIT);

Expand Down
1 change: 0 additions & 1 deletion fs/jbd2/journal.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ EXPORT_SYMBOL(jbd2_journal_unlock_updates);
EXPORT_SYMBOL(jbd2_journal_get_write_access);
EXPORT_SYMBOL(jbd2_journal_get_create_access);
EXPORT_SYMBOL(jbd2_journal_get_undo_access);
EXPORT_SYMBOL(jbd2_journal_dirty_data);
EXPORT_SYMBOL(jbd2_journal_dirty_metadata);
EXPORT_SYMBOL(jbd2_journal_release_buffer);
EXPORT_SYMBOL(jbd2_journal_forget);
Expand Down
Loading

0 comments on commit 87c89c2

Please sign in to comment.