diff options
Diffstat (limited to 'fs/xfs/xfs_bmap.c')
-rw-r--r-- | fs/xfs/xfs_bmap.c | 225 |
1 files changed, 130 insertions, 95 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 5b6092ef51ef..1ff0da6e2bf9 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -94,7 +94,7 @@ xfs_bmap_compute_maxlevels( | |||
94 | maxleafents = MAXAEXTNUM; | 94 | maxleafents = MAXAEXTNUM; |
95 | sz = XFS_BMDR_SPACE_CALC(MINABTPTRS); | 95 | sz = XFS_BMDR_SPACE_CALC(MINABTPTRS); |
96 | } | 96 | } |
97 | maxrootrecs = xfs_bmdr_maxrecs(mp, sz, 0); | 97 | maxrootrecs = xfs_bmdr_maxrecs(sz, 0); |
98 | minleafrecs = mp->m_bmap_dmnr[0]; | 98 | minleafrecs = mp->m_bmap_dmnr[0]; |
99 | minnoderecs = mp->m_bmap_dmnr[1]; | 99 | minnoderecs = mp->m_bmap_dmnr[1]; |
100 | maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; | 100 | maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; |
@@ -233,7 +233,6 @@ xfs_default_attroffset( | |||
233 | */ | 233 | */ |
234 | STATIC void | 234 | STATIC void |
235 | xfs_bmap_forkoff_reset( | 235 | xfs_bmap_forkoff_reset( |
236 | xfs_mount_t *mp, | ||
237 | xfs_inode_t *ip, | 236 | xfs_inode_t *ip, |
238 | int whichfork) | 237 | int whichfork) |
239 | { | 238 | { |
@@ -905,7 +904,7 @@ xfs_bmap_local_to_extents_empty( | |||
905 | ASSERT(ifp->if_bytes == 0); | 904 | ASSERT(ifp->if_bytes == 0); |
906 | ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0); | 905 | ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0); |
907 | 906 | ||
908 | xfs_bmap_forkoff_reset(ip->i_mount, ip, whichfork); | 907 | xfs_bmap_forkoff_reset(ip, whichfork); |
909 | ifp->if_flags &= ~XFS_IFINLINE; | 908 | ifp->if_flags &= ~XFS_IFINLINE; |
910 | ifp->if_flags |= XFS_IFEXTENTS; | 909 | ifp->if_flags |= XFS_IFEXTENTS; |
911 | XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); | 910 | XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); |
@@ -1675,7 +1674,6 @@ xfs_bmap_isaeof( | |||
1675 | */ | 1674 | */ |
1676 | int | 1675 | int |
1677 | xfs_bmap_last_offset( | 1676 | xfs_bmap_last_offset( |
1678 | struct xfs_trans *tp, | ||
1679 | struct xfs_inode *ip, | 1677 | struct xfs_inode *ip, |
1680 | xfs_fileoff_t *last_block, | 1678 | xfs_fileoff_t *last_block, |
1681 | int whichfork) | 1679 | int whichfork) |
@@ -3517,6 +3515,67 @@ xfs_bmap_adjacent( | |||
3517 | #undef ISVALID | 3515 | #undef ISVALID |
3518 | } | 3516 | } |
3519 | 3517 | ||
3518 | static int | ||
3519 | xfs_bmap_longest_free_extent( | ||
3520 | struct xfs_trans *tp, | ||
3521 | xfs_agnumber_t ag, | ||
3522 | xfs_extlen_t *blen, | ||
3523 | int *notinit) | ||
3524 | { | ||
3525 | struct xfs_mount *mp = tp->t_mountp; | ||
3526 | struct xfs_perag *pag; | ||
3527 | xfs_extlen_t longest; | ||
3528 | int error = 0; | ||
3529 | |||
3530 | pag = xfs_perag_get(mp, ag); | ||
3531 | if (!pag->pagf_init) { | ||
3532 | error = xfs_alloc_pagf_init(mp, tp, ag, XFS_ALLOC_FLAG_TRYLOCK); | ||
3533 | if (error) | ||
3534 | goto out; | ||
3535 | |||
3536 | if (!pag->pagf_init) { | ||
3537 | *notinit = 1; | ||
3538 | goto out; | ||
3539 | } | ||
3540 | } | ||
3541 | |||
3542 | longest = xfs_alloc_longest_free_extent(mp, pag); | ||
3543 | if (*blen < longest) | ||
3544 | *blen = longest; | ||
3545 | |||
3546 | out: | ||
3547 | xfs_perag_put(pag); | ||
3548 | return error; | ||
3549 | } | ||
3550 | |||
3551 | static void | ||
3552 | xfs_bmap_select_minlen( | ||
3553 | struct xfs_bmalloca *ap, | ||
3554 | struct xfs_alloc_arg *args, | ||
3555 | xfs_extlen_t *blen, | ||
3556 | int notinit) | ||
3557 | { | ||
3558 | if (notinit || *blen < ap->minlen) { | ||
3559 | /* | ||
3560 | * Since we did a BUF_TRYLOCK above, it is possible that | ||
3561 | * there is space for this request. | ||
3562 | */ | ||
3563 | args->minlen = ap->minlen; | ||
3564 | } else if (*blen < args->maxlen) { | ||
3565 | /* | ||
3566 | * If the best seen length is less than the request length, | ||
3567 | * use the best as the minimum. | ||
3568 | */ | ||
3569 | args->minlen = *blen; | ||
3570 | } else { | ||
3571 | /* | ||
3572 | * Otherwise we've seen an extent as big as maxlen, use that | ||
3573 | * as the minimum. | ||
3574 | */ | ||
3575 | args->minlen = args->maxlen; | ||
3576 | } | ||
3577 | } | ||
3578 | |||
3520 | STATIC int | 3579 | STATIC int |
3521 | xfs_bmap_btalloc_nullfb( | 3580 | xfs_bmap_btalloc_nullfb( |
3522 | struct xfs_bmalloca *ap, | 3581 | struct xfs_bmalloca *ap, |
@@ -3524,111 +3583,74 @@ xfs_bmap_btalloc_nullfb( | |||
3524 | xfs_extlen_t *blen) | 3583 | xfs_extlen_t *blen) |
3525 | { | 3584 | { |
3526 | struct xfs_mount *mp = ap->ip->i_mount; | 3585 | struct xfs_mount *mp = ap->ip->i_mount; |
3527 | struct xfs_perag *pag; | ||
3528 | xfs_agnumber_t ag, startag; | 3586 | xfs_agnumber_t ag, startag; |
3529 | int notinit = 0; | 3587 | int notinit = 0; |
3530 | int error; | 3588 | int error; |
3531 | 3589 | ||
3532 | if (ap->userdata && xfs_inode_is_filestream(ap->ip)) | 3590 | args->type = XFS_ALLOCTYPE_START_BNO; |
3533 | args->type = XFS_ALLOCTYPE_NEAR_BNO; | ||
3534 | else | ||
3535 | args->type = XFS_ALLOCTYPE_START_BNO; | ||
3536 | args->total = ap->total; | 3591 | args->total = ap->total; |
3537 | 3592 | ||
3538 | /* | ||
3539 | * Search for an allocation group with a single extent large enough | ||
3540 | * for the request. If one isn't found, then adjust the minimum | ||
3541 | * allocation size to the largest space found. | ||
3542 | */ | ||
3543 | startag = ag = XFS_FSB_TO_AGNO(mp, args->fsbno); | 3593 | startag = ag = XFS_FSB_TO_AGNO(mp, args->fsbno); |
3544 | if (startag == NULLAGNUMBER) | 3594 | if (startag == NULLAGNUMBER) |
3545 | startag = ag = 0; | 3595 | startag = ag = 0; |
3546 | 3596 | ||
3547 | pag = xfs_perag_get(mp, ag); | ||
3548 | while (*blen < args->maxlen) { | 3597 | while (*blen < args->maxlen) { |
3549 | if (!pag->pagf_init) { | 3598 | error = xfs_bmap_longest_free_extent(args->tp, ag, blen, |
3550 | error = xfs_alloc_pagf_init(mp, args->tp, ag, | 3599 | ¬init); |
3551 | XFS_ALLOC_FLAG_TRYLOCK); | 3600 | if (error) |
3552 | if (error) { | 3601 | return error; |
3553 | xfs_perag_put(pag); | ||
3554 | return error; | ||
3555 | } | ||
3556 | } | ||
3557 | |||
3558 | /* | ||
3559 | * See xfs_alloc_fix_freelist... | ||
3560 | */ | ||
3561 | if (pag->pagf_init) { | ||
3562 | xfs_extlen_t longest; | ||
3563 | longest = xfs_alloc_longest_free_extent(mp, pag); | ||
3564 | if (*blen < longest) | ||
3565 | *blen = longest; | ||
3566 | } else | ||
3567 | notinit = 1; | ||
3568 | |||
3569 | if (xfs_inode_is_filestream(ap->ip)) { | ||
3570 | if (*blen >= args->maxlen) | ||
3571 | break; | ||
3572 | |||
3573 | if (ap->userdata) { | ||
3574 | /* | ||
3575 | * If startag is an invalid AG, we've | ||
3576 | * come here once before and | ||
3577 | * xfs_filestream_new_ag picked the | ||
3578 | * best currently available. | ||
3579 | * | ||
3580 | * Don't continue looping, since we | ||
3581 | * could loop forever. | ||
3582 | */ | ||
3583 | if (startag == NULLAGNUMBER) | ||
3584 | break; | ||
3585 | |||
3586 | error = xfs_filestream_new_ag(ap, &ag); | ||
3587 | xfs_perag_put(pag); | ||
3588 | if (error) | ||
3589 | return error; | ||
3590 | 3602 | ||
3591 | /* loop again to set 'blen'*/ | ||
3592 | startag = NULLAGNUMBER; | ||
3593 | pag = xfs_perag_get(mp, ag); | ||
3594 | continue; | ||
3595 | } | ||
3596 | } | ||
3597 | if (++ag == mp->m_sb.sb_agcount) | 3603 | if (++ag == mp->m_sb.sb_agcount) |
3598 | ag = 0; | 3604 | ag = 0; |
3599 | if (ag == startag) | 3605 | if (ag == startag) |
3600 | break; | 3606 | break; |
3601 | xfs_perag_put(pag); | ||
3602 | pag = xfs_perag_get(mp, ag); | ||
3603 | } | 3607 | } |
3604 | xfs_perag_put(pag); | ||
3605 | 3608 | ||
3606 | /* | 3609 | xfs_bmap_select_minlen(ap, args, blen, notinit); |
3607 | * Since the above loop did a BUF_TRYLOCK, it is | 3610 | return 0; |
3608 | * possible that there is space for this request. | 3611 | } |
3609 | */ | 3612 | |
3610 | if (notinit || *blen < ap->minlen) | 3613 | STATIC int |
3611 | args->minlen = ap->minlen; | 3614 | xfs_bmap_btalloc_filestreams( |
3612 | /* | 3615 | struct xfs_bmalloca *ap, |
3613 | * If the best seen length is less than the request | 3616 | struct xfs_alloc_arg *args, |
3614 | * length, use the best as the minimum. | 3617 | xfs_extlen_t *blen) |
3615 | */ | 3618 | { |
3616 | else if (*blen < args->maxlen) | 3619 | struct xfs_mount *mp = ap->ip->i_mount; |
3617 | args->minlen = *blen; | 3620 | xfs_agnumber_t ag; |
3618 | /* | 3621 | int notinit = 0; |
3619 | * Otherwise we've seen an extent as big as maxlen, | 3622 | int error; |
3620 | * use that as the minimum. | 3623 | |
3621 | */ | 3624 | args->type = XFS_ALLOCTYPE_NEAR_BNO; |
3622 | else | 3625 | args->total = ap->total; |
3623 | args->minlen = args->maxlen; | 3626 | |
3627 | ag = XFS_FSB_TO_AGNO(mp, args->fsbno); | ||
3628 | if (ag == NULLAGNUMBER) | ||
3629 | ag = 0; | ||
3630 | |||
3631 | error = xfs_bmap_longest_free_extent(args->tp, ag, blen, ¬init); | ||
3632 | if (error) | ||
3633 | return error; | ||
3634 | |||
3635 | if (*blen < args->maxlen) { | ||
3636 | error = xfs_filestream_new_ag(ap, &ag); | ||
3637 | if (error) | ||
3638 | return error; | ||
3639 | |||
3640 | error = xfs_bmap_longest_free_extent(args->tp, ag, blen, | ||
3641 | ¬init); | ||
3642 | if (error) | ||
3643 | return error; | ||
3644 | |||
3645 | } | ||
3646 | |||
3647 | xfs_bmap_select_minlen(ap, args, blen, notinit); | ||
3624 | 3648 | ||
3625 | /* | 3649 | /* |
3626 | * set the failure fallback case to look in the selected | 3650 | * Set the failure fallback case to look in the selected AG as stream |
3627 | * AG as the stream may have moved. | 3651 | * may have moved. |
3628 | */ | 3652 | */ |
3629 | if (xfs_inode_is_filestream(ap->ip)) | 3653 | ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0); |
3630 | ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0); | ||
3631 | |||
3632 | return 0; | 3654 | return 0; |
3633 | } | 3655 | } |
3634 | 3656 | ||
@@ -3708,7 +3730,15 @@ xfs_bmap_btalloc( | |||
3708 | args.firstblock = *ap->firstblock; | 3730 | args.firstblock = *ap->firstblock; |
3709 | blen = 0; | 3731 | blen = 0; |
3710 | if (nullfb) { | 3732 | if (nullfb) { |
3711 | error = xfs_bmap_btalloc_nullfb(ap, &args, &blen); | 3733 | /* |
3734 | * Search for an allocation group with a single extent large | ||
3735 | * enough for the request. If one isn't found, then adjust | ||
3736 | * the minimum allocation size to the largest space found. | ||
3737 | */ | ||
3738 | if (ap->userdata && xfs_inode_is_filestream(ap->ip)) | ||
3739 | error = xfs_bmap_btalloc_filestreams(ap, &args, &blen); | ||
3740 | else | ||
3741 | error = xfs_bmap_btalloc_nullfb(ap, &args, &blen); | ||
3712 | if (error) | 3742 | if (error) |
3713 | return error; | 3743 | return error; |
3714 | } else if (ap->flist->xbf_low) { | 3744 | } else if (ap->flist->xbf_low) { |
@@ -5413,6 +5443,7 @@ xfs_bmap_shift_extents( | |||
5413 | int whichfork = XFS_DATA_FORK; | 5443 | int whichfork = XFS_DATA_FORK; |
5414 | int logflags; | 5444 | int logflags; |
5415 | xfs_filblks_t blockcount = 0; | 5445 | xfs_filblks_t blockcount = 0; |
5446 | int total_extents; | ||
5416 | 5447 | ||
5417 | if (unlikely(XFS_TEST_ERROR( | 5448 | if (unlikely(XFS_TEST_ERROR( |
5418 | (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && | 5449 | (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && |
@@ -5429,7 +5460,6 @@ xfs_bmap_shift_extents( | |||
5429 | ASSERT(current_ext != NULL); | 5460 | ASSERT(current_ext != NULL); |
5430 | 5461 | ||
5431 | ifp = XFS_IFORK_PTR(ip, whichfork); | 5462 | ifp = XFS_IFORK_PTR(ip, whichfork); |
5432 | |||
5433 | if (!(ifp->if_flags & XFS_IFEXTENTS)) { | 5463 | if (!(ifp->if_flags & XFS_IFEXTENTS)) { |
5434 | /* Read in all the extents */ | 5464 | /* Read in all the extents */ |
5435 | error = xfs_iread_extents(tp, ip, whichfork); | 5465 | error = xfs_iread_extents(tp, ip, whichfork); |
@@ -5456,7 +5486,6 @@ xfs_bmap_shift_extents( | |||
5456 | 5486 | ||
5457 | /* We are going to change core inode */ | 5487 | /* We are going to change core inode */ |
5458 | logflags = XFS_ILOG_CORE; | 5488 | logflags = XFS_ILOG_CORE; |
5459 | |||
5460 | if (ifp->if_flags & XFS_IFBROOT) { | 5489 | if (ifp->if_flags & XFS_IFBROOT) { |
5461 | cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); | 5490 | cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); |
5462 | cur->bc_private.b.firstblock = *firstblock; | 5491 | cur->bc_private.b.firstblock = *firstblock; |
@@ -5467,8 +5496,14 @@ xfs_bmap_shift_extents( | |||
5467 | logflags |= XFS_ILOG_DEXT; | 5496 | logflags |= XFS_ILOG_DEXT; |
5468 | } | 5497 | } |
5469 | 5498 | ||
5470 | while (nexts++ < num_exts && | 5499 | /* |
5471 | *current_ext < XFS_IFORK_NEXTENTS(ip, whichfork)) { | 5500 | * There may be delalloc extents in the data fork before the range we |
5501 | * are collapsing out, so we cannot | ||
5502 | * use the count of real extents here. Instead we have to calculate it | ||
5503 | * from the incore fork. | ||
5504 | */ | ||
5505 | total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); | ||
5506 | while (nexts++ < num_exts && *current_ext < total_extents) { | ||
5472 | 5507 | ||
5473 | gotp = xfs_iext_get_ext(ifp, *current_ext); | 5508 | gotp = xfs_iext_get_ext(ifp, *current_ext); |
5474 | xfs_bmbt_get_all(gotp, &got); | 5509 | xfs_bmbt_get_all(gotp, &got); |
@@ -5556,10 +5591,11 @@ xfs_bmap_shift_extents( | |||
5556 | } | 5591 | } |
5557 | 5592 | ||
5558 | (*current_ext)++; | 5593 | (*current_ext)++; |
5594 | total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); | ||
5559 | } | 5595 | } |
5560 | 5596 | ||
5561 | /* Check if we are done */ | 5597 | /* Check if we are done */ |
5562 | if (*current_ext == XFS_IFORK_NEXTENTS(ip, whichfork)) | 5598 | if (*current_ext == total_extents) |
5563 | *done = 1; | 5599 | *done = 1; |
5564 | 5600 | ||
5565 | del_cursor: | 5601 | del_cursor: |
@@ -5568,6 +5604,5 @@ del_cursor: | |||
5568 | error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); | 5604 | error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); |
5569 | 5605 | ||
5570 | xfs_trans_log_inode(tp, ip, logflags); | 5606 | xfs_trans_log_inode(tp, ip, logflags); |
5571 | |||
5572 | return error; | 5607 | return error; |
5573 | } | 5608 | } |