Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong <darrick.wong@oracle.com> */ #include "xfs.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_btree.h" #include "scrub/bitmap.h" /* * Set a range of this bitmap. Caller must ensure the range is not set. * * This is the logical equivalent of bitmap |= mask(start, len). */ int xfs_bitmap_set( struct xfs_bitmap *bitmap, uint64_t start, uint64_t len) { struct xfs_bitmap_range *bmr; bmr = kmem_alloc(sizeof(struct xfs_bitmap_range), KM_MAYFAIL); if (!bmr) return -ENOMEM; INIT_LIST_HEAD(&bmr->list); bmr->start = start; bmr->len = len; list_add_tail(&bmr->list, &bitmap->list); return 0; } /* Free everything related to this bitmap. */ void xfs_bitmap_destroy( struct xfs_bitmap *bitmap) { struct xfs_bitmap_range *bmr; struct xfs_bitmap_range *n; for_each_xfs_bitmap_extent(bmr, n, bitmap) { list_del(&bmr->list); kmem_free(bmr); } } /* Set up a per-AG block bitmap. */ void xfs_bitmap_init( struct xfs_bitmap *bitmap) { INIT_LIST_HEAD(&bitmap->list); } /* Compare two btree extents. */ static int xfs_bitmap_range_cmp( void *priv, struct list_head *a, struct list_head *b) { struct xfs_bitmap_range *ap; struct xfs_bitmap_range *bp; ap = container_of(a, struct xfs_bitmap_range, list); bp = container_of(b, struct xfs_bitmap_range, list); if (ap->start > bp->start) return 1; if (ap->start < bp->start) return -1; return 0; } /* * Remove all the blocks mentioned in @sub from the extents in @bitmap. * * The intent is that callers will iterate the rmapbt for all of its records * for a given owner to generate @bitmap; and iterate all the blocks of the * metadata structures that are not being rebuilt and have the same rmapbt * owner to generate @sub. This routine subtracts all the extents * mentioned in sub from all the extents linked in @bitmap, which leaves * @bitmap as the list of blocks that are not accounted for, which we assume * are the dead blocks of the old metadata structure. The blocks mentioned in * @bitmap can be reaped. * * This is the logical equivalent of bitmap &= ~sub. */ #define LEFT_ALIGNED (1 << 0) #define RIGHT_ALIGNED (1 << 1) int xfs_bitmap_disunion( struct xfs_bitmap *bitmap, struct xfs_bitmap *sub) { struct list_head *lp; struct xfs_bitmap_range *br; struct xfs_bitmap_range *new_br; struct xfs_bitmap_range *sub_br; uint64_t sub_start; uint64_t sub_len; int state; int error = 0; if (list_empty(&bitmap->list) || list_empty(&sub->list)) return 0; ASSERT(!list_empty(&sub->list)); list_sort(NULL, &bitmap->list, xfs_bitmap_range_cmp); list_sort(NULL, &sub->list, xfs_bitmap_range_cmp); /* * Now that we've sorted both lists, we iterate bitmap once, rolling * forward through sub and/or bitmap as necessary until we find an * overlap or reach the end of either list. We do not reset lp to the * head of bitmap nor do we reset sub_br to the head of sub. The * list traversal is similar to merge sort, but we're deleting * instead. In this manner we avoid O(n^2) operations. */ sub_br = list_first_entry(&sub->list, struct xfs_bitmap_range, list); lp = bitmap->list.next; while (lp != &bitmap->list) { br = list_entry(lp, struct xfs_bitmap_range, list); /* * Advance sub_br and/or br until we find a pair that * intersect or we run out of extents. */ while (sub_br->start + sub_br->len <= br->start) { if (list_is_last(&sub_br->list, &sub->list)) goto out; sub_br = list_next_entry(sub_br, list); } if (sub_br->start >= br->start + br->len) { lp = lp->next; continue; } /* trim sub_br to fit the extent we have */ sub_start = sub_br->start; sub_len = sub_br->len; if (sub_br->start < br->start) { sub_len -= br->start - sub_br->start; sub_start = br->start; } if (sub_len > br->len) sub_len = br->len; state = 0; if (sub_start == br->start) state |= LEFT_ALIGNED; if (sub_start + sub_len == br->start + br->len) state |= RIGHT_ALIGNED; switch (state) { case LEFT_ALIGNED: /* Coincides with only the left. */ br->start += sub_len; br->len -= sub_len; break; case RIGHT_ALIGNED: /* Coincides with only the right. */ br->len -= sub_len; lp = lp->next; break; case LEFT_ALIGNED | RIGHT_ALIGNED: /* Total overlap, just delete ex. */ lp = lp->next; list_del(&br->list); kmem_free(br); break; case 0: /* * Deleting from the middle: add the new right extent * and then shrink the left extent. */ new_br = kmem_alloc(sizeof(struct xfs_bitmap_range), KM_MAYFAIL); if (!new_br) { error = -ENOMEM; goto out; } INIT_LIST_HEAD(&new_br->list); new_br->start = sub_start + sub_len; new_br->len = br->start + br->len - new_br->start; list_add(&new_br->list, &br->list); br->len = sub_start - br->start; lp = lp->next; break; default: ASSERT(0); break; } } out: return error; } #undef LEFT_ALIGNED #undef RIGHT_ALIGNED /* * Record all btree blocks seen while iterating all records of a btree. * * We know that the btree query_all function starts at the left edge and walks * towards the right edge of the tree. Therefore, we know that we can walk up * the btree cursor towards the root; if the pointer for a given level points * to the first record/key in that block, we haven't seen this block before; * and therefore we need to remember that we saw this block in the btree. * * So if our btree is: * * 4 * / | \ * 1 2 3 * * Pretend for this example that each leaf block has 100 btree records. For * the first btree record, we'll observe that bc_ptrs[0] == 1, so we record * that we saw block 1. Then we observe that bc_ptrs[1] == 1, so we record * block 4. The list is [1, 4]. * * For the second btree record, we see that bc_ptrs[0] == 2, so we exit the * loop. The list remains [1, 4]. * * For the 101st btree record, we've moved onto leaf block 2. Now * bc_ptrs[0] == 1 again, so we record that we saw block 2. We see that * bc_ptrs[1] == 2, so we exit the loop. The list is now [1, 4, 2]. * * For the 102nd record, bc_ptrs[0] == 2, so we continue. * * For the 201st record, we've moved on to leaf block 3. bc_ptrs[0] == 1, so * we add 3 to the list. Now it is [1, 4, 2, 3]. * * For the 300th record we just exit, with the list being [1, 4, 2, 3]. */ /* * Record all the buffers pointed to by the btree cursor. Callers already * engaged in a btree walk should call this function to capture the list of * blocks going from the leaf towards the root. */ int xfs_bitmap_set_btcur_path( struct xfs_bitmap *bitmap, struct xfs_btree_cur *cur) { struct xfs_buf *bp; xfs_fsblock_t fsb; int i; int error; for (i = 0; i < cur->bc_nlevels && cur->bc_ptrs[i] == 1; i++) { xfs_btree_get_block(cur, i, &bp); if (!bp) continue; fsb = XFS_DADDR_TO_FSB(cur->bc_mp, bp->b_bn); error = xfs_bitmap_set(bitmap, fsb, 1); if (error) return error; } return 0; } /* Collect a btree's block in the bitmap. */ STATIC int xfs_bitmap_collect_btblock( struct xfs_btree_cur *cur, int level, void *priv) { struct xfs_bitmap *bitmap = priv; struct xfs_buf *bp; xfs_fsblock_t fsbno; xfs_btree_get_block(cur, level, &bp); if (!bp) return 0; fsbno = XFS_DADDR_TO_FSB(cur->bc_mp, bp->b_bn); return xfs_bitmap_set(bitmap, fsbno, 1); } /* Walk the btree and mark the bitmap wherever a btree block is found. */ int xfs_bitmap_set_btblocks( struct xfs_bitmap *bitmap, struct xfs_btree_cur *cur) { return xfs_btree_visit_blocks(cur, xfs_bitmap_collect_btblock, bitmap); } |