aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJoel Becker <joel.becker@oracle.com>2008-09-11 18:35:47 -0400
committerMark Fasheh <mfasheh@suse.com>2009-01-05 11:40:30 -0500
commite06c8227fd94ec181849ba206bf032be31c4295c (patch)
tree67261cd94aa86dc6112d7de74304c2a1af5b64fb /fs
parent754938c142ae0c28360426c43f965ddc5164b21e (diff)
jbd2: Add buffer triggers
Filesystems often to do compute intensive operation on some metadata. If this operation is repeated many times, it can be very expensive. It would be much nicer if the operation could be performed once before a buffer goes to disk. This adds triggers to jbd2 buffer heads. Just before writing a metadata buffer to the journal, jbd2 will optionally call a commit trigger associated with the buffer. If the journal is aborted, an abort trigger will be called on any dirty buffers as they are dropped from pending transactions. ocfs2 will use this feature. Initially I tried to come up with a more generic trigger that could be used for non-buffer-related events like transaction completion. It doesn't tie nicely, because the information a buffer trigger needs (specific to a journal_head) isn't the same as what a transaction trigger needs (specific to a tranaction_t or perhaps journal_t). So I implemented a buffer set, with the understanding that journal/transaction wide triggers should be implemented separately. There is only one trigger set allowed per buffer. I can't think of any reason to attach more than one set. Contrast this with a journal or transaction in which multiple places may want to watch the entire transaction separately. The trigger sets are considered static allocation from the jbd2 perspective. ocfs2 will just have one trigger set per block type, setting the same set on every bh of the same type. Signed-off-by: Joel Becker <joel.becker@oracle.com> Cc: "Theodore Ts'o" <tytso@mit.edu> Cc: <linux-ext4@vger.kernel.org> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/jbd2/commit.c9
-rw-r--r--fs/jbd2/journal.c19
-rw-r--r--fs/jbd2/transaction.c47
3 files changed, 75 insertions, 0 deletions
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index ebc667bc54a8..c8a1bace685a 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -509,6 +509,10 @@ void jbd2_journal_commit_transaction(journal_t *journal)
509 if (is_journal_aborted(journal)) { 509 if (is_journal_aborted(journal)) {
510 clear_buffer_jbddirty(jh2bh(jh)); 510 clear_buffer_jbddirty(jh2bh(jh));
511 JBUFFER_TRACE(jh, "journal is aborting: refile"); 511 JBUFFER_TRACE(jh, "journal is aborting: refile");
512 jbd2_buffer_abort_trigger(jh,
513 jh->b_frozen_data ?
514 jh->b_frozen_triggers :
515 jh->b_triggers);
512 jbd2_journal_refile_buffer(journal, jh); 516 jbd2_journal_refile_buffer(journal, jh);
513 /* If that was the last one, we need to clean up 517 /* If that was the last one, we need to clean up
514 * any descriptor buffers which may have been 518 * any descriptor buffers which may have been
@@ -844,6 +848,9 @@ restart_loop:
844 * data. 848 * data.
845 * 849 *
846 * Otherwise, we can just throw away the frozen data now. 850 * Otherwise, we can just throw away the frozen data now.
851 *
852 * We also know that the frozen data has already fired
853 * its triggers if they exist, so we can clear that too.
847 */ 854 */
848 if (jh->b_committed_data) { 855 if (jh->b_committed_data) {
849 jbd2_free(jh->b_committed_data, bh->b_size); 856 jbd2_free(jh->b_committed_data, bh->b_size);
@@ -851,10 +858,12 @@ restart_loop:
851 if (jh->b_frozen_data) { 858 if (jh->b_frozen_data) {
852 jh->b_committed_data = jh->b_frozen_data; 859 jh->b_committed_data = jh->b_frozen_data;
853 jh->b_frozen_data = NULL; 860 jh->b_frozen_data = NULL;
861 jh->b_frozen_triggers = NULL;
854 } 862 }
855 } else if (jh->b_frozen_data) { 863 } else if (jh->b_frozen_data) {
856 jbd2_free(jh->b_frozen_data, bh->b_size); 864 jbd2_free(jh->b_frozen_data, bh->b_size);
857 jh->b_frozen_data = NULL; 865 jh->b_frozen_data = NULL;
866 jh->b_frozen_triggers = NULL;
858 } 867 }
859 868
860 spin_lock(&journal->j_list_lock); 869 spin_lock(&journal->j_list_lock);
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index e70d657a19f8..f6bff9d6f8df 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -50,6 +50,7 @@ EXPORT_SYMBOL(jbd2_journal_unlock_updates);
50EXPORT_SYMBOL(jbd2_journal_get_write_access); 50EXPORT_SYMBOL(jbd2_journal_get_write_access);
51EXPORT_SYMBOL(jbd2_journal_get_create_access); 51EXPORT_SYMBOL(jbd2_journal_get_create_access);
52EXPORT_SYMBOL(jbd2_journal_get_undo_access); 52EXPORT_SYMBOL(jbd2_journal_get_undo_access);
53EXPORT_SYMBOL(jbd2_journal_set_triggers);
53EXPORT_SYMBOL(jbd2_journal_dirty_metadata); 54EXPORT_SYMBOL(jbd2_journal_dirty_metadata);
54EXPORT_SYMBOL(jbd2_journal_release_buffer); 55EXPORT_SYMBOL(jbd2_journal_release_buffer);
55EXPORT_SYMBOL(jbd2_journal_forget); 56EXPORT_SYMBOL(jbd2_journal_forget);
@@ -290,6 +291,7 @@ int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
290 struct page *new_page; 291 struct page *new_page;
291 unsigned int new_offset; 292 unsigned int new_offset;
292 struct buffer_head *bh_in = jh2bh(jh_in); 293 struct buffer_head *bh_in = jh2bh(jh_in);
294 struct jbd2_buffer_trigger_type *triggers;
293 295
294 /* 296 /*
295 * The buffer really shouldn't be locked: only the current committing 297 * The buffer really shouldn't be locked: only the current committing
@@ -314,13 +316,23 @@ repeat:
314 done_copy_out = 1; 316 done_copy_out = 1;
315 new_page = virt_to_page(jh_in->b_frozen_data); 317 new_page = virt_to_page(jh_in->b_frozen_data);
316 new_offset = offset_in_page(jh_in->b_frozen_data); 318 new_offset = offset_in_page(jh_in->b_frozen_data);
319 triggers = jh_in->b_frozen_triggers;
317 } else { 320 } else {
318 new_page = jh2bh(jh_in)->b_page; 321 new_page = jh2bh(jh_in)->b_page;
319 new_offset = offset_in_page(jh2bh(jh_in)->b_data); 322 new_offset = offset_in_page(jh2bh(jh_in)->b_data);
323 triggers = jh_in->b_triggers;
320 } 324 }
321 325
322 mapped_data = kmap_atomic(new_page, KM_USER0); 326 mapped_data = kmap_atomic(new_page, KM_USER0);
323 /* 327 /*
328 * Fire any commit trigger. Do this before checking for escaping,
329 * as the trigger may modify the magic offset. If a copy-out
330 * happens afterwards, it will have the correct data in the buffer.
331 */
332 jbd2_buffer_commit_trigger(jh_in, mapped_data + new_offset,
333 triggers);
334
335 /*
324 * Check for escaping 336 * Check for escaping
325 */ 337 */
326 if (*((__be32 *)(mapped_data + new_offset)) == 338 if (*((__be32 *)(mapped_data + new_offset)) ==
@@ -352,6 +364,13 @@ repeat:
352 new_page = virt_to_page(tmp); 364 new_page = virt_to_page(tmp);
353 new_offset = offset_in_page(tmp); 365 new_offset = offset_in_page(tmp);
354 done_copy_out = 1; 366 done_copy_out = 1;
367
368 /*
369 * This isn't strictly necessary, as we're using frozen
370 * data for the escaping, but it keeps consistency with
371 * b_frozen_data usage.
372 */
373 jh_in->b_frozen_triggers = jh_in->b_triggers;
355 } 374 }
356 375
357 /* 376 /*
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index 39b7805a599a..4f925a4f3d05 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -741,6 +741,12 @@ done:
741 source = kmap_atomic(page, KM_USER0); 741 source = kmap_atomic(page, KM_USER0);
742 memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size); 742 memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size);
743 kunmap_atomic(source, KM_USER0); 743 kunmap_atomic(source, KM_USER0);
744
745 /*
746 * Now that the frozen data is saved off, we need to store
747 * any matching triggers.
748 */
749 jh->b_frozen_triggers = jh->b_triggers;
744 } 750 }
745 jbd_unlock_bh_state(bh); 751 jbd_unlock_bh_state(bh);
746 752
@@ -944,6 +950,47 @@ out:
944} 950}
945 951
946/** 952/**
953 * void jbd2_journal_set_triggers() - Add triggers for commit writeout
954 * @bh: buffer to trigger on
955 * @type: struct jbd2_buffer_trigger_type containing the trigger(s).
956 *
957 * Set any triggers on this journal_head. This is always safe, because
958 * triggers for a committing buffer will be saved off, and triggers for
959 * a running transaction will match the buffer in that transaction.
960 *
961 * Call with NULL to clear the triggers.
962 */
963void jbd2_journal_set_triggers(struct buffer_head *bh,
964 struct jbd2_buffer_trigger_type *type)
965{
966 struct journal_head *jh = bh2jh(bh);
967
968 jh->b_triggers = type;
969}
970
971void jbd2_buffer_commit_trigger(struct journal_head *jh, void *mapped_data,
972 struct jbd2_buffer_trigger_type *triggers)
973{
974 struct buffer_head *bh = jh2bh(jh);
975
976 if (!triggers || !triggers->t_commit)
977 return;
978
979 triggers->t_commit(triggers, bh, mapped_data, bh->b_size);
980}
981
982void jbd2_buffer_abort_trigger(struct journal_head *jh,
983 struct jbd2_buffer_trigger_type *triggers)
984{
985 if (!triggers || !triggers->t_abort)
986 return;
987
988 triggers->t_abort(triggers, jh2bh(jh));
989}
990
991
992
993/**
947 * int jbd2_journal_dirty_metadata() - mark a buffer as containing dirty metadata 994 * int jbd2_journal_dirty_metadata() - mark a buffer as containing dirty metadata
948 * @handle: transaction to add buffer to. 995 * @handle: transaction to add buffer to.
949 * @bh: buffer to mark 996 * @bh: buffer to mark