aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_bmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_bmap.c')
-rw-r--r--fs/xfs/xfs_bmap.c225
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 */
234STATIC void 234STATIC void
235xfs_bmap_forkoff_reset( 235xfs_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 */
1676int 1675int
1677xfs_bmap_last_offset( 1676xfs_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
3518static int
3519xfs_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
3546out:
3547 xfs_perag_put(pag);
3548 return error;
3549}
3550
3551static void
3552xfs_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
3520STATIC int 3579STATIC int
3521xfs_bmap_btalloc_nullfb( 3580xfs_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 &notinit);
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) 3613STATIC int
3611 args->minlen = ap->minlen; 3614xfs_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, &notinit);
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 &notinit);
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
5565del_cursor: 5601del_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}