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

xfs: move the repair extent list into its own file

Move the xrep_extent_list code into a separate file. Logically, this
data structure is really just a clumsy bitmap, and in the next patch
we'll make this more obvious. No functional changes.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>

+248 -219
+1
fs/xfs/Makefile
··· 158 158 ifeq ($(CONFIG_XFS_ONLINE_REPAIR),y) 159 159 xfs-y += $(addprefix scrub/, \ 160 160 agheader_repair.o \ 161 + bitmap.o \ 161 162 repair.o \ 162 163 ) 163 164 endif
+208
fs/xfs/scrub/bitmap.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Copyright (C) 2018 Oracle. All Rights Reserved. 4 + * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 + */ 6 + #include "xfs.h" 7 + #include "xfs_fs.h" 8 + #include "xfs_shared.h" 9 + #include "xfs_format.h" 10 + #include "xfs_trans_resv.h" 11 + #include "xfs_mount.h" 12 + #include "scrub/xfs_scrub.h" 13 + #include "scrub/scrub.h" 14 + #include "scrub/common.h" 15 + #include "scrub/trace.h" 16 + #include "scrub/repair.h" 17 + #include "scrub/bitmap.h" 18 + 19 + /* Collect a dead btree extent for later disposal. */ 20 + int 21 + xrep_collect_btree_extent( 22 + struct xfs_scrub *sc, 23 + struct xrep_extent_list *exlist, 24 + xfs_fsblock_t fsbno, 25 + xfs_extlen_t len) 26 + { 27 + struct xrep_extent *rex; 28 + 29 + trace_xrep_collect_btree_extent(sc->mp, 30 + XFS_FSB_TO_AGNO(sc->mp, fsbno), 31 + XFS_FSB_TO_AGBNO(sc->mp, fsbno), len); 32 + 33 + rex = kmem_alloc(sizeof(struct xrep_extent), KM_MAYFAIL); 34 + if (!rex) 35 + return -ENOMEM; 36 + 37 + INIT_LIST_HEAD(&rex->list); 38 + rex->fsbno = fsbno; 39 + rex->len = len; 40 + list_add_tail(&rex->list, &exlist->list); 41 + 42 + return 0; 43 + } 44 + 45 + /* 46 + * An error happened during the rebuild so the transaction will be cancelled. 47 + * The fs will shut down, and the administrator has to unmount and run repair. 48 + * Therefore, free all the memory associated with the list so we can die. 49 + */ 50 + void 51 + xrep_cancel_btree_extents( 52 + struct xfs_scrub *sc, 53 + struct xrep_extent_list *exlist) 54 + { 55 + struct xrep_extent *rex; 56 + struct xrep_extent *n; 57 + 58 + for_each_xrep_extent_safe(rex, n, exlist) { 59 + list_del(&rex->list); 60 + kmem_free(rex); 61 + } 62 + } 63 + 64 + /* Compare two btree extents. */ 65 + static int 66 + xrep_btree_extent_cmp( 67 + void *priv, 68 + struct list_head *a, 69 + struct list_head *b) 70 + { 71 + struct xrep_extent *ap; 72 + struct xrep_extent *bp; 73 + 74 + ap = container_of(a, struct xrep_extent, list); 75 + bp = container_of(b, struct xrep_extent, list); 76 + 77 + if (ap->fsbno > bp->fsbno) 78 + return 1; 79 + if (ap->fsbno < bp->fsbno) 80 + return -1; 81 + return 0; 82 + } 83 + 84 + /* 85 + * Remove all the blocks mentioned in @sublist from the extents in @exlist. 86 + * 87 + * The intent is that callers will iterate the rmapbt for all of its records 88 + * for a given owner to generate @exlist; and iterate all the blocks of the 89 + * metadata structures that are not being rebuilt and have the same rmapbt 90 + * owner to generate @sublist. This routine subtracts all the extents 91 + * mentioned in sublist from all the extents linked in @exlist, which leaves 92 + * @exlist as the list of blocks that are not accounted for, which we assume 93 + * are the dead blocks of the old metadata structure. The blocks mentioned in 94 + * @exlist can be reaped. 95 + */ 96 + #define LEFT_ALIGNED (1 << 0) 97 + #define RIGHT_ALIGNED (1 << 1) 98 + int 99 + xrep_subtract_extents( 100 + struct xfs_scrub *sc, 101 + struct xrep_extent_list *exlist, 102 + struct xrep_extent_list *sublist) 103 + { 104 + struct list_head *lp; 105 + struct xrep_extent *ex; 106 + struct xrep_extent *newex; 107 + struct xrep_extent *subex; 108 + xfs_fsblock_t sub_fsb; 109 + xfs_extlen_t sub_len; 110 + int state; 111 + int error = 0; 112 + 113 + if (list_empty(&exlist->list) || list_empty(&sublist->list)) 114 + return 0; 115 + ASSERT(!list_empty(&sublist->list)); 116 + 117 + list_sort(NULL, &exlist->list, xrep_btree_extent_cmp); 118 + list_sort(NULL, &sublist->list, xrep_btree_extent_cmp); 119 + 120 + /* 121 + * Now that we've sorted both lists, we iterate exlist once, rolling 122 + * forward through sublist and/or exlist as necessary until we find an 123 + * overlap or reach the end of either list. We do not reset lp to the 124 + * head of exlist nor do we reset subex to the head of sublist. The 125 + * list traversal is similar to merge sort, but we're deleting 126 + * instead. In this manner we avoid O(n^2) operations. 127 + */ 128 + subex = list_first_entry(&sublist->list, struct xrep_extent, 129 + list); 130 + lp = exlist->list.next; 131 + while (lp != &exlist->list) { 132 + ex = list_entry(lp, struct xrep_extent, list); 133 + 134 + /* 135 + * Advance subex and/or ex until we find a pair that 136 + * intersect or we run out of extents. 137 + */ 138 + while (subex->fsbno + subex->len <= ex->fsbno) { 139 + if (list_is_last(&subex->list, &sublist->list)) 140 + goto out; 141 + subex = list_next_entry(subex, list); 142 + } 143 + if (subex->fsbno >= ex->fsbno + ex->len) { 144 + lp = lp->next; 145 + continue; 146 + } 147 + 148 + /* trim subex to fit the extent we have */ 149 + sub_fsb = subex->fsbno; 150 + sub_len = subex->len; 151 + if (subex->fsbno < ex->fsbno) { 152 + sub_len -= ex->fsbno - subex->fsbno; 153 + sub_fsb = ex->fsbno; 154 + } 155 + if (sub_len > ex->len) 156 + sub_len = ex->len; 157 + 158 + state = 0; 159 + if (sub_fsb == ex->fsbno) 160 + state |= LEFT_ALIGNED; 161 + if (sub_fsb + sub_len == ex->fsbno + ex->len) 162 + state |= RIGHT_ALIGNED; 163 + switch (state) { 164 + case LEFT_ALIGNED: 165 + /* Coincides with only the left. */ 166 + ex->fsbno += sub_len; 167 + ex->len -= sub_len; 168 + break; 169 + case RIGHT_ALIGNED: 170 + /* Coincides with only the right. */ 171 + ex->len -= sub_len; 172 + lp = lp->next; 173 + break; 174 + case LEFT_ALIGNED | RIGHT_ALIGNED: 175 + /* Total overlap, just delete ex. */ 176 + lp = lp->next; 177 + list_del(&ex->list); 178 + kmem_free(ex); 179 + break; 180 + case 0: 181 + /* 182 + * Deleting from the middle: add the new right extent 183 + * and then shrink the left extent. 184 + */ 185 + newex = kmem_alloc(sizeof(struct xrep_extent), 186 + KM_MAYFAIL); 187 + if (!newex) { 188 + error = -ENOMEM; 189 + goto out; 190 + } 191 + INIT_LIST_HEAD(&newex->list); 192 + newex->fsbno = sub_fsb + sub_len; 193 + newex->len = ex->fsbno + ex->len - newex->fsbno; 194 + list_add(&newex->list, &ex->list); 195 + ex->len = sub_fsb - ex->fsbno; 196 + lp = lp->next; 197 + break; 198 + default: 199 + ASSERT(0); 200 + break; 201 + } 202 + } 203 + 204 + out: 205 + return error; 206 + } 207 + #undef LEFT_ALIGNED 208 + #undef RIGHT_ALIGNED
+37
fs/xfs/scrub/bitmap.h
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Copyright (C) 2018 Oracle. All Rights Reserved. 4 + * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 + */ 6 + #ifndef __XFS_SCRUB_BITMAP_H__ 7 + #define __XFS_SCRUB_BITMAP_H__ 8 + 9 + struct xrep_extent { 10 + struct list_head list; 11 + xfs_fsblock_t fsbno; 12 + xfs_extlen_t len; 13 + }; 14 + 15 + struct xrep_extent_list { 16 + struct list_head list; 17 + }; 18 + 19 + static inline void 20 + xrep_init_extent_list( 21 + struct xrep_extent_list *exlist) 22 + { 23 + INIT_LIST_HEAD(&exlist->list); 24 + } 25 + 26 + #define for_each_xrep_extent_safe(rbe, n, exlist) \ 27 + list_for_each_entry_safe((rbe), (n), &(exlist)->list, list) 28 + int xrep_collect_btree_extent(struct xfs_scrub *sc, 29 + struct xrep_extent_list *btlist, xfs_fsblock_t fsbno, 30 + xfs_extlen_t len); 31 + void xrep_cancel_btree_extents(struct xfs_scrub *sc, 32 + struct xrep_extent_list *btlist); 33 + int xrep_subtract_extents(struct xfs_scrub *sc, 34 + struct xrep_extent_list *exlist, 35 + struct xrep_extent_list *sublist); 36 + 37 + #endif /* __XFS_SCRUB_BITMAP_H__ */
+1 -193
fs/xfs/scrub/repair.c
··· 34 34 #include "scrub/common.h" 35 35 #include "scrub/trace.h" 36 36 #include "scrub/repair.h" 37 + #include "scrub/bitmap.h" 37 38 38 39 /* 39 40 * Attempt to repair some metadata, if the metadata is corrupt and userspace ··· 381 380 * sublist. As with the other btrees we subtract sublist from exlist, and the 382 381 * result (since the rmapbt lives in the free space) are the blocks from the 383 382 * old rmapbt. 384 - */ 385 - 386 - /* Collect a dead btree extent for later disposal. */ 387 - int 388 - xrep_collect_btree_extent( 389 - struct xfs_scrub *sc, 390 - struct xrep_extent_list *exlist, 391 - xfs_fsblock_t fsbno, 392 - xfs_extlen_t len) 393 - { 394 - struct xrep_extent *rex; 395 - 396 - trace_xrep_collect_btree_extent(sc->mp, 397 - XFS_FSB_TO_AGNO(sc->mp, fsbno), 398 - XFS_FSB_TO_AGBNO(sc->mp, fsbno), len); 399 - 400 - rex = kmem_alloc(sizeof(struct xrep_extent), KM_MAYFAIL); 401 - if (!rex) 402 - return -ENOMEM; 403 - 404 - INIT_LIST_HEAD(&rex->list); 405 - rex->fsbno = fsbno; 406 - rex->len = len; 407 - list_add_tail(&rex->list, &exlist->list); 408 - 409 - return 0; 410 - } 411 - 412 - /* 413 - * An error happened during the rebuild so the transaction will be cancelled. 414 - * The fs will shut down, and the administrator has to unmount and run repair. 415 - * Therefore, free all the memory associated with the list so we can die. 416 - */ 417 - void 418 - xrep_cancel_btree_extents( 419 - struct xfs_scrub *sc, 420 - struct xrep_extent_list *exlist) 421 - { 422 - struct xrep_extent *rex; 423 - struct xrep_extent *n; 424 - 425 - for_each_xrep_extent_safe(rex, n, exlist) { 426 - list_del(&rex->list); 427 - kmem_free(rex); 428 - } 429 - } 430 - 431 - /* Compare two btree extents. */ 432 - static int 433 - xrep_btree_extent_cmp( 434 - void *priv, 435 - struct list_head *a, 436 - struct list_head *b) 437 - { 438 - struct xrep_extent *ap; 439 - struct xrep_extent *bp; 440 - 441 - ap = container_of(a, struct xrep_extent, list); 442 - bp = container_of(b, struct xrep_extent, list); 443 - 444 - if (ap->fsbno > bp->fsbno) 445 - return 1; 446 - if (ap->fsbno < bp->fsbno) 447 - return -1; 448 - return 0; 449 - } 450 - 451 - /* 452 - * Remove all the blocks mentioned in @sublist from the extents in @exlist. 453 383 * 454 - * The intent is that callers will iterate the rmapbt for all of its records 455 - * for a given owner to generate @exlist; and iterate all the blocks of the 456 - * metadata structures that are not being rebuilt and have the same rmapbt 457 - * owner to generate @sublist. This routine subtracts all the extents 458 - * mentioned in sublist from all the extents linked in @exlist, which leaves 459 - * @exlist as the list of blocks that are not accounted for, which we assume 460 - * are the dead blocks of the old metadata structure. The blocks mentioned in 461 - * @exlist can be reaped. 462 - */ 463 - #define LEFT_ALIGNED (1 << 0) 464 - #define RIGHT_ALIGNED (1 << 1) 465 - int 466 - xrep_subtract_extents( 467 - struct xfs_scrub *sc, 468 - struct xrep_extent_list *exlist, 469 - struct xrep_extent_list *sublist) 470 - { 471 - struct list_head *lp; 472 - struct xrep_extent *ex; 473 - struct xrep_extent *newex; 474 - struct xrep_extent *subex; 475 - xfs_fsblock_t sub_fsb; 476 - xfs_extlen_t sub_len; 477 - int state; 478 - int error = 0; 479 - 480 - if (list_empty(&exlist->list) || list_empty(&sublist->list)) 481 - return 0; 482 - ASSERT(!list_empty(&sublist->list)); 483 - 484 - list_sort(NULL, &exlist->list, xrep_btree_extent_cmp); 485 - list_sort(NULL, &sublist->list, xrep_btree_extent_cmp); 486 - 487 - /* 488 - * Now that we've sorted both lists, we iterate exlist once, rolling 489 - * forward through sublist and/or exlist as necessary until we find an 490 - * overlap or reach the end of either list. We do not reset lp to the 491 - * head of exlist nor do we reset subex to the head of sublist. The 492 - * list traversal is similar to merge sort, but we're deleting 493 - * instead. In this manner we avoid O(n^2) operations. 494 - */ 495 - subex = list_first_entry(&sublist->list, struct xrep_extent, 496 - list); 497 - lp = exlist->list.next; 498 - while (lp != &exlist->list) { 499 - ex = list_entry(lp, struct xrep_extent, list); 500 - 501 - /* 502 - * Advance subex and/or ex until we find a pair that 503 - * intersect or we run out of extents. 504 - */ 505 - while (subex->fsbno + subex->len <= ex->fsbno) { 506 - if (list_is_last(&subex->list, &sublist->list)) 507 - goto out; 508 - subex = list_next_entry(subex, list); 509 - } 510 - if (subex->fsbno >= ex->fsbno + ex->len) { 511 - lp = lp->next; 512 - continue; 513 - } 514 - 515 - /* trim subex to fit the extent we have */ 516 - sub_fsb = subex->fsbno; 517 - sub_len = subex->len; 518 - if (subex->fsbno < ex->fsbno) { 519 - sub_len -= ex->fsbno - subex->fsbno; 520 - sub_fsb = ex->fsbno; 521 - } 522 - if (sub_len > ex->len) 523 - sub_len = ex->len; 524 - 525 - state = 0; 526 - if (sub_fsb == ex->fsbno) 527 - state |= LEFT_ALIGNED; 528 - if (sub_fsb + sub_len == ex->fsbno + ex->len) 529 - state |= RIGHT_ALIGNED; 530 - switch (state) { 531 - case LEFT_ALIGNED: 532 - /* Coincides with only the left. */ 533 - ex->fsbno += sub_len; 534 - ex->len -= sub_len; 535 - break; 536 - case RIGHT_ALIGNED: 537 - /* Coincides with only the right. */ 538 - ex->len -= sub_len; 539 - lp = lp->next; 540 - break; 541 - case LEFT_ALIGNED | RIGHT_ALIGNED: 542 - /* Total overlap, just delete ex. */ 543 - lp = lp->next; 544 - list_del(&ex->list); 545 - kmem_free(ex); 546 - break; 547 - case 0: 548 - /* 549 - * Deleting from the middle: add the new right extent 550 - * and then shrink the left extent. 551 - */ 552 - newex = kmem_alloc(sizeof(struct xrep_extent), 553 - KM_MAYFAIL); 554 - if (!newex) { 555 - error = -ENOMEM; 556 - goto out; 557 - } 558 - INIT_LIST_HEAD(&newex->list); 559 - newex->fsbno = sub_fsb + sub_len; 560 - newex->len = ex->fsbno + ex->len - newex->fsbno; 561 - list_add(&newex->list, &ex->list); 562 - ex->len = sub_fsb - ex->fsbno; 563 - lp = lp->next; 564 - break; 565 - default: 566 - ASSERT(0); 567 - break; 568 - } 569 - } 570 - 571 - out: 572 - return error; 573 - } 574 - #undef LEFT_ALIGNED 575 - #undef RIGHT_ALIGNED 576 - 577 - /* 578 384 * Disposal of Blocks from Old per-AG Btrees 579 385 * 580 386 * Now that we've constructed a new btree to replace the damaged one, we want
+1 -26
fs/xfs/scrub/repair.h
··· 27 27 struct xfs_buf **bpp, xfs_btnum_t btnum, 28 28 const struct xfs_buf_ops *ops); 29 29 30 - struct xrep_extent { 31 - struct list_head list; 32 - xfs_fsblock_t fsbno; 33 - xfs_extlen_t len; 34 - }; 30 + struct xrep_extent_list; 35 31 36 - struct xrep_extent_list { 37 - struct list_head list; 38 - }; 39 - 40 - static inline void 41 - xrep_init_extent_list( 42 - struct xrep_extent_list *exlist) 43 - { 44 - INIT_LIST_HEAD(&exlist->list); 45 - } 46 - 47 - #define for_each_xrep_extent_safe(rbe, n, exlist) \ 48 - list_for_each_entry_safe((rbe), (n), &(exlist)->list, list) 49 - int xrep_collect_btree_extent(struct xfs_scrub *sc, 50 - struct xrep_extent_list *btlist, xfs_fsblock_t fsbno, 51 - xfs_extlen_t len); 52 - void xrep_cancel_btree_extents(struct xfs_scrub *sc, 53 - struct xrep_extent_list *btlist); 54 - int xrep_subtract_extents(struct xfs_scrub *sc, 55 - struct xrep_extent_list *exlist, 56 - struct xrep_extent_list *sublist); 57 32 int xrep_fix_freelist(struct xfs_scrub *sc, bool can_shrink); 58 33 int xrep_invalidate_blocks(struct xfs_scrub *sc, 59 34 struct xrep_extent_list *btlist);