diff options
Diffstat (limited to 'fs/xfs/xfs_alloc.c')
| -rw-r--r-- | fs/xfs/xfs_alloc.c | 188 |
1 files changed, 104 insertions, 84 deletions
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index f3227984a9bf..27d64d752eab 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c | |||
| @@ -147,10 +147,9 @@ xfs_alloc_get_rec( | |||
| 147 | */ | 147 | */ |
| 148 | STATIC void | 148 | STATIC void |
| 149 | xfs_alloc_compute_aligned( | 149 | xfs_alloc_compute_aligned( |
| 150 | xfs_alloc_arg_t *args, /* allocation argument structure */ | ||
| 150 | xfs_agblock_t foundbno, /* starting block in found extent */ | 151 | xfs_agblock_t foundbno, /* starting block in found extent */ |
| 151 | xfs_extlen_t foundlen, /* length in found extent */ | 152 | xfs_extlen_t foundlen, /* length in found extent */ |
| 152 | xfs_extlen_t alignment, /* alignment for allocation */ | ||
| 153 | xfs_extlen_t minlen, /* minimum length for allocation */ | ||
| 154 | xfs_agblock_t *resbno, /* result block number */ | 153 | xfs_agblock_t *resbno, /* result block number */ |
| 155 | xfs_extlen_t *reslen) /* result length */ | 154 | xfs_extlen_t *reslen) /* result length */ |
| 156 | { | 155 | { |
| @@ -158,8 +157,8 @@ xfs_alloc_compute_aligned( | |||
| 158 | xfs_extlen_t diff; | 157 | xfs_extlen_t diff; |
| 159 | xfs_extlen_t len; | 158 | xfs_extlen_t len; |
| 160 | 159 | ||
| 161 | if (alignment > 1 && foundlen >= minlen) { | 160 | if (args->alignment > 1 && foundlen >= args->minlen) { |
| 162 | bno = roundup(foundbno, alignment); | 161 | bno = roundup(foundbno, args->alignment); |
| 163 | diff = bno - foundbno; | 162 | diff = bno - foundbno; |
| 164 | len = diff >= foundlen ? 0 : foundlen - diff; | 163 | len = diff >= foundlen ? 0 : foundlen - diff; |
| 165 | } else { | 164 | } else { |
| @@ -464,6 +463,27 @@ xfs_alloc_read_agfl( | |||
| 464 | return 0; | 463 | return 0; |
| 465 | } | 464 | } |
| 466 | 465 | ||
| 466 | STATIC int | ||
| 467 | xfs_alloc_update_counters( | ||
| 468 | struct xfs_trans *tp, | ||
| 469 | struct xfs_perag *pag, | ||
| 470 | struct xfs_buf *agbp, | ||
| 471 | long len) | ||
| 472 | { | ||
| 473 | struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); | ||
| 474 | |||
| 475 | pag->pagf_freeblks += len; | ||
| 476 | be32_add_cpu(&agf->agf_freeblks, len); | ||
| 477 | |||
| 478 | xfs_trans_agblocks_delta(tp, len); | ||
| 479 | if (unlikely(be32_to_cpu(agf->agf_freeblks) > | ||
| 480 | be32_to_cpu(agf->agf_length))) | ||
| 481 | return EFSCORRUPTED; | ||
| 482 | |||
| 483 | xfs_alloc_log_agf(tp, agbp, XFS_AGF_FREEBLKS); | ||
| 484 | return 0; | ||
| 485 | } | ||
| 486 | |||
| 467 | /* | 487 | /* |
| 468 | * Allocation group level functions. | 488 | * Allocation group level functions. |
| 469 | */ | 489 | */ |
| @@ -505,49 +525,44 @@ xfs_alloc_ag_vextent( | |||
| 505 | ASSERT(0); | 525 | ASSERT(0); |
| 506 | /* NOTREACHED */ | 526 | /* NOTREACHED */ |
| 507 | } | 527 | } |
| 508 | if (error) | 528 | |
| 529 | if (error || args->agbno == NULLAGBLOCK) | ||
| 509 | return error; | 530 | return error; |
| 510 | /* | ||
| 511 | * If the allocation worked, need to change the agf structure | ||
| 512 | * (and log it), and the superblock. | ||
| 513 | */ | ||
| 514 | if (args->agbno != NULLAGBLOCK) { | ||
| 515 | xfs_agf_t *agf; /* allocation group freelist header */ | ||
| 516 | long slen = (long)args->len; | ||
| 517 | 531 | ||
| 518 | ASSERT(args->len >= args->minlen && args->len <= args->maxlen); | 532 | ASSERT(args->len >= args->minlen); |
| 519 | ASSERT(!(args->wasfromfl) || !args->isfl); | 533 | ASSERT(args->len <= args->maxlen); |
| 520 | ASSERT(args->agbno % args->alignment == 0); | 534 | ASSERT(!args->wasfromfl || !args->isfl); |
| 521 | if (!(args->wasfromfl)) { | 535 | ASSERT(args->agbno % args->alignment == 0); |
| 522 | 536 | ||
| 523 | agf = XFS_BUF_TO_AGF(args->agbp); | 537 | if (!args->wasfromfl) { |
| 524 | be32_add_cpu(&agf->agf_freeblks, -(args->len)); | 538 | error = xfs_alloc_update_counters(args->tp, args->pag, |
| 525 | xfs_trans_agblocks_delta(args->tp, | 539 | args->agbp, |
| 526 | -((long)(args->len))); | 540 | -((long)(args->len))); |
| 527 | args->pag->pagf_freeblks -= args->len; | 541 | if (error) |
| 528 | ASSERT(be32_to_cpu(agf->agf_freeblks) <= | 542 | return error; |
| 529 | be32_to_cpu(agf->agf_length)); | 543 | |
| 530 | xfs_alloc_log_agf(args->tp, args->agbp, | 544 | /* |
| 531 | XFS_AGF_FREEBLKS); | 545 | * Search the busylist for these blocks and mark the |
| 532 | /* | 546 | * transaction as synchronous if blocks are found. This |
| 533 | * Search the busylist for these blocks and mark the | 547 | * avoids the need to block due to a synchronous log |
| 534 | * transaction as synchronous if blocks are found. This | 548 | * force to ensure correct ordering as the synchronous |
| 535 | * avoids the need to block due to a synchronous log | 549 | * transaction will guarantee that for us. |
| 536 | * force to ensure correct ordering as the synchronous | 550 | */ |
| 537 | * transaction will guarantee that for us. | 551 | if (xfs_alloc_busy_search(args->mp, args->agno, |
| 538 | */ | 552 | args->agbno, args->len)) |
| 539 | if (xfs_alloc_busy_search(args->mp, args->agno, | 553 | xfs_trans_set_sync(args->tp); |
| 540 | args->agbno, args->len)) | ||
| 541 | xfs_trans_set_sync(args->tp); | ||
| 542 | } | ||
| 543 | if (!args->isfl) | ||
| 544 | xfs_trans_mod_sb(args->tp, | ||
| 545 | args->wasdel ? XFS_TRANS_SB_RES_FDBLOCKS : | ||
| 546 | XFS_TRANS_SB_FDBLOCKS, -slen); | ||
| 547 | XFS_STATS_INC(xs_allocx); | ||
| 548 | XFS_STATS_ADD(xs_allocb, args->len); | ||
| 549 | } | 554 | } |
| 550 | return 0; | 555 | |
| 556 | if (!args->isfl) { | ||
| 557 | xfs_trans_mod_sb(args->tp, args->wasdel ? | ||
| 558 | XFS_TRANS_SB_RES_FDBLOCKS : | ||
| 559 | XFS_TRANS_SB_FDBLOCKS, | ||
| 560 | -((long)(args->len))); | ||
| 561 | } | ||
| 562 | |||
| 563 | XFS_STATS_INC(xs_allocx); | ||
| 564 | XFS_STATS_ADD(xs_allocb, args->len); | ||
| 565 | return error; | ||
| 551 | } | 566 | } |
| 552 | 567 | ||
| 553 | /* | 568 | /* |
| @@ -693,8 +708,7 @@ xfs_alloc_find_best_extent( | |||
| 693 | if (error) | 708 | if (error) |
| 694 | goto error0; | 709 | goto error0; |
| 695 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 710 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
| 696 | xfs_alloc_compute_aligned(*sbno, *slen, args->alignment, | 711 | xfs_alloc_compute_aligned(args, *sbno, *slen, &bno, slena); |
| 697 | args->minlen, &bno, slena); | ||
| 698 | 712 | ||
| 699 | /* | 713 | /* |
| 700 | * The good extent is closer than this one. | 714 | * The good extent is closer than this one. |
| @@ -866,8 +880,8 @@ xfs_alloc_ag_vextent_near( | |||
| 866 | if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) | 880 | if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) |
| 867 | goto error0; | 881 | goto error0; |
| 868 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 882 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
| 869 | xfs_alloc_compute_aligned(ltbno, ltlen, args->alignment, | 883 | xfs_alloc_compute_aligned(args, ltbno, ltlen, |
| 870 | args->minlen, <bnoa, <lena); | 884 | <bnoa, <lena); |
| 871 | if (ltlena < args->minlen) | 885 | if (ltlena < args->minlen) |
| 872 | continue; | 886 | continue; |
| 873 | args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); | 887 | args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); |
| @@ -987,8 +1001,8 @@ xfs_alloc_ag_vextent_near( | |||
| 987 | if ((error = xfs_alloc_get_rec(bno_cur_lt, <bno, <len, &i))) | 1001 | if ((error = xfs_alloc_get_rec(bno_cur_lt, <bno, <len, &i))) |
| 988 | goto error0; | 1002 | goto error0; |
| 989 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 1003 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
| 990 | xfs_alloc_compute_aligned(ltbno, ltlen, args->alignment, | 1004 | xfs_alloc_compute_aligned(args, ltbno, ltlen, |
| 991 | args->minlen, <bnoa, <lena); | 1005 | <bnoa, <lena); |
| 992 | if (ltlena >= args->minlen) | 1006 | if (ltlena >= args->minlen) |
| 993 | break; | 1007 | break; |
| 994 | if ((error = xfs_btree_decrement(bno_cur_lt, 0, &i))) | 1008 | if ((error = xfs_btree_decrement(bno_cur_lt, 0, &i))) |
| @@ -1003,8 +1017,8 @@ xfs_alloc_ag_vextent_near( | |||
| 1003 | if ((error = xfs_alloc_get_rec(bno_cur_gt, >bno, >len, &i))) | 1017 | if ((error = xfs_alloc_get_rec(bno_cur_gt, >bno, >len, &i))) |
| 1004 | goto error0; | 1018 | goto error0; |
| 1005 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 1019 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
| 1006 | xfs_alloc_compute_aligned(gtbno, gtlen, args->alignment, | 1020 | xfs_alloc_compute_aligned(args, gtbno, gtlen, |
| 1007 | args->minlen, >bnoa, >lena); | 1021 | >bnoa, >lena); |
| 1008 | if (gtlena >= args->minlen) | 1022 | if (gtlena >= args->minlen) |
| 1009 | break; | 1023 | break; |
| 1010 | if ((error = xfs_btree_increment(bno_cur_gt, 0, &i))) | 1024 | if ((error = xfs_btree_increment(bno_cur_gt, 0, &i))) |
| @@ -1183,8 +1197,7 @@ xfs_alloc_ag_vextent_size( | |||
| 1183 | * once aligned; if not, we search left for something better. | 1197 | * once aligned; if not, we search left for something better. |
| 1184 | * This can't happen in the second case above. | 1198 | * This can't happen in the second case above. |
| 1185 | */ | 1199 | */ |
| 1186 | xfs_alloc_compute_aligned(fbno, flen, args->alignment, args->minlen, | 1200 | xfs_alloc_compute_aligned(args, fbno, flen, &rbno, &rlen); |
| 1187 | &rbno, &rlen); | ||
| 1188 | rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); | 1201 | rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); |
| 1189 | XFS_WANT_CORRUPTED_GOTO(rlen == 0 || | 1202 | XFS_WANT_CORRUPTED_GOTO(rlen == 0 || |
| 1190 | (rlen <= flen && rbno + rlen <= fbno + flen), error0); | 1203 | (rlen <= flen && rbno + rlen <= fbno + flen), error0); |
| @@ -1209,8 +1222,8 @@ xfs_alloc_ag_vextent_size( | |||
| 1209 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 1222 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
| 1210 | if (flen < bestrlen) | 1223 | if (flen < bestrlen) |
| 1211 | break; | 1224 | break; |
| 1212 | xfs_alloc_compute_aligned(fbno, flen, args->alignment, | 1225 | xfs_alloc_compute_aligned(args, fbno, flen, |
| 1213 | args->minlen, &rbno, &rlen); | 1226 | &rbno, &rlen); |
| 1214 | rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); | 1227 | rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); |
| 1215 | XFS_WANT_CORRUPTED_GOTO(rlen == 0 || | 1228 | XFS_WANT_CORRUPTED_GOTO(rlen == 0 || |
| 1216 | (rlen <= flen && rbno + rlen <= fbno + flen), | 1229 | (rlen <= flen && rbno + rlen <= fbno + flen), |
| @@ -1388,6 +1401,7 @@ xfs_free_ag_extent( | |||
| 1388 | xfs_mount_t *mp; /* mount point struct for filesystem */ | 1401 | xfs_mount_t *mp; /* mount point struct for filesystem */ |
| 1389 | xfs_agblock_t nbno; /* new starting block of freespace */ | 1402 | xfs_agblock_t nbno; /* new starting block of freespace */ |
| 1390 | xfs_extlen_t nlen; /* new length of freespace */ | 1403 | xfs_extlen_t nlen; /* new length of freespace */ |
| 1404 | xfs_perag_t *pag; /* per allocation group data */ | ||
| 1391 | 1405 | ||
| 1392 | mp = tp->t_mountp; | 1406 | mp = tp->t_mountp; |
| 1393 | /* | 1407 | /* |
| @@ -1586,30 +1600,20 @@ xfs_free_ag_extent( | |||
| 1586 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 1600 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
| 1587 | xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); | 1601 | xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); |
| 1588 | cnt_cur = NULL; | 1602 | cnt_cur = NULL; |
| 1603 | |||
| 1589 | /* | 1604 | /* |
| 1590 | * Update the freespace totals in the ag and superblock. | 1605 | * Update the freespace totals in the ag and superblock. |
| 1591 | */ | 1606 | */ |
| 1592 | { | 1607 | pag = xfs_perag_get(mp, agno); |
| 1593 | xfs_agf_t *agf; | 1608 | error = xfs_alloc_update_counters(tp, pag, agbp, len); |
| 1594 | xfs_perag_t *pag; /* per allocation group data */ | 1609 | xfs_perag_put(pag); |
| 1595 | 1610 | if (error) | |
| 1596 | pag = xfs_perag_get(mp, agno); | 1611 | goto error0; |
| 1597 | pag->pagf_freeblks += len; | 1612 | |
| 1598 | xfs_perag_put(pag); | 1613 | if (!isfl) |
| 1599 | 1614 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (long)len); | |
| 1600 | agf = XFS_BUF_TO_AGF(agbp); | 1615 | XFS_STATS_INC(xs_freex); |
| 1601 | be32_add_cpu(&agf->agf_freeblks, len); | 1616 | XFS_STATS_ADD(xs_freeb, len); |
| 1602 | xfs_trans_agblocks_delta(tp, len); | ||
| 1603 | XFS_WANT_CORRUPTED_GOTO( | ||
| 1604 | be32_to_cpu(agf->agf_freeblks) <= | ||
| 1605 | be32_to_cpu(agf->agf_length), | ||
| 1606 | error0); | ||
| 1607 | xfs_alloc_log_agf(tp, agbp, XFS_AGF_FREEBLKS); | ||
| 1608 | if (!isfl) | ||
| 1609 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (long)len); | ||
| 1610 | XFS_STATS_INC(xs_freex); | ||
| 1611 | XFS_STATS_ADD(xs_freeb, len); | ||
| 1612 | } | ||
| 1613 | 1617 | ||
| 1614 | trace_xfs_free_extent(mp, agno, bno, len, isfl, haveleft, haveright); | 1618 | trace_xfs_free_extent(mp, agno, bno, len, isfl, haveleft, haveright); |
| 1615 | 1619 | ||
| @@ -2391,17 +2395,33 @@ xfs_free_extent( | |||
| 2391 | memset(&args, 0, sizeof(xfs_alloc_arg_t)); | 2395 | memset(&args, 0, sizeof(xfs_alloc_arg_t)); |
| 2392 | args.tp = tp; | 2396 | args.tp = tp; |
| 2393 | args.mp = tp->t_mountp; | 2397 | args.mp = tp->t_mountp; |
| 2398 | |||
| 2399 | /* | ||
| 2400 | * validate that the block number is legal - the enables us to detect | ||
| 2401 | * and handle a silent filesystem corruption rather than crashing. | ||
| 2402 | */ | ||
| 2394 | args.agno = XFS_FSB_TO_AGNO(args.mp, bno); | 2403 | args.agno = XFS_FSB_TO_AGNO(args.mp, bno); |
| 2395 | ASSERT(args.agno < args.mp->m_sb.sb_agcount); | 2404 | if (args.agno >= args.mp->m_sb.sb_agcount) |
| 2405 | return EFSCORRUPTED; | ||
| 2406 | |||
| 2396 | args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno); | 2407 | args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno); |
| 2408 | if (args.agbno >= args.mp->m_sb.sb_agblocks) | ||
| 2409 | return EFSCORRUPTED; | ||
| 2410 | |||
| 2397 | args.pag = xfs_perag_get(args.mp, args.agno); | 2411 | args.pag = xfs_perag_get(args.mp, args.agno); |
| 2398 | if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING))) | 2412 | ASSERT(args.pag); |
| 2413 | |||
| 2414 | error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING); | ||
| 2415 | if (error) | ||
| 2399 | goto error0; | 2416 | goto error0; |
| 2400 | #ifdef DEBUG | 2417 | |
| 2401 | ASSERT(args.agbp != NULL); | 2418 | /* validate the extent size is legal now we have the agf locked */ |
| 2402 | ASSERT((args.agbno + len) <= | 2419 | if (args.agbno + len > |
| 2403 | be32_to_cpu(XFS_BUF_TO_AGF(args.agbp)->agf_length)); | 2420 | be32_to_cpu(XFS_BUF_TO_AGF(args.agbp)->agf_length)) { |
| 2404 | #endif | 2421 | error = EFSCORRUPTED; |
| 2422 | goto error0; | ||
| 2423 | } | ||
| 2424 | |||
| 2405 | error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0); | 2425 | error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0); |
| 2406 | error0: | 2426 | error0: |
| 2407 | xfs_perag_put(args.pag); | 2427 | xfs_perag_put(args.pag); |
