.. | .. |
---|
10 | 10 | #include "xfs_shared.h" |
---|
11 | 11 | #include "xfs_format.h" |
---|
12 | 12 | #include "xfs_trans_resv.h" |
---|
| 13 | +#include "xfs_bit.h" |
---|
13 | 14 | #include "xfs_sb.h" |
---|
14 | 15 | #include "xfs_mount.h" |
---|
15 | 16 | #include "xfs_btree.h" |
---|
.. | .. |
---|
19 | 20 | #include "xfs_ialloc.h" |
---|
20 | 21 | #include "xfs_rmap.h" |
---|
21 | 22 | #include "xfs_ag.h" |
---|
| 23 | +#include "xfs_ag_resv.h" |
---|
| 24 | +#include "xfs_health.h" |
---|
22 | 25 | |
---|
23 | | -static struct xfs_buf * |
---|
| 26 | +static int |
---|
24 | 27 | xfs_get_aghdr_buf( |
---|
25 | 28 | struct xfs_mount *mp, |
---|
26 | 29 | xfs_daddr_t blkno, |
---|
27 | 30 | size_t numblks, |
---|
28 | | - int flags, |
---|
| 31 | + struct xfs_buf **bpp, |
---|
29 | 32 | const struct xfs_buf_ops *ops) |
---|
30 | 33 | { |
---|
31 | 34 | struct xfs_buf *bp; |
---|
| 35 | + int error; |
---|
32 | 36 | |
---|
33 | | - bp = xfs_buf_get_uncached(mp->m_ddev_targp, numblks, flags); |
---|
34 | | - if (!bp) |
---|
35 | | - return NULL; |
---|
| 37 | + error = xfs_buf_get_uncached(mp->m_ddev_targp, numblks, 0, &bp); |
---|
| 38 | + if (error) |
---|
| 39 | + return error; |
---|
36 | 40 | |
---|
37 | 41 | xfs_buf_zero(bp, 0, BBTOB(bp->b_length)); |
---|
38 | 42 | bp->b_bn = blkno; |
---|
39 | 43 | bp->b_maps[0].bm_bn = blkno; |
---|
40 | 44 | bp->b_ops = ops; |
---|
41 | 45 | |
---|
42 | | - return bp; |
---|
| 46 | + *bpp = bp; |
---|
| 47 | + return 0; |
---|
| 48 | +} |
---|
| 49 | + |
---|
| 50 | +static inline bool is_log_ag(struct xfs_mount *mp, struct aghdr_init_data *id) |
---|
| 51 | +{ |
---|
| 52 | + return mp->m_sb.sb_logstart > 0 && |
---|
| 53 | + id->agno == XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart); |
---|
43 | 54 | } |
---|
44 | 55 | |
---|
45 | 56 | /* |
---|
.. | .. |
---|
51 | 62 | struct xfs_buf *bp, |
---|
52 | 63 | struct aghdr_init_data *id) |
---|
53 | 64 | { |
---|
54 | | - xfs_btree_init_block(mp, bp, id->type, 0, 0, id->agno, 0); |
---|
| 65 | + xfs_btree_init_block(mp, bp, id->type, 0, 0, id->agno); |
---|
| 66 | +} |
---|
| 67 | + |
---|
| 68 | +/* Finish initializing a free space btree. */ |
---|
| 69 | +static void |
---|
| 70 | +xfs_freesp_init_recs( |
---|
| 71 | + struct xfs_mount *mp, |
---|
| 72 | + struct xfs_buf *bp, |
---|
| 73 | + struct aghdr_init_data *id) |
---|
| 74 | +{ |
---|
| 75 | + struct xfs_alloc_rec *arec; |
---|
| 76 | + struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); |
---|
| 77 | + |
---|
| 78 | + arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1); |
---|
| 79 | + arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks); |
---|
| 80 | + |
---|
| 81 | + if (is_log_ag(mp, id)) { |
---|
| 82 | + struct xfs_alloc_rec *nrec; |
---|
| 83 | + xfs_agblock_t start = XFS_FSB_TO_AGBNO(mp, |
---|
| 84 | + mp->m_sb.sb_logstart); |
---|
| 85 | + |
---|
| 86 | + ASSERT(start >= mp->m_ag_prealloc_blocks); |
---|
| 87 | + if (start != mp->m_ag_prealloc_blocks) { |
---|
| 88 | + /* |
---|
| 89 | + * Modify first record to pad stripe align of log |
---|
| 90 | + */ |
---|
| 91 | + arec->ar_blockcount = cpu_to_be32(start - |
---|
| 92 | + mp->m_ag_prealloc_blocks); |
---|
| 93 | + nrec = arec + 1; |
---|
| 94 | + |
---|
| 95 | + /* |
---|
| 96 | + * Insert second record at start of internal log |
---|
| 97 | + * which then gets trimmed. |
---|
| 98 | + */ |
---|
| 99 | + nrec->ar_startblock = cpu_to_be32( |
---|
| 100 | + be32_to_cpu(arec->ar_startblock) + |
---|
| 101 | + be32_to_cpu(arec->ar_blockcount)); |
---|
| 102 | + arec = nrec; |
---|
| 103 | + be16_add_cpu(&block->bb_numrecs, 1); |
---|
| 104 | + } |
---|
| 105 | + /* |
---|
| 106 | + * Change record start to after the internal log |
---|
| 107 | + */ |
---|
| 108 | + be32_add_cpu(&arec->ar_startblock, mp->m_sb.sb_logblocks); |
---|
| 109 | + } |
---|
| 110 | + |
---|
| 111 | + /* |
---|
| 112 | + * Calculate the record block count and check for the case where |
---|
| 113 | + * the log might have consumed all available space in the AG. If |
---|
| 114 | + * so, reset the record count to 0 to avoid exposure of an invalid |
---|
| 115 | + * record start block. |
---|
| 116 | + */ |
---|
| 117 | + arec->ar_blockcount = cpu_to_be32(id->agsize - |
---|
| 118 | + be32_to_cpu(arec->ar_startblock)); |
---|
| 119 | + if (!arec->ar_blockcount) |
---|
| 120 | + block->bb_numrecs = 0; |
---|
55 | 121 | } |
---|
56 | 122 | |
---|
57 | 123 | /* |
---|
.. | .. |
---|
63 | 129 | struct xfs_buf *bp, |
---|
64 | 130 | struct aghdr_init_data *id) |
---|
65 | 131 | { |
---|
66 | | - struct xfs_alloc_rec *arec; |
---|
67 | | - |
---|
68 | | - xfs_btree_init_block(mp, bp, XFS_BTNUM_BNO, 0, 1, id->agno, 0); |
---|
69 | | - arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1); |
---|
70 | | - arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks); |
---|
71 | | - arec->ar_blockcount = cpu_to_be32(id->agsize - |
---|
72 | | - be32_to_cpu(arec->ar_startblock)); |
---|
| 132 | + xfs_btree_init_block(mp, bp, XFS_BTNUM_BNO, 0, 1, id->agno); |
---|
| 133 | + xfs_freesp_init_recs(mp, bp, id); |
---|
73 | 134 | } |
---|
74 | 135 | |
---|
75 | 136 | static void |
---|
.. | .. |
---|
78 | 139 | struct xfs_buf *bp, |
---|
79 | 140 | struct aghdr_init_data *id) |
---|
80 | 141 | { |
---|
81 | | - struct xfs_alloc_rec *arec; |
---|
82 | | - |
---|
83 | | - xfs_btree_init_block(mp, bp, XFS_BTNUM_CNT, 0, 1, id->agno, 0); |
---|
84 | | - arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1); |
---|
85 | | - arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks); |
---|
86 | | - arec->ar_blockcount = cpu_to_be32(id->agsize - |
---|
87 | | - be32_to_cpu(arec->ar_startblock)); |
---|
| 142 | + xfs_btree_init_block(mp, bp, XFS_BTNUM_CNT, 0, 1, id->agno); |
---|
| 143 | + xfs_freesp_init_recs(mp, bp, id); |
---|
88 | 144 | } |
---|
89 | 145 | |
---|
90 | 146 | /* |
---|
.. | .. |
---|
99 | 155 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); |
---|
100 | 156 | struct xfs_rmap_rec *rrec; |
---|
101 | 157 | |
---|
102 | | - xfs_btree_init_block(mp, bp, XFS_BTNUM_RMAP, 0, 4, id->agno, 0); |
---|
| 158 | + xfs_btree_init_block(mp, bp, XFS_BTNUM_RMAP, 0, 4, id->agno); |
---|
103 | 159 | |
---|
104 | 160 | /* |
---|
105 | 161 | * mark the AG header regions as static metadata The BNO |
---|
.. | .. |
---|
147 | 203 | rrec->rm_offset = 0; |
---|
148 | 204 | be16_add_cpu(&block->bb_numrecs, 1); |
---|
149 | 205 | } |
---|
| 206 | + |
---|
| 207 | + /* account for the log space */ |
---|
| 208 | + if (is_log_ag(mp, id)) { |
---|
| 209 | + rrec = XFS_RMAP_REC_ADDR(block, |
---|
| 210 | + be16_to_cpu(block->bb_numrecs) + 1); |
---|
| 211 | + rrec->rm_startblock = cpu_to_be32( |
---|
| 212 | + XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart)); |
---|
| 213 | + rrec->rm_blockcount = cpu_to_be32(mp->m_sb.sb_logblocks); |
---|
| 214 | + rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_LOG); |
---|
| 215 | + rrec->rm_offset = 0; |
---|
| 216 | + be16_add_cpu(&block->bb_numrecs, 1); |
---|
| 217 | + } |
---|
150 | 218 | } |
---|
151 | 219 | |
---|
152 | 220 | /* |
---|
.. | .. |
---|
163 | 231 | struct xfs_buf *bp, |
---|
164 | 232 | struct aghdr_init_data *id) |
---|
165 | 233 | { |
---|
166 | | - struct xfs_dsb *dsb = XFS_BUF_TO_SBP(bp); |
---|
| 234 | + struct xfs_dsb *dsb = bp->b_addr; |
---|
167 | 235 | |
---|
168 | 236 | xfs_sb_to_disk(dsb, &mp->m_sb); |
---|
169 | 237 | dsb->sb_inprogress = 1; |
---|
.. | .. |
---|
175 | 243 | struct xfs_buf *bp, |
---|
176 | 244 | struct aghdr_init_data *id) |
---|
177 | 245 | { |
---|
178 | | - struct xfs_agf *agf = XFS_BUF_TO_AGF(bp); |
---|
| 246 | + struct xfs_agf *agf = bp->b_addr; |
---|
179 | 247 | xfs_extlen_t tmpsize; |
---|
180 | 248 | |
---|
181 | 249 | agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC); |
---|
.. | .. |
---|
207 | 275 | agf->agf_refcount_level = cpu_to_be32(1); |
---|
208 | 276 | agf->agf_refcount_blocks = cpu_to_be32(1); |
---|
209 | 277 | } |
---|
| 278 | + |
---|
| 279 | + if (is_log_ag(mp, id)) { |
---|
| 280 | + int64_t logblocks = mp->m_sb.sb_logblocks; |
---|
| 281 | + |
---|
| 282 | + be32_add_cpu(&agf->agf_freeblks, -logblocks); |
---|
| 283 | + agf->agf_longest = cpu_to_be32(id->agsize - |
---|
| 284 | + XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart) - logblocks); |
---|
| 285 | + } |
---|
210 | 286 | } |
---|
211 | 287 | |
---|
212 | 288 | static void |
---|
.. | .. |
---|
225 | 301 | uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid); |
---|
226 | 302 | } |
---|
227 | 303 | |
---|
228 | | - agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, bp); |
---|
| 304 | + agfl_bno = xfs_buf_to_agfl_bno(bp); |
---|
229 | 305 | for (bucket = 0; bucket < xfs_agfl_size(mp); bucket++) |
---|
230 | 306 | agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK); |
---|
231 | 307 | } |
---|
.. | .. |
---|
236 | 312 | struct xfs_buf *bp, |
---|
237 | 313 | struct aghdr_init_data *id) |
---|
238 | 314 | { |
---|
239 | | - struct xfs_agi *agi = XFS_BUF_TO_AGI(bp); |
---|
| 315 | + struct xfs_agi *agi = bp->b_addr; |
---|
240 | 316 | int bucket; |
---|
241 | 317 | |
---|
242 | 318 | agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC); |
---|
.. | .. |
---|
257 | 333 | } |
---|
258 | 334 | for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) |
---|
259 | 335 | agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO); |
---|
| 336 | + if (xfs_sb_version_hasinobtcounts(&mp->m_sb)) { |
---|
| 337 | + agi->agi_iblocks = cpu_to_be32(1); |
---|
| 338 | + if (xfs_sb_version_hasfinobt(&mp->m_sb)) |
---|
| 339 | + agi->agi_fblocks = cpu_to_be32(1); |
---|
| 340 | + } |
---|
260 | 341 | } |
---|
261 | 342 | |
---|
262 | 343 | typedef void (*aghdr_init_work_f)(struct xfs_mount *mp, struct xfs_buf *bp, |
---|
.. | .. |
---|
267 | 348 | struct aghdr_init_data *id, |
---|
268 | 349 | aghdr_init_work_f work, |
---|
269 | 350 | const struct xfs_buf_ops *ops) |
---|
270 | | - |
---|
271 | 351 | { |
---|
272 | 352 | struct xfs_buf *bp; |
---|
| 353 | + int error; |
---|
273 | 354 | |
---|
274 | | - bp = xfs_get_aghdr_buf(mp, id->daddr, id->numblks, 0, ops); |
---|
275 | | - if (!bp) |
---|
276 | | - return -ENOMEM; |
---|
| 355 | + error = xfs_get_aghdr_buf(mp, id->daddr, id->numblks, &bp, ops); |
---|
| 356 | + if (error) |
---|
| 357 | + return error; |
---|
277 | 358 | |
---|
278 | 359 | (*work)(mp, bp, id); |
---|
279 | 360 | |
---|
.. | .. |
---|
339 | 420 | { /* BNO root block */ |
---|
340 | 421 | .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_BNO_BLOCK(mp)), |
---|
341 | 422 | .numblks = BTOBB(mp->m_sb.sb_blocksize), |
---|
342 | | - .ops = &xfs_allocbt_buf_ops, |
---|
| 423 | + .ops = &xfs_bnobt_buf_ops, |
---|
343 | 424 | .work = &xfs_bnoroot_init, |
---|
344 | 425 | .need_init = true |
---|
345 | 426 | }, |
---|
346 | 427 | { /* CNT root block */ |
---|
347 | 428 | .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_CNT_BLOCK(mp)), |
---|
348 | 429 | .numblks = BTOBB(mp->m_sb.sb_blocksize), |
---|
349 | | - .ops = &xfs_allocbt_buf_ops, |
---|
| 430 | + .ops = &xfs_cntbt_buf_ops, |
---|
350 | 431 | .work = &xfs_cntroot_init, |
---|
351 | 432 | .need_init = true |
---|
352 | 433 | }, |
---|
.. | .. |
---|
361 | 442 | { /* FINO root block */ |
---|
362 | 443 | .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_FIBT_BLOCK(mp)), |
---|
363 | 444 | .numblks = BTOBB(mp->m_sb.sb_blocksize), |
---|
364 | | - .ops = &xfs_inobt_buf_ops, |
---|
| 445 | + .ops = &xfs_finobt_buf_ops, |
---|
365 | 446 | .work = &xfs_btroot_init, |
---|
366 | 447 | .type = XFS_BTNUM_FINO, |
---|
367 | 448 | .need_init = xfs_sb_version_hasfinobt(&mp->m_sb) |
---|
.. | .. |
---|
414 | 495 | struct aghdr_init_data *id, |
---|
415 | 496 | xfs_extlen_t len) |
---|
416 | 497 | { |
---|
417 | | - struct xfs_owner_info oinfo; |
---|
418 | 498 | struct xfs_buf *bp; |
---|
419 | 499 | struct xfs_agi *agi; |
---|
420 | 500 | struct xfs_agf *agf; |
---|
.. | .. |
---|
427 | 507 | if (error) |
---|
428 | 508 | return error; |
---|
429 | 509 | |
---|
430 | | - agi = XFS_BUF_TO_AGI(bp); |
---|
| 510 | + agi = bp->b_addr; |
---|
431 | 511 | be32_add_cpu(&agi->agi_length, len); |
---|
432 | 512 | ASSERT(id->agno == mp->m_sb.sb_agcount - 1 || |
---|
433 | 513 | be32_to_cpu(agi->agi_length) == mp->m_sb.sb_agblocks); |
---|
.. | .. |
---|
440 | 520 | if (error) |
---|
441 | 521 | return error; |
---|
442 | 522 | |
---|
443 | | - agf = XFS_BUF_TO_AGF(bp); |
---|
| 523 | + agf = bp->b_addr; |
---|
444 | 524 | be32_add_cpu(&agf->agf_length, len); |
---|
445 | 525 | ASSERT(agf->agf_length == agi->agi_length); |
---|
446 | 526 | xfs_alloc_log_agf(tp, bp, XFS_AGF_LENGTH); |
---|
.. | .. |
---|
448 | 528 | /* |
---|
449 | 529 | * Free the new space. |
---|
450 | 530 | * |
---|
451 | | - * XFS_RMAP_OWN_NULL is used here to tell the rmap btree that |
---|
| 531 | + * XFS_RMAP_OINFO_SKIP_UPDATE is used here to tell the rmap btree that |
---|
452 | 532 | * this doesn't actually exist in the rmap btree. |
---|
453 | 533 | */ |
---|
454 | | - xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_NULL); |
---|
455 | 534 | error = xfs_rmap_free(tp, bp, id->agno, |
---|
456 | 535 | be32_to_cpu(agf->agf_length) - len, |
---|
457 | | - len, &oinfo); |
---|
| 536 | + len, &XFS_RMAP_OINFO_SKIP_UPDATE); |
---|
458 | 537 | if (error) |
---|
459 | 538 | return error; |
---|
460 | 539 | |
---|
461 | 540 | return xfs_free_extent(tp, XFS_AGB_TO_FSB(mp, id->agno, |
---|
462 | 541 | be32_to_cpu(agf->agf_length) - len), |
---|
463 | | - len, &oinfo, XFS_AG_RESV_NONE); |
---|
| 542 | + len, &XFS_RMAP_OINFO_SKIP_UPDATE, |
---|
| 543 | + XFS_AG_RESV_NONE); |
---|
| 544 | +} |
---|
| 545 | + |
---|
| 546 | +/* Retrieve AG geometry. */ |
---|
| 547 | +int |
---|
| 548 | +xfs_ag_get_geometry( |
---|
| 549 | + struct xfs_mount *mp, |
---|
| 550 | + xfs_agnumber_t agno, |
---|
| 551 | + struct xfs_ag_geometry *ageo) |
---|
| 552 | +{ |
---|
| 553 | + struct xfs_buf *agi_bp; |
---|
| 554 | + struct xfs_buf *agf_bp; |
---|
| 555 | + struct xfs_agi *agi; |
---|
| 556 | + struct xfs_agf *agf; |
---|
| 557 | + struct xfs_perag *pag; |
---|
| 558 | + unsigned int freeblks; |
---|
| 559 | + int error; |
---|
| 560 | + |
---|
| 561 | + if (agno >= mp->m_sb.sb_agcount) |
---|
| 562 | + return -EINVAL; |
---|
| 563 | + |
---|
| 564 | + /* Lock the AG headers. */ |
---|
| 565 | + error = xfs_ialloc_read_agi(mp, NULL, agno, &agi_bp); |
---|
| 566 | + if (error) |
---|
| 567 | + return error; |
---|
| 568 | + error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agf_bp); |
---|
| 569 | + if (error) |
---|
| 570 | + goto out_agi; |
---|
| 571 | + |
---|
| 572 | + pag = agi_bp->b_pag; |
---|
| 573 | + |
---|
| 574 | + /* Fill out form. */ |
---|
| 575 | + memset(ageo, 0, sizeof(*ageo)); |
---|
| 576 | + ageo->ag_number = agno; |
---|
| 577 | + |
---|
| 578 | + agi = agi_bp->b_addr; |
---|
| 579 | + ageo->ag_icount = be32_to_cpu(agi->agi_count); |
---|
| 580 | + ageo->ag_ifree = be32_to_cpu(agi->agi_freecount); |
---|
| 581 | + |
---|
| 582 | + agf = agf_bp->b_addr; |
---|
| 583 | + ageo->ag_length = be32_to_cpu(agf->agf_length); |
---|
| 584 | + freeblks = pag->pagf_freeblks + |
---|
| 585 | + pag->pagf_flcount + |
---|
| 586 | + pag->pagf_btreeblks - |
---|
| 587 | + xfs_ag_resv_needed(pag, XFS_AG_RESV_NONE); |
---|
| 588 | + ageo->ag_freeblks = freeblks; |
---|
| 589 | + xfs_ag_geom_health(pag, ageo); |
---|
| 590 | + |
---|
| 591 | + /* Release resources. */ |
---|
| 592 | + xfs_buf_relse(agf_bp); |
---|
| 593 | +out_agi: |
---|
| 594 | + xfs_buf_relse(agi_bp); |
---|
| 595 | + return error; |
---|
464 | 596 | } |
---|