Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

GFS2: Move recovery variables to journal structure in memory

If multiple nodes fail and their recovery work runs simultaneously, they
would use the same unprotected variables in the superblock. For example,
they would stomp on each other's revoked blocks lists, which resulted
in file system metadata corruption. This patch moves the necessary
variables so that each journal has its own separate area for tracking
its journal replay.

Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

authored by

Bob Peterson and committed by
Steven Whitehouse
a17d758b fc554ed3

+39 -43
+9 -9
fs/gfs2/incore.h
··· 503 503 unsigned int jd_jid; 504 504 unsigned int jd_blocks; 505 505 int jd_recover_error; 506 + /* Replay stuff */ 507 + 508 + unsigned int jd_found_blocks; 509 + unsigned int jd_found_revokes; 510 + unsigned int jd_replayed_blocks; 511 + 512 + struct list_head jd_revoke_list; 513 + unsigned int jd_replay_tail; 514 + 506 515 }; 507 516 508 517 struct gfs2_statfs_change_host { ··· 790 781 spinlock_t sd_ail_lock; 791 782 struct list_head sd_ail1_list; 792 783 struct list_head sd_ail2_list; 793 - 794 - /* Replay stuff */ 795 - 796 - struct list_head sd_revoke_list; 797 - unsigned int sd_replay_tail; 798 - 799 - unsigned int sd_found_blocks; 800 - unsigned int sd_found_revokes; 801 - unsigned int sd_replayed_blocks; 802 784 803 785 /* For quiescing the filesystem */ 804 786 struct gfs2_holder sd_freeze_gh;
+17 -21
fs/gfs2/lops.c
··· 520 520 static void buf_lo_before_scan(struct gfs2_jdesc *jd, 521 521 struct gfs2_log_header_host *head, int pass) 522 522 { 523 - struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); 524 - 525 523 if (pass != 0) 526 524 return; 527 525 528 - sdp->sd_found_blocks = 0; 529 - sdp->sd_replayed_blocks = 0; 526 + jd->jd_found_blocks = 0; 527 + jd->jd_replayed_blocks = 0; 530 528 } 531 529 532 530 static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, ··· 547 549 for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) { 548 550 blkno = be64_to_cpu(*ptr++); 549 551 550 - sdp->sd_found_blocks++; 552 + jd->jd_found_blocks++; 551 553 552 - if (gfs2_revoke_check(sdp, blkno, start)) 554 + if (gfs2_revoke_check(jd, blkno, start)) 553 555 continue; 554 556 555 557 error = gfs2_replay_read_block(jd, start, &bh_log); ··· 570 572 if (error) 571 573 break; 572 574 573 - sdp->sd_replayed_blocks++; 575 + jd->jd_replayed_blocks++; 574 576 } 575 577 576 578 return error; ··· 613 615 gfs2_meta_sync(ip->i_gl); 614 616 615 617 fs_info(sdp, "jid=%u: Replayed %u of %u blocks\n", 616 - jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks); 618 + jd->jd_jid, jd->jd_replayed_blocks, jd->jd_found_blocks); 617 619 } 618 620 619 621 static void revoke_lo_before_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) ··· 675 677 static void revoke_lo_before_scan(struct gfs2_jdesc *jd, 676 678 struct gfs2_log_header_host *head, int pass) 677 679 { 678 - struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); 679 - 680 680 if (pass != 0) 681 681 return; 682 682 683 - sdp->sd_found_revokes = 0; 684 - sdp->sd_replay_tail = head->lh_tail; 683 + jd->jd_found_revokes = 0; 684 + jd->jd_replay_tail = head->lh_tail; 685 685 } 686 686 687 687 static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, ··· 711 715 while (offset + sizeof(u64) <= sdp->sd_sb.sb_bsize) { 712 716 blkno = be64_to_cpu(*(__be64 *)(bh->b_data + offset)); 713 717 714 - error = gfs2_revoke_add(sdp, blkno, start); 718 + error = gfs2_revoke_add(jd, blkno, start); 715 719 if (error < 0) { 716 720 brelse(bh); 717 721 return error; 718 722 } 719 723 else if (error) 720 - sdp->sd_found_revokes++; 724 + jd->jd_found_revokes++; 721 725 722 726 if (!--revokes) 723 727 break; ··· 737 741 struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); 738 742 739 743 if (error) { 740 - gfs2_revoke_clean(sdp); 744 + gfs2_revoke_clean(jd); 741 745 return; 742 746 } 743 747 if (pass != 1) 744 748 return; 745 749 746 750 fs_info(sdp, "jid=%u: Found %u revoke tags\n", 747 - jd->jd_jid, sdp->sd_found_revokes); 751 + jd->jd_jid, jd->jd_found_revokes); 748 752 749 - gfs2_revoke_clean(sdp); 753 + gfs2_revoke_clean(jd); 750 754 } 751 755 752 756 /** ··· 785 789 blkno = be64_to_cpu(*ptr++); 786 790 esc = be64_to_cpu(*ptr++); 787 791 788 - sdp->sd_found_blocks++; 792 + jd->jd_found_blocks++; 789 793 790 - if (gfs2_revoke_check(sdp, blkno, start)) 794 + if (gfs2_revoke_check(jd, blkno, start)) 791 795 continue; 792 796 793 797 error = gfs2_replay_read_block(jd, start, &bh_log); ··· 807 811 brelse(bh_log); 808 812 brelse(bh_ip); 809 813 810 - sdp->sd_replayed_blocks++; 814 + jd->jd_replayed_blocks++; 811 815 } 812 816 813 817 return error; ··· 831 835 gfs2_meta_sync(ip->i_gl); 832 836 833 837 fs_info(sdp, "jid=%u: Replayed %u of %u data blocks\n", 834 - jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks); 838 + jd->jd_jid, jd->jd_replayed_blocks, jd->jd_found_blocks); 835 839 } 836 840 837 841 static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
+2 -2
fs/gfs2/ops_fstype.c
··· 128 128 atomic_set(&sdp->sd_log_in_flight, 0); 129 129 init_waitqueue_head(&sdp->sd_log_flush_wait); 130 130 131 - INIT_LIST_HEAD(&sdp->sd_revoke_list); 132 - 133 131 return sdp; 134 132 } 135 133 ··· 573 575 break; 574 576 575 577 INIT_LIST_HEAD(&jd->extent_list); 578 + INIT_LIST_HEAD(&jd->jd_revoke_list); 579 + 576 580 INIT_WORK(&jd->jd_work, gfs2_recover_func); 577 581 jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1); 578 582 if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
+8 -8
fs/gfs2/recovery.c
··· 52 52 return error; 53 53 } 54 54 55 - int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where) 55 + int gfs2_revoke_add(struct gfs2_jdesc *jd, u64 blkno, unsigned int where) 56 56 { 57 - struct list_head *head = &sdp->sd_revoke_list; 57 + struct list_head *head = &jd->jd_revoke_list; 58 58 struct gfs2_revoke_replay *rr; 59 59 int found = 0; 60 60 ··· 81 81 return 1; 82 82 } 83 83 84 - int gfs2_revoke_check(struct gfs2_sbd *sdp, u64 blkno, unsigned int where) 84 + int gfs2_revoke_check(struct gfs2_jdesc *jd, u64 blkno, unsigned int where) 85 85 { 86 86 struct gfs2_revoke_replay *rr; 87 87 int wrap, a, b, revoke; 88 88 int found = 0; 89 89 90 - list_for_each_entry(rr, &sdp->sd_revoke_list, rr_list) { 90 + list_for_each_entry(rr, &jd->jd_revoke_list, rr_list) { 91 91 if (rr->rr_blkno == blkno) { 92 92 found = 1; 93 93 break; ··· 97 97 if (!found) 98 98 return 0; 99 99 100 - wrap = (rr->rr_where < sdp->sd_replay_tail); 101 - a = (sdp->sd_replay_tail < where); 100 + wrap = (rr->rr_where < jd->jd_replay_tail); 101 + a = (jd->jd_replay_tail < where); 102 102 b = (where < rr->rr_where); 103 103 revoke = (wrap) ? (a || b) : (a && b); 104 104 105 105 return revoke; 106 106 } 107 107 108 - void gfs2_revoke_clean(struct gfs2_sbd *sdp) 108 + void gfs2_revoke_clean(struct gfs2_jdesc *jd) 109 109 { 110 - struct list_head *head = &sdp->sd_revoke_list; 110 + struct list_head *head = &jd->jd_revoke_list; 111 111 struct gfs2_revoke_replay *rr; 112 112 113 113 while (!list_empty(head)) {
+3 -3
fs/gfs2/recovery.h
··· 23 23 extern int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, 24 24 struct buffer_head **bh); 25 25 26 - extern int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where); 27 - extern int gfs2_revoke_check(struct gfs2_sbd *sdp, u64 blkno, unsigned int where); 28 - extern void gfs2_revoke_clean(struct gfs2_sbd *sdp); 26 + extern int gfs2_revoke_add(struct gfs2_jdesc *jd, u64 blkno, unsigned int where); 27 + extern int gfs2_revoke_check(struct gfs2_jdesc *jd, u64 blkno, unsigned int where); 28 + extern void gfs2_revoke_clean(struct gfs2_jdesc *jd); 29 29 30 30 extern int gfs2_find_jhead(struct gfs2_jdesc *jd, 31 31 struct gfs2_log_header_host *head);