diff options
-rw-r--r-- | fs/jbd2/commit.c | 9 | ||||
-rw-r--r-- | fs/jbd2/journal.c | 19 | ||||
-rw-r--r-- | fs/jbd2/transaction.c | 47 | ||||
-rw-r--r-- | include/linux/jbd2.h | 31 | ||||
-rw-r--r-- | include/linux/journal-head.h | 8 |
5 files changed, 114 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); | |||
50 | EXPORT_SYMBOL(jbd2_journal_get_write_access); | 50 | EXPORT_SYMBOL(jbd2_journal_get_write_access); |
51 | EXPORT_SYMBOL(jbd2_journal_get_create_access); | 51 | EXPORT_SYMBOL(jbd2_journal_get_create_access); |
52 | EXPORT_SYMBOL(jbd2_journal_get_undo_access); | 52 | EXPORT_SYMBOL(jbd2_journal_get_undo_access); |
53 | EXPORT_SYMBOL(jbd2_journal_set_triggers); | ||
53 | EXPORT_SYMBOL(jbd2_journal_dirty_metadata); | 54 | EXPORT_SYMBOL(jbd2_journal_dirty_metadata); |
54 | EXPORT_SYMBOL(jbd2_journal_release_buffer); | 55 | EXPORT_SYMBOL(jbd2_journal_release_buffer); |
55 | EXPORT_SYMBOL(jbd2_journal_forget); | 56 | EXPORT_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 | */ | ||
963 | void 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 | |||
971 | void 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 | |||
982 | void 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 |
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index f36645745489..34456476e761 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h | |||
@@ -1008,6 +1008,35 @@ int __jbd2_journal_clean_checkpoint_list(journal_t *journal); | |||
1008 | int __jbd2_journal_remove_checkpoint(struct journal_head *); | 1008 | int __jbd2_journal_remove_checkpoint(struct journal_head *); |
1009 | void __jbd2_journal_insert_checkpoint(struct journal_head *, transaction_t *); | 1009 | void __jbd2_journal_insert_checkpoint(struct journal_head *, transaction_t *); |
1010 | 1010 | ||
1011 | |||
1012 | /* | ||
1013 | * Triggers | ||
1014 | */ | ||
1015 | |||
1016 | struct jbd2_buffer_trigger_type { | ||
1017 | /* | ||
1018 | * Fired just before a buffer is written to the journal. | ||
1019 | * mapped_data is a mapped buffer that is the frozen data for | ||
1020 | * commit. | ||
1021 | */ | ||
1022 | void (*t_commit)(struct jbd2_buffer_trigger_type *type, | ||
1023 | struct buffer_head *bh, void *mapped_data, | ||
1024 | size_t size); | ||
1025 | |||
1026 | /* | ||
1027 | * Fired during journal abort for dirty buffers that will not be | ||
1028 | * committed. | ||
1029 | */ | ||
1030 | void (*t_abort)(struct jbd2_buffer_trigger_type *type, | ||
1031 | struct buffer_head *bh); | ||
1032 | }; | ||
1033 | |||
1034 | extern void jbd2_buffer_commit_trigger(struct journal_head *jh, | ||
1035 | void *mapped_data, | ||
1036 | struct jbd2_buffer_trigger_type *triggers); | ||
1037 | extern void jbd2_buffer_abort_trigger(struct journal_head *jh, | ||
1038 | struct jbd2_buffer_trigger_type *triggers); | ||
1039 | |||
1011 | /* Buffer IO */ | 1040 | /* Buffer IO */ |
1012 | extern int | 1041 | extern int |
1013 | jbd2_journal_write_metadata_buffer(transaction_t *transaction, | 1042 | jbd2_journal_write_metadata_buffer(transaction_t *transaction, |
@@ -1046,6 +1075,8 @@ extern int jbd2_journal_extend (handle_t *, int nblocks); | |||
1046 | extern int jbd2_journal_get_write_access(handle_t *, struct buffer_head *); | 1075 | extern int jbd2_journal_get_write_access(handle_t *, struct buffer_head *); |
1047 | extern int jbd2_journal_get_create_access (handle_t *, struct buffer_head *); | 1076 | extern int jbd2_journal_get_create_access (handle_t *, struct buffer_head *); |
1048 | extern int jbd2_journal_get_undo_access(handle_t *, struct buffer_head *); | 1077 | extern int jbd2_journal_get_undo_access(handle_t *, struct buffer_head *); |
1078 | void jbd2_journal_set_triggers(struct buffer_head *, | ||
1079 | struct jbd2_buffer_trigger_type *type); | ||
1049 | extern int jbd2_journal_dirty_metadata (handle_t *, struct buffer_head *); | 1080 | extern int jbd2_journal_dirty_metadata (handle_t *, struct buffer_head *); |
1050 | extern void jbd2_journal_release_buffer (handle_t *, struct buffer_head *); | 1081 | extern void jbd2_journal_release_buffer (handle_t *, struct buffer_head *); |
1051 | extern int jbd2_journal_forget (handle_t *, struct buffer_head *); | 1082 | extern int jbd2_journal_forget (handle_t *, struct buffer_head *); |
diff --git a/include/linux/journal-head.h b/include/linux/journal-head.h index bb70ebb6a2d5..525aac3c97df 100644 --- a/include/linux/journal-head.h +++ b/include/linux/journal-head.h | |||
@@ -12,6 +12,8 @@ | |||
12 | 12 | ||
13 | typedef unsigned int tid_t; /* Unique transaction ID */ | 13 | typedef unsigned int tid_t; /* Unique transaction ID */ |
14 | typedef struct transaction_s transaction_t; /* Compound transaction type */ | 14 | typedef struct transaction_s transaction_t; /* Compound transaction type */ |
15 | |||
16 | |||
15 | struct buffer_head; | 17 | struct buffer_head; |
16 | 18 | ||
17 | struct journal_head { | 19 | struct journal_head { |
@@ -87,6 +89,12 @@ struct journal_head { | |||
87 | * [j_list_lock] | 89 | * [j_list_lock] |
88 | */ | 90 | */ |
89 | struct journal_head *b_cpnext, *b_cpprev; | 91 | struct journal_head *b_cpnext, *b_cpprev; |
92 | |||
93 | /* Trigger type */ | ||
94 | struct jbd2_buffer_trigger_type *b_triggers; | ||
95 | |||
96 | /* Trigger type for the committing transaction's frozen data */ | ||
97 | struct jbd2_buffer_trigger_type *b_frozen_triggers; | ||
90 | }; | 98 | }; |
91 | 99 | ||
92 | #endif /* JOURNAL_HEAD_H_INCLUDED */ | 100 | #endif /* JOURNAL_HEAD_H_INCLUDED */ |