diff options
Diffstat (limited to 'fs/xfs/xfs_log_recover.c')
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 311 |
1 files changed, 154 insertions, 157 deletions
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 22e6efdc17ea..0de08e366315 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
@@ -56,33 +56,61 @@ STATIC void xlog_recover_check_summary(xlog_t *); | |||
56 | #define xlog_recover_check_summary(log) | 56 | #define xlog_recover_check_summary(log) |
57 | #endif | 57 | #endif |
58 | 58 | ||
59 | |||
60 | /* | 59 | /* |
61 | * Sector aligned buffer routines for buffer create/read/write/access | 60 | * Sector aligned buffer routines for buffer create/read/write/access |
62 | */ | 61 | */ |
63 | 62 | ||
64 | #define XLOG_SECTOR_ROUNDUP_BBCOUNT(log, bbs) \ | 63 | /* |
65 | ( ((log)->l_sectbb_mask && (bbs & (log)->l_sectbb_mask)) ? \ | 64 | * Verify the given count of basic blocks is valid number of blocks |
66 | ((bbs + (log)->l_sectbb_mask + 1) & ~(log)->l_sectbb_mask) : (bbs) ) | 65 | * to specify for an operation involving the given XFS log buffer. |
67 | #define XLOG_SECTOR_ROUNDDOWN_BLKNO(log, bno) ((bno) & ~(log)->l_sectbb_mask) | 66 | * Returns nonzero if the count is valid, 0 otherwise. |
67 | */ | ||
68 | 68 | ||
69 | static inline int | ||
70 | xlog_buf_bbcount_valid( | ||
71 | xlog_t *log, | ||
72 | int bbcount) | ||
73 | { | ||
74 | return bbcount > 0 && bbcount <= log->l_logBBsize; | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * Allocate a buffer to hold log data. The buffer needs to be able | ||
79 | * to map to a range of nbblks basic blocks at any valid (basic | ||
80 | * block) offset within the log. | ||
81 | */ | ||
69 | STATIC xfs_buf_t * | 82 | STATIC xfs_buf_t * |
70 | xlog_get_bp( | 83 | xlog_get_bp( |
71 | xlog_t *log, | 84 | xlog_t *log, |
72 | int nbblks) | 85 | int nbblks) |
73 | { | 86 | { |
74 | if (nbblks <= 0 || nbblks > log->l_logBBsize) { | 87 | if (!xlog_buf_bbcount_valid(log, nbblks)) { |
75 | xlog_warn("XFS: Invalid block length (0x%x) given for buffer", nbblks); | 88 | xlog_warn("XFS: Invalid block length (0x%x) given for buffer", |
76 | XFS_ERROR_REPORT("xlog_get_bp(1)", | 89 | nbblks); |
77 | XFS_ERRLEVEL_HIGH, log->l_mp); | 90 | XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp); |
78 | return NULL; | 91 | return NULL; |
79 | } | 92 | } |
80 | 93 | ||
81 | if (log->l_sectbb_log) { | 94 | /* |
82 | if (nbblks > 1) | 95 | * We do log I/O in units of log sectors (a power-of-2 |
83 | nbblks += XLOG_SECTOR_ROUNDUP_BBCOUNT(log, 1); | 96 | * multiple of the basic block size), so we round up the |
84 | nbblks = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, nbblks); | 97 | * requested size to acommodate the basic blocks required |
85 | } | 98 | * for complete log sectors. |
99 | * | ||
100 | * In addition, the buffer may be used for a non-sector- | ||
101 | * aligned block offset, in which case an I/O of the | ||
102 | * requested size could extend beyond the end of the | ||
103 | * buffer. If the requested size is only 1 basic block it | ||
104 | * will never straddle a sector boundary, so this won't be | ||
105 | * an issue. Nor will this be a problem if the log I/O is | ||
106 | * done in basic blocks (sector size 1). But otherwise we | ||
107 | * extend the buffer by one extra log sector to ensure | ||
108 | * there's space to accomodate this possiblility. | ||
109 | */ | ||
110 | if (nbblks > 1 && log->l_sectBBsize > 1) | ||
111 | nbblks += log->l_sectBBsize; | ||
112 | nbblks = round_up(nbblks, log->l_sectBBsize); | ||
113 | |||
86 | return xfs_buf_get_noaddr(BBTOB(nbblks), log->l_mp->m_logdev_targp); | 114 | return xfs_buf_get_noaddr(BBTOB(nbblks), log->l_mp->m_logdev_targp); |
87 | } | 115 | } |
88 | 116 | ||
@@ -93,6 +121,10 @@ xlog_put_bp( | |||
93 | xfs_buf_free(bp); | 121 | xfs_buf_free(bp); |
94 | } | 122 | } |
95 | 123 | ||
124 | /* | ||
125 | * Return the address of the start of the given block number's data | ||
126 | * in a log buffer. The buffer covers a log sector-aligned region. | ||
127 | */ | ||
96 | STATIC xfs_caddr_t | 128 | STATIC xfs_caddr_t |
97 | xlog_align( | 129 | xlog_align( |
98 | xlog_t *log, | 130 | xlog_t *log, |
@@ -100,14 +132,14 @@ xlog_align( | |||
100 | int nbblks, | 132 | int nbblks, |
101 | xfs_buf_t *bp) | 133 | xfs_buf_t *bp) |
102 | { | 134 | { |
135 | xfs_daddr_t offset; | ||
103 | xfs_caddr_t ptr; | 136 | xfs_caddr_t ptr; |
104 | 137 | ||
105 | if (!log->l_sectbb_log) | 138 | offset = blk_no & ((xfs_daddr_t) log->l_sectBBsize - 1); |
106 | return XFS_BUF_PTR(bp); | 139 | ptr = XFS_BUF_PTR(bp) + BBTOB(offset); |
140 | |||
141 | ASSERT(ptr + BBTOB(nbblks) <= XFS_BUF_PTR(bp) + XFS_BUF_SIZE(bp)); | ||
107 | 142 | ||
108 | ptr = XFS_BUF_PTR(bp) + BBTOB((int)blk_no & log->l_sectbb_mask); | ||
109 | ASSERT(XFS_BUF_SIZE(bp) >= | ||
110 | BBTOB(nbblks + (blk_no & log->l_sectbb_mask))); | ||
111 | return ptr; | 143 | return ptr; |
112 | } | 144 | } |
113 | 145 | ||
@@ -124,21 +156,18 @@ xlog_bread_noalign( | |||
124 | { | 156 | { |
125 | int error; | 157 | int error; |
126 | 158 | ||
127 | if (nbblks <= 0 || nbblks > log->l_logBBsize) { | 159 | if (!xlog_buf_bbcount_valid(log, nbblks)) { |
128 | xlog_warn("XFS: Invalid block length (0x%x) given for buffer", nbblks); | 160 | xlog_warn("XFS: Invalid block length (0x%x) given for buffer", |
129 | XFS_ERROR_REPORT("xlog_bread(1)", | 161 | nbblks); |
130 | XFS_ERRLEVEL_HIGH, log->l_mp); | 162 | XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp); |
131 | return EFSCORRUPTED; | 163 | return EFSCORRUPTED; |
132 | } | 164 | } |
133 | 165 | ||
134 | if (log->l_sectbb_log) { | 166 | blk_no = round_down(blk_no, log->l_sectBBsize); |
135 | blk_no = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, blk_no); | 167 | nbblks = round_up(nbblks, log->l_sectBBsize); |
136 | nbblks = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, nbblks); | ||
137 | } | ||
138 | 168 | ||
139 | ASSERT(nbblks > 0); | 169 | ASSERT(nbblks > 0); |
140 | ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp)); | 170 | ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp)); |
141 | ASSERT(bp); | ||
142 | 171 | ||
143 | XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no); | 172 | XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no); |
144 | XFS_BUF_READ(bp); | 173 | XFS_BUF_READ(bp); |
@@ -186,17 +215,15 @@ xlog_bwrite( | |||
186 | { | 215 | { |
187 | int error; | 216 | int error; |
188 | 217 | ||
189 | if (nbblks <= 0 || nbblks > log->l_logBBsize) { | 218 | if (!xlog_buf_bbcount_valid(log, nbblks)) { |
190 | xlog_warn("XFS: Invalid block length (0x%x) given for buffer", nbblks); | 219 | xlog_warn("XFS: Invalid block length (0x%x) given for buffer", |
191 | XFS_ERROR_REPORT("xlog_bwrite(1)", | 220 | nbblks); |
192 | XFS_ERRLEVEL_HIGH, log->l_mp); | 221 | XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp); |
193 | return EFSCORRUPTED; | 222 | return EFSCORRUPTED; |
194 | } | 223 | } |
195 | 224 | ||
196 | if (log->l_sectbb_log) { | 225 | blk_no = round_down(blk_no, log->l_sectBBsize); |
197 | blk_no = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, blk_no); | 226 | nbblks = round_up(nbblks, log->l_sectBBsize); |
198 | nbblks = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, nbblks); | ||
199 | } | ||
200 | 227 | ||
201 | ASSERT(nbblks > 0); | 228 | ASSERT(nbblks > 0); |
202 | ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp)); | 229 | ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp)); |
@@ -327,39 +354,38 @@ xlog_find_cycle_start( | |||
327 | { | 354 | { |
328 | xfs_caddr_t offset; | 355 | xfs_caddr_t offset; |
329 | xfs_daddr_t mid_blk; | 356 | xfs_daddr_t mid_blk; |
357 | xfs_daddr_t end_blk; | ||
330 | uint mid_cycle; | 358 | uint mid_cycle; |
331 | int error; | 359 | int error; |
332 | 360 | ||
333 | mid_blk = BLK_AVG(first_blk, *last_blk); | 361 | end_blk = *last_blk; |
334 | while (mid_blk != first_blk && mid_blk != *last_blk) { | 362 | mid_blk = BLK_AVG(first_blk, end_blk); |
363 | while (mid_blk != first_blk && mid_blk != end_blk) { | ||
335 | error = xlog_bread(log, mid_blk, 1, bp, &offset); | 364 | error = xlog_bread(log, mid_blk, 1, bp, &offset); |
336 | if (error) | 365 | if (error) |
337 | return error; | 366 | return error; |
338 | mid_cycle = xlog_get_cycle(offset); | 367 | mid_cycle = xlog_get_cycle(offset); |
339 | if (mid_cycle == cycle) { | 368 | if (mid_cycle == cycle) |
340 | *last_blk = mid_blk; | 369 | end_blk = mid_blk; /* last_half_cycle == mid_cycle */ |
341 | /* last_half_cycle == mid_cycle */ | 370 | else |
342 | } else { | 371 | first_blk = mid_blk; /* first_half_cycle == mid_cycle */ |
343 | first_blk = mid_blk; | 372 | mid_blk = BLK_AVG(first_blk, end_blk); |
344 | /* first_half_cycle == mid_cycle */ | ||
345 | } | ||
346 | mid_blk = BLK_AVG(first_blk, *last_blk); | ||
347 | } | 373 | } |
348 | ASSERT((mid_blk == first_blk && mid_blk+1 == *last_blk) || | 374 | ASSERT((mid_blk == first_blk && mid_blk+1 == end_blk) || |
349 | (mid_blk == *last_blk && mid_blk-1 == first_blk)); | 375 | (mid_blk == end_blk && mid_blk-1 == first_blk)); |
376 | |||
377 | *last_blk = end_blk; | ||
350 | 378 | ||
351 | return 0; | 379 | return 0; |
352 | } | 380 | } |
353 | 381 | ||
354 | /* | 382 | /* |
355 | * Check that the range of blocks does not contain the cycle number | 383 | * Check that a range of blocks does not contain stop_on_cycle_no. |
356 | * given. The scan needs to occur from front to back and the ptr into the | 384 | * Fill in *new_blk with the block offset where such a block is |
357 | * region must be updated since a later routine will need to perform another | 385 | * found, or with -1 (an invalid block number) if there is no such |
358 | * test. If the region is completely good, we end up returning the same | 386 | * block in the range. The scan needs to occur from front to back |
359 | * last block number. | 387 | * and the pointer into the region must be updated since a later |
360 | * | 388 | * routine will need to perform another test. |
361 | * Set blkno to -1 if we encounter no errors. This is an invalid block number | ||
362 | * since we don't ever expect logs to get this large. | ||
363 | */ | 389 | */ |
364 | STATIC int | 390 | STATIC int |
365 | xlog_find_verify_cycle( | 391 | xlog_find_verify_cycle( |
@@ -376,12 +402,16 @@ xlog_find_verify_cycle( | |||
376 | xfs_caddr_t buf = NULL; | 402 | xfs_caddr_t buf = NULL; |
377 | int error = 0; | 403 | int error = 0; |
378 | 404 | ||
405 | /* | ||
406 | * Greedily allocate a buffer big enough to handle the full | ||
407 | * range of basic blocks we'll be examining. If that fails, | ||
408 | * try a smaller size. We need to be able to read at least | ||
409 | * a log sector, or we're out of luck. | ||
410 | */ | ||
379 | bufblks = 1 << ffs(nbblks); | 411 | bufblks = 1 << ffs(nbblks); |
380 | |||
381 | while (!(bp = xlog_get_bp(log, bufblks))) { | 412 | while (!(bp = xlog_get_bp(log, bufblks))) { |
382 | /* can't get enough memory to do everything in one big buffer */ | ||
383 | bufblks >>= 1; | 413 | bufblks >>= 1; |
384 | if (bufblks <= log->l_sectbb_log) | 414 | if (bufblks < log->l_sectBBsize) |
385 | return ENOMEM; | 415 | return ENOMEM; |
386 | } | 416 | } |
387 | 417 | ||
@@ -629,7 +659,7 @@ xlog_find_head( | |||
629 | * In this case we want to find the first block with cycle | 659 | * In this case we want to find the first block with cycle |
630 | * number matching last_half_cycle. We expect the log to be | 660 | * number matching last_half_cycle. We expect the log to be |
631 | * some variation on | 661 | * some variation on |
632 | * x + 1 ... | x ... | 662 | * x + 1 ... | x ... | x |
633 | * The first block with cycle number x (last_half_cycle) will | 663 | * The first block with cycle number x (last_half_cycle) will |
634 | * be where the new head belongs. First we do a binary search | 664 | * be where the new head belongs. First we do a binary search |
635 | * for the first occurrence of last_half_cycle. The binary | 665 | * for the first occurrence of last_half_cycle. The binary |
@@ -639,11 +669,13 @@ xlog_find_head( | |||
639 | * the log, then we look for occurrences of last_half_cycle - 1 | 669 | * the log, then we look for occurrences of last_half_cycle - 1 |
640 | * at the end of the log. The cases we're looking for look | 670 | * at the end of the log. The cases we're looking for look |
641 | * like | 671 | * like |
642 | * x + 1 ... | x | x + 1 | x ... | 672 | * v binary search stopped here |
643 | * ^ binary search stopped here | 673 | * x + 1 ... | x | x + 1 | x ... | x |
674 | * ^ but we want to locate this spot | ||
644 | * or | 675 | * or |
645 | * x + 1 ... | x ... | x - 1 | x | ||
646 | * <---------> less than scan distance | 676 | * <---------> less than scan distance |
677 | * x + 1 ... | x ... | x - 1 | x | ||
678 | * ^ we want to locate this spot | ||
647 | */ | 679 | */ |
648 | stop_on_cycle = last_half_cycle; | 680 | stop_on_cycle = last_half_cycle; |
649 | if ((error = xlog_find_cycle_start(log, bp, first_blk, | 681 | if ((error = xlog_find_cycle_start(log, bp, first_blk, |
@@ -699,16 +731,16 @@ xlog_find_head( | |||
699 | * certainly not the head of the log. By searching for | 731 | * certainly not the head of the log. By searching for |
700 | * last_half_cycle-1 we accomplish that. | 732 | * last_half_cycle-1 we accomplish that. |
701 | */ | 733 | */ |
702 | start_blk = log_bbnum - num_scan_bblks + head_blk; | ||
703 | ASSERT(head_blk <= INT_MAX && | 734 | ASSERT(head_blk <= INT_MAX && |
704 | (xfs_daddr_t) num_scan_bblks - head_blk >= 0); | 735 | (xfs_daddr_t) num_scan_bblks >= head_blk); |
736 | start_blk = log_bbnum - (num_scan_bblks - head_blk); | ||
705 | if ((error = xlog_find_verify_cycle(log, start_blk, | 737 | if ((error = xlog_find_verify_cycle(log, start_blk, |
706 | num_scan_bblks - (int)head_blk, | 738 | num_scan_bblks - (int)head_blk, |
707 | (stop_on_cycle - 1), &new_blk))) | 739 | (stop_on_cycle - 1), &new_blk))) |
708 | goto bp_err; | 740 | goto bp_err; |
709 | if (new_blk != -1) { | 741 | if (new_blk != -1) { |
710 | head_blk = new_blk; | 742 | head_blk = new_blk; |
711 | goto bad_blk; | 743 | goto validate_head; |
712 | } | 744 | } |
713 | 745 | ||
714 | /* | 746 | /* |
@@ -726,7 +758,7 @@ xlog_find_head( | |||
726 | head_blk = new_blk; | 758 | head_blk = new_blk; |
727 | } | 759 | } |
728 | 760 | ||
729 | bad_blk: | 761 | validate_head: |
730 | /* | 762 | /* |
731 | * Now we need to make sure head_blk is not pointing to a block in | 763 | * Now we need to make sure head_blk is not pointing to a block in |
732 | * the middle of a log record. | 764 | * the middle of a log record. |
@@ -748,7 +780,7 @@ xlog_find_head( | |||
748 | if ((error = xlog_find_verify_log_record(log, start_blk, | 780 | if ((error = xlog_find_verify_log_record(log, start_blk, |
749 | &head_blk, 0)) == -1) { | 781 | &head_blk, 0)) == -1) { |
750 | /* We hit the beginning of the log during our search */ | 782 | /* We hit the beginning of the log during our search */ |
751 | start_blk = log_bbnum - num_scan_bblks + head_blk; | 783 | start_blk = log_bbnum - (num_scan_bblks - head_blk); |
752 | new_blk = log_bbnum; | 784 | new_blk = log_bbnum; |
753 | ASSERT(start_blk <= INT_MAX && | 785 | ASSERT(start_blk <= INT_MAX && |
754 | (xfs_daddr_t) log_bbnum-start_blk >= 0); | 786 | (xfs_daddr_t) log_bbnum-start_blk >= 0); |
@@ -833,12 +865,12 @@ xlog_find_tail( | |||
833 | if (*head_blk == 0) { /* special case */ | 865 | if (*head_blk == 0) { /* special case */ |
834 | error = xlog_bread(log, 0, 1, bp, &offset); | 866 | error = xlog_bread(log, 0, 1, bp, &offset); |
835 | if (error) | 867 | if (error) |
836 | goto bread_err; | 868 | goto done; |
837 | 869 | ||
838 | if (xlog_get_cycle(offset) == 0) { | 870 | if (xlog_get_cycle(offset) == 0) { |
839 | *tail_blk = 0; | 871 | *tail_blk = 0; |
840 | /* leave all other log inited values alone */ | 872 | /* leave all other log inited values alone */ |
841 | goto exit; | 873 | goto done; |
842 | } | 874 | } |
843 | } | 875 | } |
844 | 876 | ||
@@ -849,7 +881,7 @@ xlog_find_tail( | |||
849 | for (i = (int)(*head_blk) - 1; i >= 0; i--) { | 881 | for (i = (int)(*head_blk) - 1; i >= 0; i--) { |
850 | error = xlog_bread(log, i, 1, bp, &offset); | 882 | error = xlog_bread(log, i, 1, bp, &offset); |
851 | if (error) | 883 | if (error) |
852 | goto bread_err; | 884 | goto done; |
853 | 885 | ||
854 | if (XLOG_HEADER_MAGIC_NUM == be32_to_cpu(*(__be32 *)offset)) { | 886 | if (XLOG_HEADER_MAGIC_NUM == be32_to_cpu(*(__be32 *)offset)) { |
855 | found = 1; | 887 | found = 1; |
@@ -866,7 +898,7 @@ xlog_find_tail( | |||
866 | for (i = log->l_logBBsize - 1; i >= (int)(*head_blk); i--) { | 898 | for (i = log->l_logBBsize - 1; i >= (int)(*head_blk); i--) { |
867 | error = xlog_bread(log, i, 1, bp, &offset); | 899 | error = xlog_bread(log, i, 1, bp, &offset); |
868 | if (error) | 900 | if (error) |
869 | goto bread_err; | 901 | goto done; |
870 | 902 | ||
871 | if (XLOG_HEADER_MAGIC_NUM == | 903 | if (XLOG_HEADER_MAGIC_NUM == |
872 | be32_to_cpu(*(__be32 *)offset)) { | 904 | be32_to_cpu(*(__be32 *)offset)) { |
@@ -941,7 +973,7 @@ xlog_find_tail( | |||
941 | umount_data_blk = (i + hblks) % log->l_logBBsize; | 973 | umount_data_blk = (i + hblks) % log->l_logBBsize; |
942 | error = xlog_bread(log, umount_data_blk, 1, bp, &offset); | 974 | error = xlog_bread(log, umount_data_blk, 1, bp, &offset); |
943 | if (error) | 975 | if (error) |
944 | goto bread_err; | 976 | goto done; |
945 | 977 | ||
946 | op_head = (xlog_op_header_t *)offset; | 978 | op_head = (xlog_op_header_t *)offset; |
947 | if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) { | 979 | if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) { |
@@ -987,12 +1019,10 @@ xlog_find_tail( | |||
987 | * But... if the -device- itself is readonly, just skip this. | 1019 | * But... if the -device- itself is readonly, just skip this. |
988 | * We can't recover this device anyway, so it won't matter. | 1020 | * We can't recover this device anyway, so it won't matter. |
989 | */ | 1021 | */ |
990 | if (!xfs_readonly_buftarg(log->l_mp->m_logdev_targp)) { | 1022 | if (!xfs_readonly_buftarg(log->l_mp->m_logdev_targp)) |
991 | error = xlog_clear_stale_blocks(log, tail_lsn); | 1023 | error = xlog_clear_stale_blocks(log, tail_lsn); |
992 | } | ||
993 | 1024 | ||
994 | bread_err: | 1025 | done: |
995 | exit: | ||
996 | xlog_put_bp(bp); | 1026 | xlog_put_bp(bp); |
997 | 1027 | ||
998 | if (error) | 1028 | if (error) |
@@ -1152,16 +1182,22 @@ xlog_write_log_records( | |||
1152 | xfs_caddr_t offset; | 1182 | xfs_caddr_t offset; |
1153 | xfs_buf_t *bp; | 1183 | xfs_buf_t *bp; |
1154 | int balign, ealign; | 1184 | int balign, ealign; |
1155 | int sectbb = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, 1); | 1185 | int sectbb = log->l_sectBBsize; |
1156 | int end_block = start_block + blocks; | 1186 | int end_block = start_block + blocks; |
1157 | int bufblks; | 1187 | int bufblks; |
1158 | int error = 0; | 1188 | int error = 0; |
1159 | int i, j = 0; | 1189 | int i, j = 0; |
1160 | 1190 | ||
1191 | /* | ||
1192 | * Greedily allocate a buffer big enough to handle the full | ||
1193 | * range of basic blocks to be written. If that fails, try | ||
1194 | * a smaller size. We need to be able to write at least a | ||
1195 | * log sector, or we're out of luck. | ||
1196 | */ | ||
1161 | bufblks = 1 << ffs(blocks); | 1197 | bufblks = 1 << ffs(blocks); |
1162 | while (!(bp = xlog_get_bp(log, bufblks))) { | 1198 | while (!(bp = xlog_get_bp(log, bufblks))) { |
1163 | bufblks >>= 1; | 1199 | bufblks >>= 1; |
1164 | if (bufblks <= log->l_sectbb_log) | 1200 | if (bufblks < sectbb) |
1165 | return ENOMEM; | 1201 | return ENOMEM; |
1166 | } | 1202 | } |
1167 | 1203 | ||
@@ -1169,7 +1205,7 @@ xlog_write_log_records( | |||
1169 | * the buffer in the starting sector not covered by the first | 1205 | * the buffer in the starting sector not covered by the first |
1170 | * write below. | 1206 | * write below. |
1171 | */ | 1207 | */ |
1172 | balign = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, start_block); | 1208 | balign = round_down(start_block, sectbb); |
1173 | if (balign != start_block) { | 1209 | if (balign != start_block) { |
1174 | error = xlog_bread_noalign(log, start_block, 1, bp); | 1210 | error = xlog_bread_noalign(log, start_block, 1, bp); |
1175 | if (error) | 1211 | if (error) |
@@ -1188,7 +1224,7 @@ xlog_write_log_records( | |||
1188 | * the buffer in the final sector not covered by the write. | 1224 | * the buffer in the final sector not covered by the write. |
1189 | * If this is the same sector as the above read, skip it. | 1225 | * If this is the same sector as the above read, skip it. |
1190 | */ | 1226 | */ |
1191 | ealign = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, end_block); | 1227 | ealign = round_down(end_block, sectbb); |
1192 | if (j == 0 && (start_block + endcount > ealign)) { | 1228 | if (j == 0 && (start_block + endcount > ealign)) { |
1193 | offset = XFS_BUF_PTR(bp); | 1229 | offset = XFS_BUF_PTR(bp); |
1194 | balign = BBTOB(ealign - start_block); | 1230 | balign = BBTOB(ealign - start_block); |
@@ -1408,6 +1444,7 @@ xlog_recover_add_item( | |||
1408 | 1444 | ||
1409 | STATIC int | 1445 | STATIC int |
1410 | xlog_recover_add_to_cont_trans( | 1446 | xlog_recover_add_to_cont_trans( |
1447 | struct log *log, | ||
1411 | xlog_recover_t *trans, | 1448 | xlog_recover_t *trans, |
1412 | xfs_caddr_t dp, | 1449 | xfs_caddr_t dp, |
1413 | int len) | 1450 | int len) |
@@ -1434,6 +1471,7 @@ xlog_recover_add_to_cont_trans( | |||
1434 | memcpy(&ptr[old_len], dp, len); /* d, s, l */ | 1471 | memcpy(&ptr[old_len], dp, len); /* d, s, l */ |
1435 | item->ri_buf[item->ri_cnt-1].i_len += len; | 1472 | item->ri_buf[item->ri_cnt-1].i_len += len; |
1436 | item->ri_buf[item->ri_cnt-1].i_addr = ptr; | 1473 | item->ri_buf[item->ri_cnt-1].i_addr = ptr; |
1474 | trace_xfs_log_recover_item_add_cont(log, trans, item, 0); | ||
1437 | return 0; | 1475 | return 0; |
1438 | } | 1476 | } |
1439 | 1477 | ||
@@ -1452,6 +1490,7 @@ xlog_recover_add_to_cont_trans( | |||
1452 | */ | 1490 | */ |
1453 | STATIC int | 1491 | STATIC int |
1454 | xlog_recover_add_to_trans( | 1492 | xlog_recover_add_to_trans( |
1493 | struct log *log, | ||
1455 | xlog_recover_t *trans, | 1494 | xlog_recover_t *trans, |
1456 | xfs_caddr_t dp, | 1495 | xfs_caddr_t dp, |
1457 | int len) | 1496 | int len) |
@@ -1510,6 +1549,7 @@ xlog_recover_add_to_trans( | |||
1510 | item->ri_buf[item->ri_cnt].i_addr = ptr; | 1549 | item->ri_buf[item->ri_cnt].i_addr = ptr; |
1511 | item->ri_buf[item->ri_cnt].i_len = len; | 1550 | item->ri_buf[item->ri_cnt].i_len = len; |
1512 | item->ri_cnt++; | 1551 | item->ri_cnt++; |
1552 | trace_xfs_log_recover_item_add(log, trans, item, 0); | ||
1513 | return 0; | 1553 | return 0; |
1514 | } | 1554 | } |
1515 | 1555 | ||
@@ -1521,7 +1561,9 @@ xlog_recover_add_to_trans( | |||
1521 | */ | 1561 | */ |
1522 | STATIC int | 1562 | STATIC int |
1523 | xlog_recover_reorder_trans( | 1563 | xlog_recover_reorder_trans( |
1524 | xlog_recover_t *trans) | 1564 | struct log *log, |
1565 | xlog_recover_t *trans, | ||
1566 | int pass) | ||
1525 | { | 1567 | { |
1526 | xlog_recover_item_t *item, *n; | 1568 | xlog_recover_item_t *item, *n; |
1527 | LIST_HEAD(sort_list); | 1569 | LIST_HEAD(sort_list); |
@@ -1535,6 +1577,8 @@ xlog_recover_reorder_trans( | |||
1535 | switch (ITEM_TYPE(item)) { | 1577 | switch (ITEM_TYPE(item)) { |
1536 | case XFS_LI_BUF: | 1578 | case XFS_LI_BUF: |
1537 | if (!(buf_f->blf_flags & XFS_BLI_CANCEL)) { | 1579 | if (!(buf_f->blf_flags & XFS_BLI_CANCEL)) { |
1580 | trace_xfs_log_recover_item_reorder_head(log, | ||
1581 | trans, item, pass); | ||
1538 | list_move(&item->ri_list, &trans->r_itemq); | 1582 | list_move(&item->ri_list, &trans->r_itemq); |
1539 | break; | 1583 | break; |
1540 | } | 1584 | } |
@@ -1543,6 +1587,8 @@ xlog_recover_reorder_trans( | |||
1543 | case XFS_LI_QUOTAOFF: | 1587 | case XFS_LI_QUOTAOFF: |
1544 | case XFS_LI_EFD: | 1588 | case XFS_LI_EFD: |
1545 | case XFS_LI_EFI: | 1589 | case XFS_LI_EFI: |
1590 | trace_xfs_log_recover_item_reorder_tail(log, | ||
1591 | trans, item, pass); | ||
1546 | list_move_tail(&item->ri_list, &trans->r_itemq); | 1592 | list_move_tail(&item->ri_list, &trans->r_itemq); |
1547 | break; | 1593 | break; |
1548 | default: | 1594 | default: |
@@ -1592,8 +1638,10 @@ xlog_recover_do_buffer_pass1( | |||
1592 | /* | 1638 | /* |
1593 | * If this isn't a cancel buffer item, then just return. | 1639 | * If this isn't a cancel buffer item, then just return. |
1594 | */ | 1640 | */ |
1595 | if (!(flags & XFS_BLI_CANCEL)) | 1641 | if (!(flags & XFS_BLI_CANCEL)) { |
1642 | trace_xfs_log_recover_buf_not_cancel(log, buf_f); | ||
1596 | return; | 1643 | return; |
1644 | } | ||
1597 | 1645 | ||
1598 | /* | 1646 | /* |
1599 | * Insert an xfs_buf_cancel record into the hash table of | 1647 | * Insert an xfs_buf_cancel record into the hash table of |
@@ -1627,6 +1675,7 @@ xlog_recover_do_buffer_pass1( | |||
1627 | while (nextp != NULL) { | 1675 | while (nextp != NULL) { |
1628 | if (nextp->bc_blkno == blkno && nextp->bc_len == len) { | 1676 | if (nextp->bc_blkno == blkno && nextp->bc_len == len) { |
1629 | nextp->bc_refcount++; | 1677 | nextp->bc_refcount++; |
1678 | trace_xfs_log_recover_buf_cancel_ref_inc(log, buf_f); | ||
1630 | return; | 1679 | return; |
1631 | } | 1680 | } |
1632 | prevp = nextp; | 1681 | prevp = nextp; |
@@ -1640,6 +1689,7 @@ xlog_recover_do_buffer_pass1( | |||
1640 | bcp->bc_refcount = 1; | 1689 | bcp->bc_refcount = 1; |
1641 | bcp->bc_next = NULL; | 1690 | bcp->bc_next = NULL; |
1642 | prevp->bc_next = bcp; | 1691 | prevp->bc_next = bcp; |
1692 | trace_xfs_log_recover_buf_cancel_add(log, buf_f); | ||
1643 | } | 1693 | } |
1644 | 1694 | ||
1645 | /* | 1695 | /* |
@@ -1779,6 +1829,8 @@ xlog_recover_do_inode_buffer( | |||
1779 | unsigned int *data_map = NULL; | 1829 | unsigned int *data_map = NULL; |
1780 | unsigned int map_size = 0; | 1830 | unsigned int map_size = 0; |
1781 | 1831 | ||
1832 | trace_xfs_log_recover_buf_inode_buf(mp->m_log, buf_f); | ||
1833 | |||
1782 | switch (buf_f->blf_type) { | 1834 | switch (buf_f->blf_type) { |
1783 | case XFS_LI_BUF: | 1835 | case XFS_LI_BUF: |
1784 | data_map = buf_f->blf_data_map; | 1836 | data_map = buf_f->blf_data_map; |
@@ -1874,6 +1926,7 @@ xlog_recover_do_inode_buffer( | |||
1874 | /*ARGSUSED*/ | 1926 | /*ARGSUSED*/ |
1875 | STATIC void | 1927 | STATIC void |
1876 | xlog_recover_do_reg_buffer( | 1928 | xlog_recover_do_reg_buffer( |
1929 | struct xfs_mount *mp, | ||
1877 | xlog_recover_item_t *item, | 1930 | xlog_recover_item_t *item, |
1878 | xfs_buf_t *bp, | 1931 | xfs_buf_t *bp, |
1879 | xfs_buf_log_format_t *buf_f) | 1932 | xfs_buf_log_format_t *buf_f) |
@@ -1885,6 +1938,8 @@ xlog_recover_do_reg_buffer( | |||
1885 | unsigned int map_size = 0; | 1938 | unsigned int map_size = 0; |
1886 | int error; | 1939 | int error; |
1887 | 1940 | ||
1941 | trace_xfs_log_recover_buf_reg_buf(mp->m_log, buf_f); | ||
1942 | |||
1888 | switch (buf_f->blf_type) { | 1943 | switch (buf_f->blf_type) { |
1889 | case XFS_LI_BUF: | 1944 | case XFS_LI_BUF: |
1890 | data_map = buf_f->blf_data_map; | 1945 | data_map = buf_f->blf_data_map; |
@@ -2083,6 +2138,8 @@ xlog_recover_do_dquot_buffer( | |||
2083 | { | 2138 | { |
2084 | uint type; | 2139 | uint type; |
2085 | 2140 | ||
2141 | trace_xfs_log_recover_buf_dquot_buf(log, buf_f); | ||
2142 | |||
2086 | /* | 2143 | /* |
2087 | * Filesystems are required to send in quota flags at mount time. | 2144 | * Filesystems are required to send in quota flags at mount time. |
2088 | */ | 2145 | */ |
@@ -2103,7 +2160,7 @@ xlog_recover_do_dquot_buffer( | |||
2103 | if (log->l_quotaoffs_flag & type) | 2160 | if (log->l_quotaoffs_flag & type) |
2104 | return; | 2161 | return; |
2105 | 2162 | ||
2106 | xlog_recover_do_reg_buffer(item, bp, buf_f); | 2163 | xlog_recover_do_reg_buffer(mp, item, bp, buf_f); |
2107 | } | 2164 | } |
2108 | 2165 | ||
2109 | /* | 2166 | /* |
@@ -2164,9 +2221,11 @@ xlog_recover_do_buffer_trans( | |||
2164 | */ | 2221 | */ |
2165 | cancel = xlog_recover_do_buffer_pass2(log, buf_f); | 2222 | cancel = xlog_recover_do_buffer_pass2(log, buf_f); |
2166 | if (cancel) { | 2223 | if (cancel) { |
2224 | trace_xfs_log_recover_buf_cancel(log, buf_f); | ||
2167 | return 0; | 2225 | return 0; |
2168 | } | 2226 | } |
2169 | } | 2227 | } |
2228 | trace_xfs_log_recover_buf_recover(log, buf_f); | ||
2170 | switch (buf_f->blf_type) { | 2229 | switch (buf_f->blf_type) { |
2171 | case XFS_LI_BUF: | 2230 | case XFS_LI_BUF: |
2172 | blkno = buf_f->blf_blkno; | 2231 | blkno = buf_f->blf_blkno; |
@@ -2204,7 +2263,7 @@ xlog_recover_do_buffer_trans( | |||
2204 | (XFS_BLI_UDQUOT_BUF|XFS_BLI_PDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) { | 2263 | (XFS_BLI_UDQUOT_BUF|XFS_BLI_PDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) { |
2205 | xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f); | 2264 | xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f); |
2206 | } else { | 2265 | } else { |
2207 | xlog_recover_do_reg_buffer(item, bp, buf_f); | 2266 | xlog_recover_do_reg_buffer(mp, item, bp, buf_f); |
2208 | } | 2267 | } |
2209 | if (error) | 2268 | if (error) |
2210 | return XFS_ERROR(error); | 2269 | return XFS_ERROR(error); |
@@ -2284,8 +2343,10 @@ xlog_recover_do_inode_trans( | |||
2284 | if (xlog_check_buffer_cancelled(log, in_f->ilf_blkno, | 2343 | if (xlog_check_buffer_cancelled(log, in_f->ilf_blkno, |
2285 | in_f->ilf_len, 0)) { | 2344 | in_f->ilf_len, 0)) { |
2286 | error = 0; | 2345 | error = 0; |
2346 | trace_xfs_log_recover_inode_cancel(log, in_f); | ||
2287 | goto error; | 2347 | goto error; |
2288 | } | 2348 | } |
2349 | trace_xfs_log_recover_inode_recover(log, in_f); | ||
2289 | 2350 | ||
2290 | bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len, | 2351 | bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len, |
2291 | XBF_LOCK); | 2352 | XBF_LOCK); |
@@ -2337,6 +2398,7 @@ xlog_recover_do_inode_trans( | |||
2337 | /* do nothing */ | 2398 | /* do nothing */ |
2338 | } else { | 2399 | } else { |
2339 | xfs_buf_relse(bp); | 2400 | xfs_buf_relse(bp); |
2401 | trace_xfs_log_recover_inode_skip(log, in_f); | ||
2340 | error = 0; | 2402 | error = 0; |
2341 | goto error; | 2403 | goto error; |
2342 | } | 2404 | } |
@@ -2758,11 +2820,12 @@ xlog_recover_do_trans( | |||
2758 | int error = 0; | 2820 | int error = 0; |
2759 | xlog_recover_item_t *item; | 2821 | xlog_recover_item_t *item; |
2760 | 2822 | ||
2761 | error = xlog_recover_reorder_trans(trans); | 2823 | error = xlog_recover_reorder_trans(log, trans, pass); |
2762 | if (error) | 2824 | if (error) |
2763 | return error; | 2825 | return error; |
2764 | 2826 | ||
2765 | list_for_each_entry(item, &trans->r_itemq, ri_list) { | 2827 | list_for_each_entry(item, &trans->r_itemq, ri_list) { |
2828 | trace_xfs_log_recover_item_recover(log, trans, item, pass); | ||
2766 | switch (ITEM_TYPE(item)) { | 2829 | switch (ITEM_TYPE(item)) { |
2767 | case XFS_LI_BUF: | 2830 | case XFS_LI_BUF: |
2768 | error = xlog_recover_do_buffer_trans(log, item, pass); | 2831 | error = xlog_recover_do_buffer_trans(log, item, pass); |
@@ -2919,8 +2982,9 @@ xlog_recover_process_data( | |||
2919 | error = xlog_recover_unmount_trans(trans); | 2982 | error = xlog_recover_unmount_trans(trans); |
2920 | break; | 2983 | break; |
2921 | case XLOG_WAS_CONT_TRANS: | 2984 | case XLOG_WAS_CONT_TRANS: |
2922 | error = xlog_recover_add_to_cont_trans(trans, | 2985 | error = xlog_recover_add_to_cont_trans(log, |
2923 | dp, be32_to_cpu(ohead->oh_len)); | 2986 | trans, dp, |
2987 | be32_to_cpu(ohead->oh_len)); | ||
2924 | break; | 2988 | break; |
2925 | case XLOG_START_TRANS: | 2989 | case XLOG_START_TRANS: |
2926 | xlog_warn( | 2990 | xlog_warn( |
@@ -2930,7 +2994,7 @@ xlog_recover_process_data( | |||
2930 | break; | 2994 | break; |
2931 | case 0: | 2995 | case 0: |
2932 | case XLOG_CONTINUE_TRANS: | 2996 | case XLOG_CONTINUE_TRANS: |
2933 | error = xlog_recover_add_to_trans(trans, | 2997 | error = xlog_recover_add_to_trans(log, trans, |
2934 | dp, be32_to_cpu(ohead->oh_len)); | 2998 | dp, be32_to_cpu(ohead->oh_len)); |
2935 | break; | 2999 | break; |
2936 | default: | 3000 | default: |
@@ -3331,42 +3395,6 @@ xlog_pack_data( | |||
3331 | } | 3395 | } |
3332 | } | 3396 | } |
3333 | 3397 | ||
3334 | #if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) | ||
3335 | STATIC void | ||
3336 | xlog_unpack_data_checksum( | ||
3337 | xlog_rec_header_t *rhead, | ||
3338 | xfs_caddr_t dp, | ||
3339 | xlog_t *log) | ||
3340 | { | ||
3341 | __be32 *up = (__be32 *)dp; | ||
3342 | uint chksum = 0; | ||
3343 | int i; | ||
3344 | |||
3345 | /* divide length by 4 to get # words */ | ||
3346 | for (i=0; i < be32_to_cpu(rhead->h_len) >> 2; i++) { | ||
3347 | chksum ^= be32_to_cpu(*up); | ||
3348 | up++; | ||
3349 | } | ||
3350 | if (chksum != be32_to_cpu(rhead->h_chksum)) { | ||
3351 | if (rhead->h_chksum || | ||
3352 | ((log->l_flags & XLOG_CHKSUM_MISMATCH) == 0)) { | ||
3353 | cmn_err(CE_DEBUG, | ||
3354 | "XFS: LogR chksum mismatch: was (0x%x) is (0x%x)\n", | ||
3355 | be32_to_cpu(rhead->h_chksum), chksum); | ||
3356 | cmn_err(CE_DEBUG, | ||
3357 | "XFS: Disregard message if filesystem was created with non-DEBUG kernel"); | ||
3358 | if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) { | ||
3359 | cmn_err(CE_DEBUG, | ||
3360 | "XFS: LogR this is a LogV2 filesystem\n"); | ||
3361 | } | ||
3362 | log->l_flags |= XLOG_CHKSUM_MISMATCH; | ||
3363 | } | ||
3364 | } | ||
3365 | } | ||
3366 | #else | ||
3367 | #define xlog_unpack_data_checksum(rhead, dp, log) | ||
3368 | #endif | ||
3369 | |||
3370 | STATIC void | 3398 | STATIC void |
3371 | xlog_unpack_data( | 3399 | xlog_unpack_data( |
3372 | xlog_rec_header_t *rhead, | 3400 | xlog_rec_header_t *rhead, |
@@ -3390,8 +3418,6 @@ xlog_unpack_data( | |||
3390 | dp += BBSIZE; | 3418 | dp += BBSIZE; |
3391 | } | 3419 | } |
3392 | } | 3420 | } |
3393 | |||
3394 | xlog_unpack_data_checksum(rhead, dp, log); | ||
3395 | } | 3421 | } |
3396 | 3422 | ||
3397 | STATIC int | 3423 | STATIC int |
@@ -3490,7 +3516,7 @@ xlog_do_recovery_pass( | |||
3490 | hblks = 1; | 3516 | hblks = 1; |
3491 | } | 3517 | } |
3492 | } else { | 3518 | } else { |
3493 | ASSERT(log->l_sectbb_log == 0); | 3519 | ASSERT(log->l_sectBBsize == 1); |
3494 | hblks = 1; | 3520 | hblks = 1; |
3495 | hbp = xlog_get_bp(log, 1); | 3521 | hbp = xlog_get_bp(log, 1); |
3496 | h_size = XLOG_BIG_RECORD_BSIZE; | 3522 | h_size = XLOG_BIG_RECORD_BSIZE; |
@@ -3946,10 +3972,6 @@ xlog_recover_check_summary( | |||
3946 | xfs_agf_t *agfp; | 3972 | xfs_agf_t *agfp; |
3947 | xfs_buf_t *agfbp; | 3973 | xfs_buf_t *agfbp; |
3948 | xfs_buf_t *agibp; | 3974 | xfs_buf_t *agibp; |
3949 | xfs_buf_t *sbbp; | ||
3950 | #ifdef XFS_LOUD_RECOVERY | ||
3951 | xfs_sb_t *sbp; | ||
3952 | #endif | ||
3953 | xfs_agnumber_t agno; | 3975 | xfs_agnumber_t agno; |
3954 | __uint64_t freeblks; | 3976 | __uint64_t freeblks; |
3955 | __uint64_t itotal; | 3977 | __uint64_t itotal; |
@@ -3984,30 +4006,5 @@ xlog_recover_check_summary( | |||
3984 | xfs_buf_relse(agibp); | 4006 | xfs_buf_relse(agibp); |
3985 | } | 4007 | } |
3986 | } | 4008 | } |
3987 | |||
3988 | sbbp = xfs_getsb(mp, 0); | ||
3989 | #ifdef XFS_LOUD_RECOVERY | ||
3990 | sbp = &mp->m_sb; | ||
3991 | xfs_sb_from_disk(sbp, XFS_BUF_TO_SBP(sbbp)); | ||
3992 | cmn_err(CE_NOTE, | ||
3993 | "xlog_recover_check_summary: sb_icount %Lu itotal %Lu", | ||
3994 | sbp->sb_icount, itotal); | ||
3995 | cmn_err(CE_NOTE, | ||
3996 | "xlog_recover_check_summary: sb_ifree %Lu itotal %Lu", | ||
3997 | sbp->sb_ifree, ifree); | ||
3998 | cmn_err(CE_NOTE, | ||
3999 | "xlog_recover_check_summary: sb_fdblocks %Lu freeblks %Lu", | ||
4000 | sbp->sb_fdblocks, freeblks); | ||
4001 | #if 0 | ||
4002 | /* | ||
4003 | * This is turned off until I account for the allocation | ||
4004 | * btree blocks which live in free space. | ||
4005 | */ | ||
4006 | ASSERT(sbp->sb_icount == itotal); | ||
4007 | ASSERT(sbp->sb_ifree == ifree); | ||
4008 | ASSERT(sbp->sb_fdblocks == freeblks); | ||
4009 | #endif | ||
4010 | #endif | ||
4011 | xfs_buf_relse(sbbp); | ||
4012 | } | 4009 | } |
4013 | #endif /* DEBUG */ | 4010 | #endif /* DEBUG */ |