]>
Commit | Line | Data |
---|---|---|
959ef981 | 1 | // SPDX-License-Identifier: GPL-2.0 |
2bd0ea18 | 2 | /* |
da23017d NS |
3 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. |
4 | * All Rights Reserved. | |
2bd0ea18 NS |
5 | */ |
6 | ||
6b803e5a | 7 | #include "libxfs.h" |
c94d40ce | 8 | #include "libfrog/bitmap.h" |
2bd0ea18 NS |
9 | #include "avl.h" |
10 | #include "globals.h" | |
11 | #include "agheader.h" | |
12 | #include "incore.h" | |
13 | #include "protos.h" | |
14 | #include "err_protos.h" | |
15 | #include "dinode.h" | |
16 | #include "rt.h" | |
17 | #include "versions.h" | |
3b6ac903 | 18 | #include "threads.h" |
06fbdda9 | 19 | #include "progress.h" |
934b5548 DW |
20 | #include "slab.h" |
21 | #include "rmap.h" | |
7e5ec4e4 DW |
22 | #include "bulkload.h" |
23 | #include "agbtree.h" | |
2bd0ea18 | 24 | |
14f8b681 DW |
25 | static uint64_t *sb_icount_ag; /* allocated inodes per ag */ |
26 | static uint64_t *sb_ifree_ag; /* free inodes per ag */ | |
27 | static uint64_t *sb_fdblocks_ag; /* free data blocks per ag */ | |
2bd0ea18 | 28 | |
8b8a6b02 | 29 | static int |
7e5ec4e4 DW |
30 | mk_incore_fstree( |
31 | struct xfs_mount *mp, | |
32 | xfs_agnumber_t agno, | |
33 | unsigned int *num_freeblocks) | |
2bd0ea18 NS |
34 | { |
35 | int in_extent; | |
36 | int num_extents; | |
37 | xfs_agblock_t extent_start; | |
38 | xfs_extlen_t extent_len; | |
39 | xfs_agblock_t agbno; | |
40 | xfs_agblock_t ag_end; | |
41 | uint free_blocks; | |
8961bfde BN |
42 | xfs_extlen_t blen; |
43 | int bstate; | |
2bd0ea18 | 44 | |
7e5ec4e4 DW |
45 | *num_freeblocks = 0; |
46 | ||
2bd0ea18 NS |
47 | /* |
48 | * scan the bitmap for the ag looking for continuous | |
49 | * extents of free blocks. At this point, we know | |
50 | * that blocks in the bitmap are either set to an | |
51 | * "in use" state or set to unknown (0) since the | |
dab9b8d6 | 52 | * bmaps were zero'ed in phase 4 and only blocks |
2bd0ea18 NS |
53 | * being used by inodes, inode bmaps, ag headers, |
54 | * and the files themselves were put into the bitmap. | |
55 | * | |
56 | */ | |
57 | ASSERT(agno < mp->m_sb.sb_agcount); | |
58 | ||
59 | extent_start = extent_len = 0; | |
60 | in_extent = 0; | |
61 | num_extents = free_blocks = 0; | |
62 | ||
63 | if (agno < mp->m_sb.sb_agcount - 1) | |
64 | ag_end = mp->m_sb.sb_agblocks; | |
65 | else | |
66 | ag_end = mp->m_sb.sb_dblocks - | |
5a35bf2c | 67 | (xfs_rfsblock_t)mp->m_sb.sb_agblocks * |
003e8e41 | 68 | (mp->m_sb.sb_agcount - 1); |
2bd0ea18 NS |
69 | |
70 | /* | |
71 | * ok, now find the number of extents, keep track of the | |
72 | * largest extent. | |
73 | */ | |
8961bfde BN |
74 | for (agbno = 0; agbno < ag_end; agbno += blen) { |
75 | bstate = get_bmap_ext(agno, agbno, ag_end, &blen); | |
76 | if (bstate < XR_E_INUSE) { | |
77 | free_blocks += blen; | |
2bd0ea18 NS |
78 | if (in_extent == 0) { |
79 | /* | |
80 | * found the start of a free extent | |
81 | */ | |
82 | in_extent = 1; | |
83 | num_extents++; | |
84 | extent_start = agbno; | |
8961bfde | 85 | extent_len = blen; |
2bd0ea18 | 86 | } else { |
8961bfde | 87 | extent_len += blen; |
2bd0ea18 NS |
88 | } |
89 | } else { | |
90 | if (in_extent) { | |
91 | /* | |
92 | * free extent ends here, add extent to the | |
93 | * 2 incore extent (avl-to-be-B+) trees | |
94 | */ | |
95 | in_extent = 0; | |
96 | #if defined(XR_BLD_FREE_TRACE) && defined(XR_BLD_ADD_EXTENT) | |
97 | fprintf(stderr, "adding extent %u [%u %u]\n", | |
98 | agno, extent_start, extent_len); | |
99 | #endif | |
100 | add_bno_extent(agno, extent_start, extent_len); | |
101 | add_bcnt_extent(agno, extent_start, extent_len); | |
7e5ec4e4 | 102 | *num_freeblocks += extent_len; |
2bd0ea18 NS |
103 | } |
104 | } | |
105 | } | |
106 | if (in_extent) { | |
107 | /* | |
108 | * free extent ends here | |
109 | */ | |
2bd0ea18 NS |
110 | #if defined(XR_BLD_FREE_TRACE) && defined(XR_BLD_ADD_EXTENT) |
111 | fprintf(stderr, "adding extent %u [%u %u]\n", | |
112 | agno, extent_start, extent_len); | |
113 | #endif | |
114 | add_bno_extent(agno, extent_start, extent_len); | |
115 | add_bcnt_extent(agno, extent_start, extent_len); | |
7e5ec4e4 | 116 | *num_freeblocks += extent_len; |
2bd0ea18 NS |
117 | } |
118 | ||
119 | return(num_extents); | |
120 | } | |
121 | ||
2bd0ea18 | 122 | /* |
7a21223c | 123 | * XXX: yet more code that can be shared with mkfs, growfs. |
2bd0ea18 | 124 | */ |
8b8a6b02 | 125 | static void |
7a21223c DW |
126 | build_agi( |
127 | struct xfs_mount *mp, | |
128 | xfs_agnumber_t agno, | |
129 | struct bt_rebuild *btr_ino, | |
130 | struct bt_rebuild *btr_fino) | |
2bd0ea18 | 131 | { |
7a21223c DW |
132 | struct xfs_buf *agi_buf; |
133 | struct xfs_agi *agi; | |
2bd0ea18 | 134 | int i; |
58a8b31f | 135 | int error; |
2bd0ea18 | 136 | |
58a8b31f | 137 | error = -libxfs_buf_get(mp->m_dev, |
9440d84d | 138 | XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), |
58a8b31f DW |
139 | mp->m_sb.sb_sectsize / BBSIZE, &agi_buf); |
140 | if (error) | |
141 | do_error(_("Cannot grab AG %u AGI buffer, err=%d"), | |
142 | agno, error); | |
e0607266 | 143 | agi_buf->b_ops = &xfs_agi_buf_ops; |
c99cea5c | 144 | agi = agi_buf->b_addr; |
dab9b8d6 | 145 | memset(agi, 0, mp->m_sb.sb_sectsize); |
2bd0ea18 | 146 | |
5e656dbb BN |
147 | agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC); |
148 | agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION); | |
149 | agi->agi_seqno = cpu_to_be32(agno); | |
2bd0ea18 | 150 | if (agno < mp->m_sb.sb_agcount - 1) |
5e656dbb | 151 | agi->agi_length = cpu_to_be32(mp->m_sb.sb_agblocks); |
2bd0ea18 | 152 | else |
5e656dbb | 153 | agi->agi_length = cpu_to_be32(mp->m_sb.sb_dblocks - |
5a35bf2c | 154 | (xfs_rfsblock_t) mp->m_sb.sb_agblocks * agno); |
7a21223c DW |
155 | agi->agi_count = cpu_to_be32(btr_ino->count); |
156 | agi->agi_root = cpu_to_be32(btr_ino->newbt.afake.af_root); | |
157 | agi->agi_level = cpu_to_be32(btr_ino->newbt.afake.af_levels); | |
158 | agi->agi_freecount = cpu_to_be32(btr_ino->freecount); | |
159 | agi->agi_newino = cpu_to_be32(btr_ino->first_agino); | |
5e656dbb BN |
160 | agi->agi_dirino = cpu_to_be32(NULLAGINO); |
161 | ||
f8149110 | 162 | for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) |
5e656dbb | 163 | agi->agi_unlinked[i] = cpu_to_be32(NULLAGINO); |
2bd0ea18 | 164 | |
e0607266 | 165 | if (xfs_sb_version_hascrc(&mp->m_sb)) |
9c4e12fb | 166 | platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid); |
e0607266 | 167 | |
bbdb21b6 | 168 | if (xfs_sb_version_hasfinobt(&mp->m_sb)) { |
7a21223c DW |
169 | agi->agi_free_root = |
170 | cpu_to_be32(btr_fino->newbt.afake.af_root); | |
171 | agi->agi_free_level = | |
172 | cpu_to_be32(btr_fino->newbt.afake.af_levels); | |
bbdb21b6 BF |
173 | } |
174 | ||
086250dc DW |
175 | if (xfs_sb_version_hasinobtcounts(&mp->m_sb)) { |
176 | agi->agi_iblocks = cpu_to_be32(btr_ino->newbt.afake.af_blocks); | |
177 | agi->agi_fblocks = cpu_to_be32(btr_fino->newbt.afake.af_blocks); | |
178 | } | |
179 | ||
f524ae04 | 180 | libxfs_buf_mark_dirty(agi_buf); |
18b4f688 | 181 | libxfs_buf_relse(agi_buf); |
2bd0ea18 NS |
182 | } |
183 | ||
7e5ec4e4 DW |
184 | /* Fill the AGFL with any leftover bnobt rebuilder blocks. */ |
185 | static void | |
186 | fill_agfl( | |
187 | struct bt_rebuild *btr, | |
188 | __be32 *agfl_bnos, | |
189 | unsigned int *agfl_idx) | |
190 | { | |
191 | struct bulkload_resv *resv, *n; | |
192 | struct xfs_mount *mp = btr->newbt.sc->mp; | |
193 | ||
194 | for_each_bulkload_reservation(&btr->newbt, resv, n) { | |
195 | xfs_agblock_t bno; | |
196 | ||
197 | bno = XFS_FSB_TO_AGBNO(mp, resv->fsbno + resv->used); | |
198 | while (resv->used < resv->len && | |
199 | *agfl_idx < libxfs_agfl_size(mp)) { | |
200 | agfl_bnos[(*agfl_idx)++] = cpu_to_be32(bno++); | |
201 | resv->used++; | |
202 | } | |
203 | } | |
204 | } | |
205 | ||
2bd0ea18 NS |
206 | /* |
207 | * build both the agf and the agfl for an agno given both | |
e0607266 DC |
208 | * btree cursors. |
209 | * | |
210 | * XXX: yet more common code that can be shared with mkfs/growfs. | |
2bd0ea18 | 211 | */ |
8b8a6b02 | 212 | static void |
934b5548 DW |
213 | build_agf_agfl( |
214 | struct xfs_mount *mp, | |
215 | xfs_agnumber_t agno, | |
7e5ec4e4 DW |
216 | struct bt_rebuild *btr_bno, |
217 | struct bt_rebuild *btr_cnt, | |
dc9f4f5e | 218 | struct bt_rebuild *btr_rmap, |
3c1ce0fc | 219 | struct bt_rebuild *btr_refc, |
c94d40ce | 220 | struct bitmap *lost_blocks) |
2bd0ea18 | 221 | { |
934b5548 DW |
222 | struct extent_tree_node *ext_ptr; |
223 | struct xfs_buf *agf_buf, *agfl_buf; | |
3acf0068 | 224 | unsigned int agfl_idx; |
934b5548 DW |
225 | struct xfs_agfl *agfl; |
226 | struct xfs_agf *agf; | |
84232448 | 227 | __be32 *freelist; |
ef4332b8 | 228 | int error; |
2bd0ea18 | 229 | |
58a8b31f | 230 | error = -libxfs_buf_get(mp->m_dev, |
9440d84d | 231 | XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), |
58a8b31f DW |
232 | mp->m_sb.sb_sectsize / BBSIZE, &agf_buf); |
233 | if (error) | |
234 | do_error(_("Cannot grab AG %u AGF buffer, err=%d"), | |
235 | agno, error); | |
e0607266 | 236 | agf_buf->b_ops = &xfs_agf_buf_ops; |
0bc284c2 | 237 | agf = agf_buf->b_addr; |
dab9b8d6 | 238 | memset(agf, 0, mp->m_sb.sb_sectsize); |
2bd0ea18 NS |
239 | |
240 | #ifdef XR_BLD_FREE_TRACE | |
ef4109d1 | 241 | fprintf(stderr, "agf = %p, agf_buf->b_addr = %p\n", |
7c7c113c | 242 | agf, agf_buf->b_addr); |
2bd0ea18 NS |
243 | #endif |
244 | ||
245 | /* | |
246 | * set up fixed part of agf | |
247 | */ | |
5e656dbb BN |
248 | agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC); |
249 | agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION); | |
250 | agf->agf_seqno = cpu_to_be32(agno); | |
2bd0ea18 NS |
251 | |
252 | if (agno < mp->m_sb.sb_agcount - 1) | |
5e656dbb | 253 | agf->agf_length = cpu_to_be32(mp->m_sb.sb_agblocks); |
2bd0ea18 | 254 | else |
5e656dbb | 255 | agf->agf_length = cpu_to_be32(mp->m_sb.sb_dblocks - |
5a35bf2c | 256 | (xfs_rfsblock_t) mp->m_sb.sb_agblocks * agno); |
2bd0ea18 | 257 | |
7e5ec4e4 DW |
258 | agf->agf_roots[XFS_BTNUM_BNO] = |
259 | cpu_to_be32(btr_bno->newbt.afake.af_root); | |
260 | agf->agf_levels[XFS_BTNUM_BNO] = | |
261 | cpu_to_be32(btr_bno->newbt.afake.af_levels); | |
262 | agf->agf_roots[XFS_BTNUM_CNT] = | |
263 | cpu_to_be32(btr_cnt->newbt.afake.af_root); | |
264 | agf->agf_levels[XFS_BTNUM_CNT] = | |
265 | cpu_to_be32(btr_cnt->newbt.afake.af_levels); | |
7e5ec4e4 | 266 | agf->agf_freeblks = cpu_to_be32(btr_bno->freeblks); |
dc9f4f5e DW |
267 | |
268 | if (xfs_sb_version_hasrmapbt(&mp->m_sb)) { | |
269 | agf->agf_roots[XFS_BTNUM_RMAP] = | |
270 | cpu_to_be32(btr_rmap->newbt.afake.af_root); | |
271 | agf->agf_levels[XFS_BTNUM_RMAP] = | |
272 | cpu_to_be32(btr_rmap->newbt.afake.af_levels); | |
273 | agf->agf_rmap_blocks = | |
274 | cpu_to_be32(btr_rmap->newbt.afake.af_blocks); | |
275 | } | |
276 | ||
3c1ce0fc DW |
277 | if (xfs_sb_version_hasreflink(&mp->m_sb)) { |
278 | agf->agf_refcount_root = | |
279 | cpu_to_be32(btr_refc->newbt.afake.af_root); | |
280 | agf->agf_refcount_level = | |
281 | cpu_to_be32(btr_refc->newbt.afake.af_levels); | |
282 | agf->agf_refcount_blocks = | |
283 | cpu_to_be32(btr_refc->newbt.afake.af_blocks); | |
284 | } | |
2bd0ea18 | 285 | |
cdded3d8 DC |
286 | /* |
287 | * Count and record the number of btree blocks consumed if required. | |
288 | */ | |
5e656dbb | 289 | if (xfs_sb_version_haslazysbcount(&mp->m_sb)) { |
934b5548 | 290 | unsigned int blks; |
cdded3d8 DC |
291 | /* |
292 | * Don't count the root blocks as they are already | |
293 | * accounted for. | |
294 | */ | |
7e5ec4e4 DW |
295 | blks = btr_bno->newbt.afake.af_blocks + |
296 | btr_cnt->newbt.afake.af_blocks - 2; | |
934b5548 | 297 | if (xfs_sb_version_hasrmapbt(&mp->m_sb)) |
dc9f4f5e | 298 | blks += btr_rmap->newbt.afake.af_blocks - 1; |
934b5548 | 299 | agf->agf_btreeblks = cpu_to_be32(blks); |
cdded3d8 DC |
300 | #ifdef XR_BLD_FREE_TRACE |
301 | fprintf(stderr, "agf->agf_btreeblks = %u\n", | |
5e656dbb | 302 | be32_to_cpu(agf->agf_btreeblks)); |
cdded3d8 DC |
303 | #endif |
304 | } | |
305 | ||
2bd0ea18 NS |
306 | #ifdef XR_BLD_FREE_TRACE |
307 | fprintf(stderr, "bno root = %u, bcnt root = %u, indices = %u %u\n", | |
5e656dbb BN |
308 | be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]), |
309 | be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]), | |
2bd0ea18 NS |
310 | XFS_BTNUM_BNO, |
311 | XFS_BTNUM_CNT); | |
312 | #endif | |
313 | ||
e0607266 | 314 | if (xfs_sb_version_hascrc(&mp->m_sb)) |
9c4e12fb | 315 | platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid); |
e0607266 DC |
316 | |
317 | /* initialise the AGFL, then fill it if there are blocks left over. */ | |
58a8b31f | 318 | error = -libxfs_buf_get(mp->m_dev, |
e0607266 | 319 | XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)), |
58a8b31f DW |
320 | mp->m_sb.sb_sectsize / BBSIZE, &agfl_buf); |
321 | if (error) | |
322 | do_error(_("Cannot grab AG %u AGFL buffer, err=%d"), | |
323 | agno, error); | |
e0607266 DC |
324 | agfl_buf->b_ops = &xfs_agfl_buf_ops; |
325 | agfl = XFS_BUF_TO_AGFL(agfl_buf); | |
326 | ||
327 | /* setting to 0xff results in initialisation to NULLAGBLOCK */ | |
328 | memset(agfl, 0xff, mp->m_sb.sb_sectsize); | |
0c02ef9b | 329 | freelist = xfs_buf_to_agfl_bno(agfl_buf); |
e0607266 DC |
330 | if (xfs_sb_version_hascrc(&mp->m_sb)) { |
331 | agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC); | |
332 | agfl->agfl_seqno = cpu_to_be32(agno); | |
9c4e12fb | 333 | platform_uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid); |
3acf0068 DW |
334 | for (agfl_idx = 0; agfl_idx < libxfs_agfl_size(mp); agfl_idx++) |
335 | freelist[agfl_idx] = cpu_to_be32(NULLAGBLOCK); | |
e0607266 | 336 | } |
b134e771 | 337 | |
7e5ec4e4 DW |
338 | /* Fill the AGFL with leftover blocks or save them for later. */ |
339 | agfl_idx = 0; | |
340 | freelist = xfs_buf_to_agfl_bno(agfl_buf); | |
341 | fill_agfl(btr_bno, freelist, &agfl_idx); | |
342 | fill_agfl(btr_cnt, freelist, &agfl_idx); | |
dc9f4f5e DW |
343 | if (xfs_sb_version_hasrmapbt(&mp->m_sb)) |
344 | fill_agfl(btr_rmap, freelist, &agfl_idx); | |
2bd0ea18 | 345 | |
7e5ec4e4 DW |
346 | /* Set the AGF counters for the AGFL. */ |
347 | if (agfl_idx > 0) { | |
46eca962 | 348 | agf->agf_flfirst = 0; |
3acf0068 DW |
349 | agf->agf_fllast = cpu_to_be32(agfl_idx - 1); |
350 | agf->agf_flcount = cpu_to_be32(agfl_idx); | |
351 | rmap_store_agflcount(mp, agno, agfl_idx); | |
2bd0ea18 NS |
352 | |
353 | #ifdef XR_BLD_FREE_TRACE | |
354 | fprintf(stderr, "writing agfl for ag %u\n", agno); | |
355 | #endif | |
356 | ||
2bd0ea18 | 357 | } else { |
46eca962 | 358 | agf->agf_flfirst = 0; |
b8165508 | 359 | agf->agf_fllast = cpu_to_be32(libxfs_agfl_size(mp) - 1); |
46eca962 | 360 | agf->agf_flcount = 0; |
2bd0ea18 NS |
361 | } |
362 | ||
f524ae04 | 363 | libxfs_buf_mark_dirty(agfl_buf); |
18b4f688 | 364 | libxfs_buf_relse(agfl_buf); |
e0607266 | 365 | |
2bd0ea18 | 366 | ext_ptr = findbiggest_bcnt_extent(agno); |
5e656dbb BN |
367 | agf->agf_longest = cpu_to_be32((ext_ptr != NULL) ? |
368 | ext_ptr->ex_blockcount : 0); | |
2bd0ea18 | 369 | |
5e656dbb BN |
370 | ASSERT(be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNOi]) != |
371 | be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNTi])); | |
586a8fc3 DW |
372 | ASSERT(be32_to_cpu(agf->agf_refcount_root) != |
373 | be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNOi])); | |
374 | ASSERT(be32_to_cpu(agf->agf_refcount_root) != | |
375 | be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNTi])); | |
2bd0ea18 | 376 | |
f524ae04 | 377 | libxfs_buf_mark_dirty(agf_buf); |
18b4f688 | 378 | libxfs_buf_relse(agf_buf); |
2bd0ea18 | 379 | |
e0607266 DC |
380 | /* |
381 | * now fix up the free list appropriately | |
e0607266 | 382 | */ |
62cf990a | 383 | fix_freelist(mp, agno, true); |
e0607266 | 384 | |
2bd0ea18 | 385 | #ifdef XR_BLD_FREE_TRACE |
7c7c113c | 386 | fprintf(stderr, "wrote agf for ag %u\n", agno); |
2bd0ea18 NS |
387 | #endif |
388 | } | |
389 | ||
390 | /* | |
391 | * update the superblock counters, sync the sb version numbers and | |
392 | * feature bits to the filesystem, and sync up the on-disk superblock | |
393 | * to match the incore superblock. | |
394 | */ | |
8b8a6b02 | 395 | static void |
2bd0ea18 NS |
396 | sync_sb(xfs_mount_t *mp) |
397 | { | |
167137fe | 398 | struct xfs_buf *bp; |
2bd0ea18 | 399 | |
67c4a324 | 400 | bp = libxfs_getsb(mp); |
2bd0ea18 | 401 | if (!bp) |
507f4e33 | 402 | do_error(_("couldn't get superblock\n")); |
2bd0ea18 | 403 | |
2bd0ea18 NS |
404 | mp->m_sb.sb_icount = sb_icount; |
405 | mp->m_sb.sb_ifree = sb_ifree; | |
406 | mp->m_sb.sb_fdblocks = sb_fdblocks; | |
407 | mp->m_sb.sb_frextents = sb_frextents; | |
408 | ||
409 | update_sb_version(mp); | |
410 | ||
d6522f1d | 411 | libxfs_sb_to_disk(bp->b_addr, &mp->m_sb); |
f524ae04 | 412 | libxfs_buf_mark_dirty(bp); |
18b4f688 | 413 | libxfs_buf_relse(bp); |
2bd0ea18 NS |
414 | } |
415 | ||
416 | /* | |
417 | * make sure the root and realtime inodes show up allocated | |
418 | * even if they've been freed. they get reinitialized in phase6. | |
419 | */ | |
8b8a6b02 | 420 | static void |
2bd0ea18 NS |
421 | keep_fsinos(xfs_mount_t *mp) |
422 | { | |
423 | ino_tree_node_t *irec; | |
424 | int i; | |
425 | ||
1ae311d5 | 426 | irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino), |
2bd0ea18 NS |
427 | XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino)); |
428 | ||
429 | for (i = 0; i < 3; i++) | |
430 | set_inode_used(irec, i); | |
431 | } | |
432 | ||
2556c98b BN |
433 | static void |
434 | phase5_func( | |
7e5ec4e4 | 435 | struct xfs_mount *mp, |
195c248c | 436 | struct xfs_perag *pag, |
c94d40ce | 437 | struct bitmap *lost_blocks) |
2bd0ea18 | 438 | { |
7e5ec4e4 | 439 | struct repair_ctx sc = { .mp = mp, }; |
7e5ec4e4 DW |
440 | struct bt_rebuild btr_bno; |
441 | struct bt_rebuild btr_cnt; | |
7a21223c DW |
442 | struct bt_rebuild btr_ino; |
443 | struct bt_rebuild btr_fino; | |
dc9f4f5e | 444 | struct bt_rebuild btr_rmap; |
3c1ce0fc | 445 | struct bt_rebuild btr_refc; |
195c248c | 446 | xfs_agnumber_t agno = pag->pag_agno; |
7e5ec4e4 DW |
447 | int extra_blocks = 0; |
448 | uint num_freeblocks; | |
449 | xfs_agblock_t num_extents; | |
2bd0ea18 | 450 | |
3b6ac903 MV |
451 | if (verbose) |
452 | do_log(_(" - agno = %d\n"), agno); | |
2bd0ea18 | 453 | |
e48f6fbc ES |
454 | /* |
455 | * build up incore bno and bcnt extent btrees | |
456 | */ | |
7e5ec4e4 | 457 | num_extents = mk_incore_fstree(mp, agno, &num_freeblocks); |
2bd0ea18 NS |
458 | |
459 | #ifdef XR_BLD_FREE_TRACE | |
e48f6fbc | 460 | fprintf(stderr, "# of bno extents is %d\n", count_bno_extents(agno)); |
2bd0ea18 NS |
461 | #endif |
462 | ||
e48f6fbc | 463 | if (num_extents == 0) { |
2bd0ea18 | 464 | /* |
e48f6fbc ES |
465 | * XXX - what we probably should do here is pick an inode for |
466 | * a regular file in the allocation group that has space | |
467 | * allocated and shoot it by traversing the bmap list and | |
468 | * putting all its extents on the incore freespace trees, | |
469 | * clearing the inode, and clearing the in-use bit in the | |
470 | * incore inode tree. Then try mk_incore_fstree() again. | |
2bd0ea18 | 471 | */ |
e48f6fbc ES |
472 | do_error( |
473 | _("unable to rebuild AG %u. Not enough free space in on-disk AG.\n"), | |
474 | agno); | |
475 | } | |
bbdb21b6 | 476 | |
7a21223c DW |
477 | init_ino_cursors(&sc, agno, num_freeblocks, &sb_icount_ag[agno], |
478 | &sb_ifree_ag[agno], &btr_ino, &btr_fino); | |
934b5548 | 479 | |
195c248c | 480 | init_rmapbt_cursor(&sc, pag, num_freeblocks, &btr_rmap); |
586a8fc3 | 481 | |
971fceb4 | 482 | init_refc_cursor(&sc, pag, num_freeblocks, &btr_refc); |
e48f6fbc ES |
483 | |
484 | num_extents = count_bno_extents_blocks(agno, &num_freeblocks); | |
485 | /* | |
486 | * lose two blocks per AG -- the space tree roots are counted as | |
487 | * allocated since the space trees always have roots | |
488 | */ | |
489 | sb_fdblocks_ag[agno] += num_freeblocks - 2; | |
490 | ||
491 | if (num_extents == 0) { | |
2bd0ea18 | 492 | /* |
e48f6fbc ES |
493 | * XXX - what we probably should do here is pick an inode for |
494 | * a regular file in the allocation group that has space | |
495 | * allocated and shoot it by traversing the bmap list and | |
496 | * putting all its extents on the incore freespace trees, | |
497 | * clearing the inode, and clearing the in-use bit in the | |
498 | * incore inode tree. Then try mk_incore_fstree() again. | |
2bd0ea18 | 499 | */ |
e48f6fbc ES |
500 | do_error(_("unable to rebuild AG %u. No free space.\n"), agno); |
501 | } | |
2bd0ea18 NS |
502 | |
503 | #ifdef XR_BLD_FREE_TRACE | |
e48f6fbc | 504 | fprintf(stderr, "# of bno extents is %d\n", num_extents); |
2bd0ea18 NS |
505 | #endif |
506 | ||
e48f6fbc ES |
507 | /* |
508 | * track blocks that we might really lose | |
509 | */ | |
7e5ec4e4 DW |
510 | init_freespace_cursors(&sc, agno, num_freeblocks, &num_extents, |
511 | &extra_blocks, &btr_bno, &btr_cnt); | |
2bd0ea18 | 512 | |
e48f6fbc ES |
513 | /* |
514 | * freespace btrees live in the "free space" but the filesystem treats | |
515 | * AGFL blocks as allocated since they aren't described by the | |
516 | * freespace trees | |
517 | */ | |
2bd0ea18 | 518 | |
e48f6fbc ES |
519 | /* |
520 | * see if we can fit all the extra blocks into the AGFL | |
521 | */ | |
522 | extra_blocks = (extra_blocks - libxfs_agfl_size(mp) > 0) ? | |
523 | extra_blocks - libxfs_agfl_size(mp) : 0; | |
2bd0ea18 | 524 | |
e48f6fbc ES |
525 | if (extra_blocks > 0) |
526 | sb_fdblocks_ag[agno] -= extra_blocks; | |
2bd0ea18 | 527 | |
2bd0ea18 | 528 | #ifdef XR_BLD_FREE_TRACE |
e48f6fbc ES |
529 | fprintf(stderr, "# of bno extents is %d\n", count_bno_extents(agno)); |
530 | fprintf(stderr, "# of bcnt extents is %d\n", count_bcnt_extents(agno)); | |
2bd0ea18 | 531 | #endif |
46eca962 | 532 | |
7e5ec4e4 | 533 | build_freespace_btrees(&sc, agno, &btr_bno, &btr_cnt); |
2bd0ea18 | 534 | |
7e5ec4e4 DW |
535 | #ifdef XR_BLD_FREE_TRACE |
536 | fprintf(stderr, "# of free blocks == %d/%d\n", btr_bno.freeblks, | |
537 | btr_cnt.freeblks); | |
1e77098c | 538 | #endif |
7e5ec4e4 | 539 | ASSERT(btr_bno.freeblks == btr_cnt.freeblks); |
2bd0ea18 | 540 | |
e48f6fbc | 541 | if (xfs_sb_version_hasrmapbt(&mp->m_sb)) { |
dc9f4f5e DW |
542 | build_rmap_tree(&sc, agno, &btr_rmap); |
543 | sb_fdblocks_ag[agno] += btr_rmap.newbt.afake.af_blocks - 1; | |
e48f6fbc | 544 | } |
934b5548 | 545 | |
3c1ce0fc DW |
546 | if (xfs_sb_version_hasreflink(&mp->m_sb)) |
547 | build_refcount_tree(&sc, agno, &btr_refc); | |
586a8fc3 | 548 | |
e48f6fbc ES |
549 | /* |
550 | * set up agf and agfl | |
551 | */ | |
3c1ce0fc | 552 | build_agf_agfl(mp, agno, &btr_bno, &btr_cnt, &btr_rmap, &btr_refc, |
c94d40ce | 553 | lost_blocks); |
7e5ec4e4 | 554 | |
7a21223c | 555 | build_inode_btrees(&sc, agno, &btr_ino, &btr_fino); |
bbdb21b6 | 556 | |
e48f6fbc | 557 | /* build the agi */ |
7a21223c | 558 | build_agi(mp, agno, &btr_ino, &btr_fino); |
d6412d17 | 559 | |
e48f6fbc ES |
560 | /* |
561 | * tear down cursors | |
562 | */ | |
c94d40ce DW |
563 | finish_rebuild(mp, &btr_bno, lost_blocks); |
564 | finish_rebuild(mp, &btr_cnt, lost_blocks); | |
565 | finish_rebuild(mp, &btr_ino, lost_blocks); | |
7a21223c | 566 | if (xfs_sb_version_hasfinobt(&mp->m_sb)) |
c94d40ce | 567 | finish_rebuild(mp, &btr_fino, lost_blocks); |
e48f6fbc | 568 | if (xfs_sb_version_hasrmapbt(&mp->m_sb)) |
c94d40ce | 569 | finish_rebuild(mp, &btr_rmap, lost_blocks); |
e48f6fbc | 570 | if (xfs_sb_version_hasreflink(&mp->m_sb)) |
c94d40ce | 571 | finish_rebuild(mp, &btr_refc, lost_blocks); |
62cf990a | 572 | |
e48f6fbc ES |
573 | /* |
574 | * release the incore per-AG bno/bcnt trees so the extent nodes | |
575 | * can be recycled | |
576 | */ | |
577 | release_agbno_extent_tree(agno); | |
578 | release_agbcnt_extent_tree(agno); | |
06fbdda9 | 579 | PROG_RPT_INC(prog_rpt_done[agno], 1); |
3b6ac903 MV |
580 | } |
581 | ||
c94d40ce | 582 | /* Inject this unused space back into the filesystem. */ |
ef4332b8 | 583 | static int |
c94d40ce DW |
584 | inject_lost_extent( |
585 | uint64_t start, | |
586 | uint64_t length, | |
587 | void *arg) | |
ef4332b8 | 588 | { |
c94d40ce DW |
589 | struct xfs_mount *mp = arg; |
590 | struct xfs_trans *tp; | |
ef4332b8 DW |
591 | int error; |
592 | ||
c94d40ce | 593 | error = -libxfs_trans_alloc_rollable(mp, 16, &tp); |
ef4332b8 DW |
594 | if (error) |
595 | return error; | |
596 | ||
c94d40ce DW |
597 | error = -libxfs_free_extent(tp, start, length, |
598 | &XFS_RMAP_OINFO_ANY_OWNER, XFS_AG_RESV_NONE); | |
599 | if (error) | |
600 | return error; | |
ef4332b8 | 601 | |
c94d40ce | 602 | return -libxfs_trans_commit(tp); |
ef4332b8 DW |
603 | } |
604 | ||
3b6ac903 MV |
605 | void |
606 | phase5(xfs_mount_t *mp) | |
607 | { | |
c94d40ce | 608 | struct bitmap *lost_blocks = NULL; |
195c248c | 609 | struct xfs_perag *pag; |
2556c98b | 610 | xfs_agnumber_t agno; |
ef4332b8 | 611 | int error; |
3b6ac903 MV |
612 | |
613 | do_log(_("Phase 5 - rebuild AG headers and trees...\n")); | |
14f8b681 | 614 | set_progress_msg(PROG_FMT_REBUILD_AG, (uint64_t)glob_agcount); |
3b6ac903 MV |
615 | |
616 | #ifdef XR_BLD_FREE_TRACE | |
617 | fprintf(stderr, "inobt level 1, maxrec = %d, minrec = %d\n", | |
e2f60652 DW |
618 | libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 0), |
619 | libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 0) / 2); | |
3b6ac903 | 620 | fprintf(stderr, "inobt level 0 (leaf), maxrec = %d, minrec = %d\n", |
e2f60652 DW |
621 | libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 1), |
622 | libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 1) / 2); | |
3b6ac903 MV |
623 | fprintf(stderr, "xr inobt level 0 (leaf), maxrec = %d\n", |
624 | XR_INOBT_BLOCK_MAXRECS(mp, 0)); | |
625 | fprintf(stderr, "xr inobt level 1 (int), maxrec = %d\n", | |
626 | XR_INOBT_BLOCK_MAXRECS(mp, 1)); | |
627 | fprintf(stderr, "bnobt level 1, maxrec = %d, minrec = %d\n", | |
e2f60652 DW |
628 | libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 0), |
629 | libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 0) / 2); | |
3b6ac903 | 630 | fprintf(stderr, "bnobt level 0 (leaf), maxrec = %d, minrec = %d\n", |
e2f60652 DW |
631 | libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 1), |
632 | libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 1) / 2); | |
3b6ac903 MV |
633 | #endif |
634 | /* | |
635 | * make sure the root and realtime inodes show up allocated | |
636 | */ | |
637 | keep_fsinos(mp); | |
638 | ||
639 | /* allocate per ag counters */ | |
14f8b681 | 640 | sb_icount_ag = calloc(mp->m_sb.sb_agcount, sizeof(uint64_t)); |
3b6ac903 MV |
641 | if (sb_icount_ag == NULL) |
642 | do_error(_("cannot alloc sb_icount_ag buffers\n")); | |
643 | ||
14f8b681 | 644 | sb_ifree_ag = calloc(mp->m_sb.sb_agcount, sizeof(uint64_t)); |
3b6ac903 MV |
645 | if (sb_ifree_ag == NULL) |
646 | do_error(_("cannot alloc sb_ifree_ag buffers\n")); | |
647 | ||
14f8b681 | 648 | sb_fdblocks_ag = calloc(mp->m_sb.sb_agcount, sizeof(uint64_t)); |
3b6ac903 MV |
649 | if (sb_fdblocks_ag == NULL) |
650 | do_error(_("cannot alloc sb_fdblocks_ag buffers\n")); | |
651 | ||
c94d40ce | 652 | error = bitmap_alloc(&lost_blocks); |
ef4332b8 | 653 | if (error) |
c94d40ce | 654 | do_error(_("cannot alloc lost block bitmap\n")); |
ef4332b8 | 655 | |
195c248c DC |
656 | for_each_perag(mp, agno, pag) |
657 | phase5_func(mp, pag, lost_blocks); | |
2556c98b | 658 | |
06fbdda9 | 659 | print_final_rpt(); |
3b6ac903 MV |
660 | |
661 | /* aggregate per ag counters */ | |
662 | for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { | |
663 | sb_icount += sb_icount_ag[agno]; | |
664 | sb_ifree += sb_ifree_ag[agno]; | |
665 | sb_fdblocks += sb_fdblocks_ag[agno]; | |
666 | } | |
667 | free(sb_icount_ag); | |
668 | free(sb_ifree_ag); | |
669 | free(sb_fdblocks_ag); | |
2bd0ea18 NS |
670 | |
671 | if (mp->m_sb.sb_rblocks) { | |
672 | do_log( | |
507f4e33 | 673 | _(" - generate realtime summary info and bitmap...\n")); |
2bd0ea18 NS |
674 | rtinit(mp); |
675 | generate_rtinfo(mp, btmcompute, sumcompute); | |
2bd0ea18 NS |
676 | } |
677 | ||
507f4e33 | 678 | do_log(_(" - reset superblock...\n")); |
2bd0ea18 NS |
679 | |
680 | /* | |
681 | * sync superblock counter and set version bits correctly | |
682 | */ | |
683 | sync_sb(mp); | |
684 | ||
ac8b6c38 DW |
685 | /* |
686 | * Put the per-AG btree rmap data into the rmapbt now that we've reset | |
687 | * the superblock counters. | |
688 | */ | |
689 | for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { | |
690 | error = rmap_store_ag_btree_rec(mp, agno); | |
691 | if (error) | |
692 | do_error( | |
693 | _("unable to add AG %u reverse-mapping data to btree.\n"), agno); | |
694 | } | |
695 | ||
696 | /* | |
697 | * Put blocks that were unnecessarily reserved for btree | |
698 | * reconstruction back into the filesystem free space data. | |
699 | */ | |
c94d40ce | 700 | error = bitmap_iterate(lost_blocks, inject_lost_extent, mp); |
ef4332b8 DW |
701 | if (error) |
702 | do_error(_("Unable to reinsert lost blocks into filesystem.\n")); | |
c94d40ce | 703 | bitmap_free(&lost_blocks); |
ef4332b8 | 704 | |
2bd0ea18 | 705 | bad_ino_btree = 0; |
3b6ac903 | 706 | |
2bd0ea18 | 707 | } |