--------------------- PatchSet 793 Date: 2002/01/11 18:59:30 Author: sct Log: Add support for a client-defined commit rundown phase, where the jbd client (eg. ext3) can do a bit of post-processing on the transaction before final commit. (No new buffers may be added to the journal at this point, but existing journaled buffers may be dirtied by the fs.) Members: fs/jbd/commit.c:1.46.2.3->1.46.2.3.2.1 [quota-branch] fs/jbd/transaction.c:1.64.2.7->1.64.2.7.2.1 [quota-branch] include/linux/jbd.h:1.37.2.8->1.37.2.8.2.1 [quota-branch] --- linux-2.4.21-pre3-rmap-ext3merge/fs/jbd/commit.c.=K0020=.orig 2003-01-23 16:30:32.000000000 +0000 +++ linux-2.4.21-pre3-rmap-ext3merge/fs/jbd/commit.c 2003-01-23 16:30:32.000000000 +0000 @@ -23,6 +23,8 @@ extern spinlock_t journal_datalist_lock; +static void do_client_callback(journal_t *, transaction_t *); + /* * Default IO end handler for temporary BJ_IO buffer_heads. */ @@ -88,6 +90,11 @@ lock_journal(journal); } + /* Once there are no active transactions, give the fs a chance + * to do any state cleanup it needs before we start on the + * commit for real. */ + do_client_callback(journal, commit_transaction); + J_ASSERT (commit_transaction->t_outstanding_credits <= journal->j_max_transaction_buffers); @@ -752,3 +759,54 @@ unlock_journal(journal); wake_up(&journal->j_wait_done_commit); } + + +/* + * The client filesystem may want to do cleanups to the state of the + * filesystem before we commit an image to the journal. + * + * The journal space reservation mechanism means that we need to have + * accounted for any unpredictable client fs block reservations before + * we get to this point, but the client may not necessarily have updated + * all reserved blocks that it might have new data for. For blocks + * which are updated regularly, deferring the updates until commit time + * can be a performance win, but such blocks MUST already have been at + * least reserved by the transaction. + * + * We'll create a temporary transaction handle with no buffer credits as + * a way to let the fs commit dirty data without allowing it to modify + * any new blocks. + * + * Called with the journal still locked. + */ + +void do_client_callback(journal_t *journal, transaction_t *transaction) +{ + handle_t tmp_handle; + + transaction->t_state = T_RUNDOWN; + + if (!journal->j_commit_callback) + return; + + jbd_debug (3, "JBD: rundown phase\n"); + + /* Set up a temporary handle against which to allow the + * filesystem to call the journaling layer */ + memset(&tmp_handle, 0, sizeof(tmp_handle)); + tmp_handle.h_ref = 1; + J_ASSERT(current->journal_info == NULL); + current->journal_info = &tmp_handle; + __journal_register_transaction(transaction, &tmp_handle); + + J_ASSERT(transaction->t_updates == 0); + + unlock_journal(journal); + journal->j_commit_callback(journal, journal->j_cookie); + lock_journal(journal); + + J_ASSERT (!tmp_handle.h_sync); + journal_stop(&tmp_handle); + + J_ASSERT(transaction->t_updates == 0); +} --- linux-2.4.21-pre3-rmap-ext3merge/fs/jbd/transaction.c.=K0020=.orig 2003-01-23 16:30:32.000000000 +0000 +++ linux-2.4.21-pre3-rmap-ext3merge/fs/jbd/transaction.c 2003-01-23 16:30:32.000000000 +0000 @@ -29,6 +29,12 @@ extern spinlock_t journal_datalist_lock; +static int transaction_is_locked(transaction_t *transaction) +{ + return (transaction->t_state == T_LOCKED || + transaction->t_state == T_RUNDOWN); +} + /* * get_transaction: obtain a new transaction_t object. * @@ -79,6 +85,15 @@ * of that one update. */ +void __journal_register_transaction(transaction_t *transaction, + handle_t *handle) +{ + handle->h_transaction = transaction; + transaction->t_outstanding_credits += handle->h_buffer_credits; + transaction->t_updates++; + transaction->t_handle_count++; +} + /* * start_this_handle: Given a handle, deal with any locking or stalling * needed to make sure that there is enough journal space for the handle @@ -130,7 +145,7 @@ /* If the current transaction is locked down for commit, wait * for the lock to be released. */ - if (transaction->t_state == T_LOCKED) { + if (transaction_is_locked(transaction)) { unlock_journal(journal); jbd_debug(3, "Handle %p stalling...\n", handle); sleep_on(&journal->j_wait_transaction_locked); @@ -196,10 +211,7 @@ /* OK, account for the buffers that this operation expects to * use and add the handle to the running transaction. */ - handle->h_transaction = transaction; - transaction->t_outstanding_credits += nblocks; - transaction->t_updates++; - transaction->t_handle_count++; + __journal_register_transaction(transaction, handle); jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n", handle, nblocks, transaction->t_outstanding_credits, log_space_left(journal)); @@ -294,7 +306,7 @@ goto fail_unlock; transaction = journal->j_running_transaction; - if (transaction->t_state == T_LOCKED) + if (transaction_is_locked(transaction)) goto fail_unlock; needed = transaction->t_outstanding_credits + nblocks; --- linux-2.4.21-pre3-rmap-ext3merge/include/linux/jbd.h.=K0020=.orig 2003-01-23 16:30:32.000000000 +0000 +++ linux-2.4.21-pre3-rmap-ext3merge/include/linux/jbd.h 2003-01-23 16:30:32.000000000 +0000 @@ -386,7 +386,7 @@ * RUNNING: accepting new updates * LOCKED: Updates still running but we don't accept new ones * RUNDOWN: Updates are tidying up but have finished requesting - * new buffers to modify (state not used for now) + * new buffers to modify * FLUSH: All updates complete, but we are still writing to disk * COMMIT: All data on disk, writing commit record * FINISHED: We still have to keep the transaction for checkpointing. @@ -671,6 +671,13 @@ /* The revoke table: maintains the list of revoked blocks in the */ /* current transaction. */ struct jbd_revoke_table_s *j_revoke; + + /* Callback into the client [filesystem] made when we're about + * to wrap up a commit. */ + void (*j_commit_callback)(journal_t *, void *); + /* And the cookie used by the client to identify which fs is + * referenced by the commit callback */ + void *j_cookie; }; /* @@ -712,6 +719,9 @@ extern void journal_insert_checkpoint(struct journal_head *, transaction_t *); extern void __journal_insert_checkpoint(struct journal_head *,transaction_t *); +/* Handle management */ +extern void __journal_register_transaction(transaction_t *, handle_t *); + /* Buffer IO */ extern int journal_write_metadata_buffer(transaction_t *transaction,