aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2010-07-14 01:56:33 -0400
committerJoel Becker <joel.becker@oracle.com>2010-07-15 18:17:47 -0400
commit13ceef099edd2b70c5a6f3a9ef5d6d97cda2e096 (patch)
tree5d65c397e9e85abe11a6fb0ebf3a69e8a4e91e0d /fs
parenta39953dd95ff10e311083d94f4f95c348cb22464 (diff)
jbd2/ocfs2: Fix block checksumming when a buffer is used in several transactions
OCFS2 uses t_commit trigger to compute and store checksum of the just committed blocks. When a buffer has b_frozen_data, checksum is computed for it instead of b_data but this can result in an old checksum being written to the filesystem in the following scenario: 1) transaction1 is opened 2) handle1 is opened 3) journal_access(handle1, bh) - This sets jh->b_transaction to transaction1 4) modify(bh) 5) journal_dirty(handle1, bh) 6) handle1 is closed 7) start committing transaction1, opening transaction2 8) handle2 is opened 9) journal_access(handle2, bh) - This copies off b_frozen_data to make it safe for transaction1 to commit. jh->b_next_transaction is set to transaction2. 10) jbd2_journal_write_metadata() checksums b_frozen_data 11) the journal correctly writes b_frozen_data to the disk journal 12) handle2 is closed - There was no dirty call for the bh on handle2, so it is never queued for any more journal operation 13) Checkpointing finally happens, and it just spools the bh via normal buffer writeback. This will write b_data, which was never triggered on and thus contains a wrong (old) checksum. This patch fixes the problem by calling the trigger at the moment data is frozen for journal commit - i.e., either when b_frozen_data is created by do_get_write_access or just before we write a buffer to the log if b_frozen_data does not exist. We also rename the trigger to t_frozen as that better describes when it is called. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Mark Fasheh <mfasheh@suse.com> Signed-off-by: Joel Becker <joel.becker@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/jbd2/journal.c15
-rw-r--r--fs/jbd2/transaction.c9
-rw-r--r--fs/ocfs2/journal.c24
3 files changed, 25 insertions, 23 deletions
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index bc2ff5932769..036880895bfc 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -297,7 +297,6 @@ int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
297 struct page *new_page; 297 struct page *new_page;
298 unsigned int new_offset; 298 unsigned int new_offset;
299 struct buffer_head *bh_in = jh2bh(jh_in); 299 struct buffer_head *bh_in = jh2bh(jh_in);
300 struct jbd2_buffer_trigger_type *triggers;
301 journal_t *journal = transaction->t_journal; 300 journal_t *journal = transaction->t_journal;
302 301
303 /* 302 /*
@@ -328,21 +327,21 @@ repeat:
328 done_copy_out = 1; 327 done_copy_out = 1;
329 new_page = virt_to_page(jh_in->b_frozen_data); 328 new_page = virt_to_page(jh_in->b_frozen_data);
330 new_offset = offset_in_page(jh_in->b_frozen_data); 329 new_offset = offset_in_page(jh_in->b_frozen_data);
331 triggers = jh_in->b_frozen_triggers;
332 } else { 330 } else {
333 new_page = jh2bh(jh_in)->b_page; 331 new_page = jh2bh(jh_in)->b_page;
334 new_offset = offset_in_page(jh2bh(jh_in)->b_data); 332 new_offset = offset_in_page(jh2bh(jh_in)->b_data);
335 triggers = jh_in->b_triggers;
336 } 333 }
337 334
338 mapped_data = kmap_atomic(new_page, KM_USER0); 335 mapped_data = kmap_atomic(new_page, KM_USER0);
339 /* 336 /*
340 * Fire any commit trigger. Do this before checking for escaping, 337 * Fire data frozen trigger if data already wasn't frozen. Do this
341 * as the trigger may modify the magic offset. If a copy-out 338 * before checking for escaping, as the trigger may modify the magic
342 * happens afterwards, it will have the correct data in the buffer. 339 * offset. If a copy-out happens afterwards, it will have the correct
340 * data in the buffer.
343 */ 341 */
344 jbd2_buffer_commit_trigger(jh_in, mapped_data + new_offset, 342 if (!done_copy_out)
345 triggers); 343 jbd2_buffer_frozen_trigger(jh_in, mapped_data + new_offset,
344 jh_in->b_triggers);
346 345
347 /* 346 /*
348 * Check for escaping 347 * Check for escaping
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index e214d68620ac..b8e0806681bb 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -725,6 +725,9 @@ done:
725 page = jh2bh(jh)->b_page; 725 page = jh2bh(jh)->b_page;
726 offset = ((unsigned long) jh2bh(jh)->b_data) & ~PAGE_MASK; 726 offset = ((unsigned long) jh2bh(jh)->b_data) & ~PAGE_MASK;
727 source = kmap_atomic(page, KM_USER0); 727 source = kmap_atomic(page, KM_USER0);
728 /* Fire data frozen trigger just before we copy the data */
729 jbd2_buffer_frozen_trigger(jh, source + offset,
730 jh->b_triggers);
728 memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size); 731 memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size);
729 kunmap_atomic(source, KM_USER0); 732 kunmap_atomic(source, KM_USER0);
730 733
@@ -963,15 +966,15 @@ void jbd2_journal_set_triggers(struct buffer_head *bh,
963 jh->b_triggers = type; 966 jh->b_triggers = type;
964} 967}
965 968
966void jbd2_buffer_commit_trigger(struct journal_head *jh, void *mapped_data, 969void jbd2_buffer_frozen_trigger(struct journal_head *jh, void *mapped_data,
967 struct jbd2_buffer_trigger_type *triggers) 970 struct jbd2_buffer_trigger_type *triggers)
968{ 971{
969 struct buffer_head *bh = jh2bh(jh); 972 struct buffer_head *bh = jh2bh(jh);
970 973
971 if (!triggers || !triggers->t_commit) 974 if (!triggers || !triggers->t_frozen)
972 return; 975 return;
973 976
974 triggers->t_commit(triggers, bh, mapped_data, bh->b_size); 977 triggers->t_frozen(triggers, bh, mapped_data, bh->b_size);
975} 978}
976 979
977void jbd2_buffer_abort_trigger(struct journal_head *jh, 980void jbd2_buffer_abort_trigger(struct journal_head *jh,
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index 39113b5e79e7..625de9d7088c 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -472,7 +472,7 @@ static inline struct ocfs2_triggers *to_ocfs2_trigger(struct jbd2_buffer_trigger
472 return container_of(triggers, struct ocfs2_triggers, ot_triggers); 472 return container_of(triggers, struct ocfs2_triggers, ot_triggers);
473} 473}
474 474
475static void ocfs2_commit_trigger(struct jbd2_buffer_trigger_type *triggers, 475static void ocfs2_frozen_trigger(struct jbd2_buffer_trigger_type *triggers,
476 struct buffer_head *bh, 476 struct buffer_head *bh,
477 void *data, size_t size) 477 void *data, size_t size)
478{ 478{
@@ -491,7 +491,7 @@ static void ocfs2_commit_trigger(struct jbd2_buffer_trigger_type *triggers,
491 * Quota blocks have their own trigger because the struct ocfs2_block_check 491 * Quota blocks have their own trigger because the struct ocfs2_block_check
492 * offset depends on the blocksize. 492 * offset depends on the blocksize.
493 */ 493 */
494static void ocfs2_dq_commit_trigger(struct jbd2_buffer_trigger_type *triggers, 494static void ocfs2_dq_frozen_trigger(struct jbd2_buffer_trigger_type *triggers,
495 struct buffer_head *bh, 495 struct buffer_head *bh,
496 void *data, size_t size) 496 void *data, size_t size)
497{ 497{
@@ -511,7 +511,7 @@ static void ocfs2_dq_commit_trigger(struct jbd2_buffer_trigger_type *triggers,
511 * Directory blocks also have their own trigger because the 511 * Directory blocks also have their own trigger because the
512 * struct ocfs2_block_check offset depends on the blocksize. 512 * struct ocfs2_block_check offset depends on the blocksize.
513 */ 513 */
514static void ocfs2_db_commit_trigger(struct jbd2_buffer_trigger_type *triggers, 514static void ocfs2_db_frozen_trigger(struct jbd2_buffer_trigger_type *triggers,
515 struct buffer_head *bh, 515 struct buffer_head *bh,
516 void *data, size_t size) 516 void *data, size_t size)
517{ 517{
@@ -544,7 +544,7 @@ static void ocfs2_abort_trigger(struct jbd2_buffer_trigger_type *triggers,
544 544
545static struct ocfs2_triggers di_triggers = { 545static struct ocfs2_triggers di_triggers = {
546 .ot_triggers = { 546 .ot_triggers = {
547 .t_commit = ocfs2_commit_trigger, 547 .t_frozen = ocfs2_frozen_trigger,
548 .t_abort = ocfs2_abort_trigger, 548 .t_abort = ocfs2_abort_trigger,
549 }, 549 },
550 .ot_offset = offsetof(struct ocfs2_dinode, i_check), 550 .ot_offset = offsetof(struct ocfs2_dinode, i_check),
@@ -552,7 +552,7 @@ static struct ocfs2_triggers di_triggers = {
552 552
553static struct ocfs2_triggers eb_triggers = { 553static struct ocfs2_triggers eb_triggers = {
554 .ot_triggers = { 554 .ot_triggers = {
555 .t_commit = ocfs2_commit_trigger, 555 .t_frozen = ocfs2_frozen_trigger,
556 .t_abort = ocfs2_abort_trigger, 556 .t_abort = ocfs2_abort_trigger,
557 }, 557 },
558 .ot_offset = offsetof(struct ocfs2_extent_block, h_check), 558 .ot_offset = offsetof(struct ocfs2_extent_block, h_check),
@@ -560,7 +560,7 @@ static struct ocfs2_triggers eb_triggers = {
560 560
561static struct ocfs2_triggers rb_triggers = { 561static struct ocfs2_triggers rb_triggers = {
562 .ot_triggers = { 562 .ot_triggers = {
563 .t_commit = ocfs2_commit_trigger, 563 .t_frozen = ocfs2_frozen_trigger,
564 .t_abort = ocfs2_abort_trigger, 564 .t_abort = ocfs2_abort_trigger,
565 }, 565 },
566 .ot_offset = offsetof(struct ocfs2_refcount_block, rf_check), 566 .ot_offset = offsetof(struct ocfs2_refcount_block, rf_check),
@@ -568,7 +568,7 @@ static struct ocfs2_triggers rb_triggers = {
568 568
569static struct ocfs2_triggers gd_triggers = { 569static struct ocfs2_triggers gd_triggers = {
570 .ot_triggers = { 570 .ot_triggers = {
571 .t_commit = ocfs2_commit_trigger, 571 .t_frozen = ocfs2_frozen_trigger,
572 .t_abort = ocfs2_abort_trigger, 572 .t_abort = ocfs2_abort_trigger,
573 }, 573 },
574 .ot_offset = offsetof(struct ocfs2_group_desc, bg_check), 574 .ot_offset = offsetof(struct ocfs2_group_desc, bg_check),
@@ -576,14 +576,14 @@ static struct ocfs2_triggers gd_triggers = {
576 576
577static struct ocfs2_triggers db_triggers = { 577static struct ocfs2_triggers db_triggers = {
578 .ot_triggers = { 578 .ot_triggers = {
579 .t_commit = ocfs2_db_commit_trigger, 579 .t_frozen = ocfs2_db_frozen_trigger,
580 .t_abort = ocfs2_abort_trigger, 580 .t_abort = ocfs2_abort_trigger,
581 }, 581 },
582}; 582};
583 583
584static struct ocfs2_triggers xb_triggers = { 584static struct ocfs2_triggers xb_triggers = {
585 .ot_triggers = { 585 .ot_triggers = {
586 .t_commit = ocfs2_commit_trigger, 586 .t_frozen = ocfs2_frozen_trigger,
587 .t_abort = ocfs2_abort_trigger, 587 .t_abort = ocfs2_abort_trigger,
588 }, 588 },
589 .ot_offset = offsetof(struct ocfs2_xattr_block, xb_check), 589 .ot_offset = offsetof(struct ocfs2_xattr_block, xb_check),
@@ -591,14 +591,14 @@ static struct ocfs2_triggers xb_triggers = {
591 591
592static struct ocfs2_triggers dq_triggers = { 592static struct ocfs2_triggers dq_triggers = {
593 .ot_triggers = { 593 .ot_triggers = {
594 .t_commit = ocfs2_dq_commit_trigger, 594 .t_frozen = ocfs2_dq_frozen_trigger,
595 .t_abort = ocfs2_abort_trigger, 595 .t_abort = ocfs2_abort_trigger,
596 }, 596 },
597}; 597};
598 598
599static struct ocfs2_triggers dr_triggers = { 599static struct ocfs2_triggers dr_triggers = {
600 .ot_triggers = { 600 .ot_triggers = {
601 .t_commit = ocfs2_commit_trigger, 601 .t_frozen = ocfs2_frozen_trigger,
602 .t_abort = ocfs2_abort_trigger, 602 .t_abort = ocfs2_abort_trigger,
603 }, 603 },
604 .ot_offset = offsetof(struct ocfs2_dx_root_block, dr_check), 604 .ot_offset = offsetof(struct ocfs2_dx_root_block, dr_check),
@@ -606,7 +606,7 @@ static struct ocfs2_triggers dr_triggers = {
606 606
607static struct ocfs2_triggers dl_triggers = { 607static struct ocfs2_triggers dl_triggers = {
608 .ot_triggers = { 608 .ot_triggers = {
609 .t_commit = ocfs2_commit_trigger, 609 .t_frozen = ocfs2_frozen_trigger,
610 .t_abort = ocfs2_abort_trigger, 610 .t_abort = ocfs2_abort_trigger,
611 }, 611 },
612 .ot_offset = offsetof(struct ocfs2_dx_leaf, dl_check), 612 .ot_offset = offsetof(struct ocfs2_dx_leaf, dl_check),