diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2017-01-09 10:39:01 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-01-12 05:39:44 -0500 |
commit | b96e4e87d2b0fee921ceafa4f5ae1c90e9121db4 (patch) | |
tree | 551ab60a202153a24f1ed08c5ba762475a1f712f /fs | |
parent | d9c7c9fa600acb0d587678cc71565316d11ec7ad (diff) |
xfs: use the actual AG length when reserving blocks
commit 20e73b000bcded44a91b79429d8fa743247602ad upstream.
We need to use the actual AG length when making per-AG reservations,
since we could otherwise end up reserving more blocks out of the last
AG than there are actual blocks.
Complained-about-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/libxfs/xfs_ag_resv.c | 3 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_refcount_btree.c | 9 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_refcount_btree.h | 3 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_rmap_btree.c | 14 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_rmap_btree.h | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_fsops.c | 14 |
6 files changed, 34 insertions, 12 deletions
diff --git a/fs/xfs/libxfs/xfs_ag_resv.c b/fs/xfs/libxfs/xfs_ag_resv.c index e5ebc3770460..d346d42c54d1 100644 --- a/fs/xfs/libxfs/xfs_ag_resv.c +++ b/fs/xfs/libxfs/xfs_ag_resv.c | |||
@@ -256,6 +256,9 @@ xfs_ag_resv_init( | |||
256 | goto out; | 256 | goto out; |
257 | } | 257 | } |
258 | 258 | ||
259 | ASSERT(xfs_perag_resv(pag, XFS_AG_RESV_METADATA)->ar_reserved + | ||
260 | xfs_perag_resv(pag, XFS_AG_RESV_AGFL)->ar_reserved <= | ||
261 | pag->pagf_freeblks + pag->pagf_flcount); | ||
259 | out: | 262 | out: |
260 | return error; | 263 | return error; |
261 | } | 264 | } |
diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c index 453bb2757ec2..2ba216966002 100644 --- a/fs/xfs/libxfs/xfs_refcount_btree.c +++ b/fs/xfs/libxfs/xfs_refcount_btree.c | |||
@@ -408,13 +408,14 @@ xfs_refcountbt_calc_size( | |||
408 | */ | 408 | */ |
409 | xfs_extlen_t | 409 | xfs_extlen_t |
410 | xfs_refcountbt_max_size( | 410 | xfs_refcountbt_max_size( |
411 | struct xfs_mount *mp) | 411 | struct xfs_mount *mp, |
412 | xfs_agblock_t agblocks) | ||
412 | { | 413 | { |
413 | /* Bail out if we're uninitialized, which can happen in mkfs. */ | 414 | /* Bail out if we're uninitialized, which can happen in mkfs. */ |
414 | if (mp->m_refc_mxr[0] == 0) | 415 | if (mp->m_refc_mxr[0] == 0) |
415 | return 0; | 416 | return 0; |
416 | 417 | ||
417 | return xfs_refcountbt_calc_size(mp, mp->m_sb.sb_agblocks); | 418 | return xfs_refcountbt_calc_size(mp, agblocks); |
418 | } | 419 | } |
419 | 420 | ||
420 | /* | 421 | /* |
@@ -429,22 +430,24 @@ xfs_refcountbt_calc_reserves( | |||
429 | { | 430 | { |
430 | struct xfs_buf *agbp; | 431 | struct xfs_buf *agbp; |
431 | struct xfs_agf *agf; | 432 | struct xfs_agf *agf; |
433 | xfs_agblock_t agblocks; | ||
432 | xfs_extlen_t tree_len; | 434 | xfs_extlen_t tree_len; |
433 | int error; | 435 | int error; |
434 | 436 | ||
435 | if (!xfs_sb_version_hasreflink(&mp->m_sb)) | 437 | if (!xfs_sb_version_hasreflink(&mp->m_sb)) |
436 | return 0; | 438 | return 0; |
437 | 439 | ||
438 | *ask += xfs_refcountbt_max_size(mp); | ||
439 | 440 | ||
440 | error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); | 441 | error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); |
441 | if (error) | 442 | if (error) |
442 | return error; | 443 | return error; |
443 | 444 | ||
444 | agf = XFS_BUF_TO_AGF(agbp); | 445 | agf = XFS_BUF_TO_AGF(agbp); |
446 | agblocks = be32_to_cpu(agf->agf_length); | ||
445 | tree_len = be32_to_cpu(agf->agf_refcount_blocks); | 447 | tree_len = be32_to_cpu(agf->agf_refcount_blocks); |
446 | xfs_buf_relse(agbp); | 448 | xfs_buf_relse(agbp); |
447 | 449 | ||
450 | *ask += xfs_refcountbt_max_size(mp, agblocks); | ||
448 | *used += tree_len; | 451 | *used += tree_len; |
449 | 452 | ||
450 | return error; | 453 | return error; |
diff --git a/fs/xfs/libxfs/xfs_refcount_btree.h b/fs/xfs/libxfs/xfs_refcount_btree.h index 3be7768bd51a..9db008b955b7 100644 --- a/fs/xfs/libxfs/xfs_refcount_btree.h +++ b/fs/xfs/libxfs/xfs_refcount_btree.h | |||
@@ -66,7 +66,8 @@ extern void xfs_refcountbt_compute_maxlevels(struct xfs_mount *mp); | |||
66 | 66 | ||
67 | extern xfs_extlen_t xfs_refcountbt_calc_size(struct xfs_mount *mp, | 67 | extern xfs_extlen_t xfs_refcountbt_calc_size(struct xfs_mount *mp, |
68 | unsigned long long len); | 68 | unsigned long long len); |
69 | extern xfs_extlen_t xfs_refcountbt_max_size(struct xfs_mount *mp); | 69 | extern xfs_extlen_t xfs_refcountbt_max_size(struct xfs_mount *mp, |
70 | xfs_agblock_t agblocks); | ||
70 | 71 | ||
71 | extern int xfs_refcountbt_calc_reserves(struct xfs_mount *mp, | 72 | extern int xfs_refcountbt_calc_reserves(struct xfs_mount *mp, |
72 | xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used); | 73 | xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used); |
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c index 83e672ff7577..33a28efc3085 100644 --- a/fs/xfs/libxfs/xfs_rmap_btree.c +++ b/fs/xfs/libxfs/xfs_rmap_btree.c | |||
@@ -549,13 +549,14 @@ xfs_rmapbt_calc_size( | |||
549 | */ | 549 | */ |
550 | xfs_extlen_t | 550 | xfs_extlen_t |
551 | xfs_rmapbt_max_size( | 551 | xfs_rmapbt_max_size( |
552 | struct xfs_mount *mp) | 552 | struct xfs_mount *mp, |
553 | xfs_agblock_t agblocks) | ||
553 | { | 554 | { |
554 | /* Bail out if we're uninitialized, which can happen in mkfs. */ | 555 | /* Bail out if we're uninitialized, which can happen in mkfs. */ |
555 | if (mp->m_rmap_mxr[0] == 0) | 556 | if (mp->m_rmap_mxr[0] == 0) |
556 | return 0; | 557 | return 0; |
557 | 558 | ||
558 | return xfs_rmapbt_calc_size(mp, mp->m_sb.sb_agblocks); | 559 | return xfs_rmapbt_calc_size(mp, agblocks); |
559 | } | 560 | } |
560 | 561 | ||
561 | /* | 562 | /* |
@@ -570,25 +571,24 @@ xfs_rmapbt_calc_reserves( | |||
570 | { | 571 | { |
571 | struct xfs_buf *agbp; | 572 | struct xfs_buf *agbp; |
572 | struct xfs_agf *agf; | 573 | struct xfs_agf *agf; |
573 | xfs_extlen_t pool_len; | 574 | xfs_agblock_t agblocks; |
574 | xfs_extlen_t tree_len; | 575 | xfs_extlen_t tree_len; |
575 | int error; | 576 | int error; |
576 | 577 | ||
577 | if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) | 578 | if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) |
578 | return 0; | 579 | return 0; |
579 | 580 | ||
580 | /* Reserve 1% of the AG or enough for 1 block per record. */ | ||
581 | pool_len = max(mp->m_sb.sb_agblocks / 100, xfs_rmapbt_max_size(mp)); | ||
582 | *ask += pool_len; | ||
583 | |||
584 | error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); | 581 | error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); |
585 | if (error) | 582 | if (error) |
586 | return error; | 583 | return error; |
587 | 584 | ||
588 | agf = XFS_BUF_TO_AGF(agbp); | 585 | agf = XFS_BUF_TO_AGF(agbp); |
586 | agblocks = be32_to_cpu(agf->agf_length); | ||
589 | tree_len = be32_to_cpu(agf->agf_rmap_blocks); | 587 | tree_len = be32_to_cpu(agf->agf_rmap_blocks); |
590 | xfs_buf_relse(agbp); | 588 | xfs_buf_relse(agbp); |
591 | 589 | ||
590 | /* Reserve 1% of the AG or enough for 1 block per record. */ | ||
591 | *ask += max(agblocks / 100, xfs_rmapbt_max_size(mp, agblocks)); | ||
592 | *used += tree_len; | 592 | *used += tree_len; |
593 | 593 | ||
594 | return error; | 594 | return error; |
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h index 2a9ac472fb15..19c08e933049 100644 --- a/fs/xfs/libxfs/xfs_rmap_btree.h +++ b/fs/xfs/libxfs/xfs_rmap_btree.h | |||
@@ -60,7 +60,8 @@ extern void xfs_rmapbt_compute_maxlevels(struct xfs_mount *mp); | |||
60 | 60 | ||
61 | extern xfs_extlen_t xfs_rmapbt_calc_size(struct xfs_mount *mp, | 61 | extern xfs_extlen_t xfs_rmapbt_calc_size(struct xfs_mount *mp, |
62 | unsigned long long len); | 62 | unsigned long long len); |
63 | extern xfs_extlen_t xfs_rmapbt_max_size(struct xfs_mount *mp); | 63 | extern xfs_extlen_t xfs_rmapbt_max_size(struct xfs_mount *mp, |
64 | xfs_agblock_t agblocks); | ||
64 | 65 | ||
65 | extern int xfs_rmapbt_calc_reserves(struct xfs_mount *mp, | 66 | extern int xfs_rmapbt_calc_reserves(struct xfs_mount *mp, |
66 | xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used); | 67 | xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used); |
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 93d12fa2670d..242e8091296d 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c | |||
@@ -631,6 +631,20 @@ xfs_growfs_data_private( | |||
631 | xfs_set_low_space_thresholds(mp); | 631 | xfs_set_low_space_thresholds(mp); |
632 | mp->m_alloc_set_aside = xfs_alloc_set_aside(mp); | 632 | mp->m_alloc_set_aside = xfs_alloc_set_aside(mp); |
633 | 633 | ||
634 | /* | ||
635 | * If we expanded the last AG, free the per-AG reservation | ||
636 | * so we can reinitialize it with the new size. | ||
637 | */ | ||
638 | if (new) { | ||
639 | struct xfs_perag *pag; | ||
640 | |||
641 | pag = xfs_perag_get(mp, agno); | ||
642 | error = xfs_ag_resv_free(pag); | ||
643 | xfs_perag_put(pag); | ||
644 | if (error) | ||
645 | goto out; | ||
646 | } | ||
647 | |||
634 | /* Reserve AG metadata blocks. */ | 648 | /* Reserve AG metadata blocks. */ |
635 | error = xfs_fs_reserve_ag_blocks(mp); | 649 | error = xfs_fs_reserve_ag_blocks(mp); |
636 | if (error && error != -ENOSPC) | 650 | if (error && error != -ENOSPC) |