diff options
-rw-r--r-- | fs/xfs/xfs_bmap.c | 302 |
1 files changed, 162 insertions, 140 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index c9492e23447..311cbc1d64c 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -4605,6 +4605,147 @@ xfs_bmapi_delay( } +STATIC int +xfs_bmapi_allocate( + struct xfs_bmalloca *bma, + xfs_extnum_t *lastx, + struct xfs_btree_cur **cur, + xfs_fsblock_t *firstblock, + struct xfs_bmap_free *flist, + int flags, + int *nallocs, + int *logflags) +{ + struct xfs_mount *mp = bma->ip->i_mount; + int whichfork = (flags & XFS_BMAPI_ATTRFORK) ? + XFS_ATTR_FORK : XFS_DATA_FORK; + struct xfs_ifork *ifp = XFS_IFORK_PTR(bma->ip, whichfork); + xfs_fsblock_t abno; + xfs_extlen_t alen; + xfs_fileoff_t aoff; + int error; + int rt; + + rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(bma->ip); + + /* + * For the wasdelay case, we could also just allocate the stuff asked + * for in this bmap call but that wouldn't be as good. + */ + if (bma->wasdel) { + alen = (xfs_extlen_t)bma->gotp->br_blockcount; + aoff = bma->gotp->br_startoff; + if (*lastx != NULLEXTNUM && *lastx) { + xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx - 1), + bma->prevp); + } + } else { + alen = (xfs_extlen_t)XFS_FILBLKS_MIN(bma->alen, MAXEXTLEN); + if (!bma->eof) + alen = (xfs_extlen_t)XFS_FILBLKS_MIN(alen, + bma->gotp->br_startoff - bma->off); + aoff = bma->off; + } + + /* + * Indicate if this is the first user data in the file, or just any + * user data. + */ + if (!(flags & XFS_BMAPI_METADATA)) { + bma->userdata = (aoff == 0) ? + XFS_ALLOC_INITIAL_USER_DATA : XFS_ALLOC_USERDATA; + } + + /* + * Fill in changeable bma fields. + */ + bma->alen = alen; + bma->off = aoff; + bma->firstblock = *firstblock; + bma->minlen = (flags & XFS_BMAPI_CONTIG) ? alen : 1; + bma->low = flist->xbf_low; + bma->aeof = 0; + + /* + * Only want to do the alignment at the eof if it is userdata and + * allocation length is larger than a stripe unit. + */ + if (mp->m_dalign && alen >= mp->m_dalign && + !(flags & XFS_BMAPI_METADATA) && whichfork == XFS_DATA_FORK) { + error = xfs_bmap_isaeof(bma->ip, aoff, whichfork, &bma->aeof); + if (error) + return error; + } + + error = xfs_bmap_alloc(bma); + if (error) + return error; + + /* + * Copy out result fields. + */ + abno = bma->rval; + flist->xbf_low = bma->low; + alen = bma->alen; + aoff = bma->off; + ASSERT(*firstblock == NULLFSBLOCK || + XFS_FSB_TO_AGNO(mp, *firstblock) == + XFS_FSB_TO_AGNO(mp, bma->firstblock) || + (flist->xbf_low && + XFS_FSB_TO_AGNO(mp, *firstblock) < + XFS_FSB_TO_AGNO(mp, bma->firstblock))); + *firstblock = bma->firstblock; + if (*cur) + (*cur)->bc_private.b.firstblock = *firstblock; + if (abno == NULLFSBLOCK) + return 0; + if ((ifp->if_flags & XFS_IFBROOT) && !*cur) { + (*cur) = xfs_bmbt_init_cursor(mp, bma->tp, bma->ip, whichfork); + (*cur)->bc_private.b.firstblock = *firstblock; + (*cur)->bc_private.b.flist = flist; + } + /* + * Bump the number of extents we've allocated + * in this call. + */ + (*nallocs)++; + + if (*cur) + (*cur)->bc_private.b.flags = + bma->wasdel ? XFS_BTCUR_BPRV_WASDEL : 0; + + bma->gotp->br_startoff = aoff; + bma->gotp->br_startblock = abno; + bma->gotp->br_blockcount = alen; + bma->gotp->br_state = XFS_EXT_NORM; + + /* + * A wasdelay extent has been initialized, so shouldn't be flagged + * as unwritten. + */ + if (!bma->wasdel && (flags & XFS_BMAPI_PREALLOC) && + xfs_sb_version_hasextflgbit(&mp->m_sb)) + bma->gotp->br_state = XFS_EXT_UNWRITTEN; + + error = xfs_bmap_add_extent(bma->tp, bma->ip, lastx, cur, bma->gotp, + firstblock, flist, logflags, whichfork); + if (error) + return error; + + /* + * Update our extent pointer, given that xfs_bmap_add_extent might + * have merged it into one of the neighbouring ones. + */ + xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp); + + ASSERT(bma->gotp->br_startoff <= aoff); + ASSERT(bma->gotp->br_startoff + bma->gotp->br_blockcount >= + aoff + alen); + ASSERT(bma->gotp->br_state == XFS_EXT_NORM || + bma->gotp->br_state == XFS_EXT_UNWRITTEN); + return 0; +} + /* * Map file blocks to filesystem blocks. * File range is given by the bno/len pair. @@ -4632,9 +4773,6 @@ xfs_bmapi( int *nmap, /* i/o: mval size/count */ xfs_bmap_free_t *flist) /* i/o: list extents to free */ { - xfs_fsblock_t abno; /* allocated block number */ - xfs_extlen_t alen; /* allocated extent length */ - xfs_fileoff_t aoff; /* allocated file offset */ xfs_bmalloca_t bma = { 0 }; /* args for xfs_bmap_alloc */ xfs_btree_cur_t *cur; /* bmap btree cursor */ xfs_fileoff_t end; /* end of mapped file region */ @@ -4646,7 +4784,6 @@ xfs_bmapi( xfs_extnum_t lastx; /* last useful extent number */ int logflags; /* flags for transaction logging */ xfs_extlen_t minleft; /* min blocks left after allocation */ - xfs_extlen_t minlen; /* min allocation size */ xfs_mount_t *mp; /* xfs mount structure */ int n; /* current extent index */ int nallocs; /* number of extents alloc'd */ @@ -4737,7 +4874,13 @@ xfs_bmapi( n = 0; end = bno + len; obno = bno; - bma.ip = NULL; + + bma.tp = tp; + bma.ip = ip; + bma.prevp = &prev; + bma.gotp = &got; + bma.total = total; + bma.userdata = 0; while (bno < end && n < *nmap) { /* @@ -4753,144 +4896,23 @@ xfs_bmapi( * that we found, if any. */ if (wr && (inhole || wasdelay)) { - /* - * For the wasdelay case, we could also just - * allocate the stuff asked for in this bmap call - * but that wouldn't be as good. - */ - if (wasdelay) { - alen = (xfs_extlen_t)got.br_blockcount; - aoff = got.br_startoff; - if (lastx != NULLEXTNUM && lastx) { - ep = xfs_iext_get_ext(ifp, lastx - 1); - xfs_bmbt_get_all(ep, &prev); - } - } else { - alen = (xfs_extlen_t) - XFS_FILBLKS_MIN(len, MAXEXTLEN); - if (!eof) - alen = (xfs_extlen_t) - XFS_FILBLKS_MIN(alen, - got.br_startoff - bno); - aoff = bno; - } - minlen = (flags & XFS_BMAPI_CONTIG) ? alen : 1; - { - /* - * If first time, allocate and fill in - * once-only bma fields. - */ - if (bma.ip == NULL) { - bma.tp = tp; - bma.ip = ip; - bma.prevp = &prev; - bma.gotp = &got; - bma.total = total; - bma.userdata = 0; - } - /* Indicate if this is the first user data - * in the file, or just any user data. - */ - if (!(flags & XFS_BMAPI_METADATA)) { - bma.userdata = (aoff == 0) ? - XFS_ALLOC_INITIAL_USER_DATA : - XFS_ALLOC_USERDATA; - } - /* - * Fill in changeable bma fields. - */ - bma.eof = eof; - bma.firstblock = *firstblock; - bma.alen = alen; - bma.off = aoff; - bma.conv = !!(flags & XFS_BMAPI_CONVERT); - bma.wasdel = wasdelay; - bma.minlen = minlen; - bma.low = flist->xbf_low; - bma.minleft = minleft; - /* - * Only want to do the alignment at the - * eof if it is userdata and allocation length - * is larger than a stripe unit. - */ - if (mp->m_dalign && alen >= mp->m_dalign && - (!(flags & XFS_BMAPI_METADATA)) && - (whichfork == XFS_DATA_FORK)) { - if ((error = xfs_bmap_isaeof(ip, aoff, - whichfork, &bma.aeof))) - goto error0; - } else - bma.aeof = 0; - /* - * Call allocator. - */ - if ((error = xfs_bmap_alloc(&bma))) - goto error0; - /* - * Copy out result fields. - */ - abno = bma.rval; - if ((flist->xbf_low = bma.low)) - minleft = 0; - alen = bma.alen; - aoff = bma.off; - ASSERT(*firstblock == NULLFSBLOCK || - XFS_FSB_TO_AGNO(mp, *firstblock) == - XFS_FSB_TO_AGNO(mp, bma.firstblock) || - (flist->xbf_low && - XFS_FSB_TO_AGNO(mp, *firstblock) < - XFS_FSB_TO_AGNO(mp, bma.firstblock))); - *firstblock = bma.firstblock; - if (cur) - cur->bc_private.b.firstblock = - *firstblock; - if (abno == NULLFSBLOCK) - break; - if ((ifp->if_flags & XFS_IFBROOT) && !cur) { - cur = xfs_bmbt_init_cursor(mp, tp, - ip, whichfork); - cur->bc_private.b.firstblock = - *firstblock; - cur->bc_private.b.flist = flist; - } - /* - * Bump the number of extents we've allocated - * in this call. - */ - nallocs++; - } - if (cur) - cur->bc_private.b.flags = - wasdelay ? XFS_BTCUR_BPRV_WASDEL : 0; - got.br_startoff = aoff; - got.br_startblock = abno; - got.br_blockcount = alen; - got.br_state = XFS_EXT_NORM; /* assume normal */ - /* - * Determine state of extent, and the filesystem. - * A wasdelay extent has been initialized, so - * shouldn't be flagged as unwritten. - */ - if (wr && xfs_sb_version_hasextflgbit(&mp->m_sb)) { - if (!wasdelay && (flags & XFS_BMAPI_PREALLOC)) - got.br_state = XFS_EXT_UNWRITTEN; - } - error = xfs_bmap_add_extent(tp, ip, &lastx, &cur, &got, - firstblock, flist, &tmp_logflags, - whichfork); + bma.eof = eof; + bma.conv = !!(flags & XFS_BMAPI_CONVERT); + bma.wasdel = wasdelay; + bma.alen = len; + bma.off = bno; + bma.minleft = minleft; + + error = xfs_bmapi_allocate(&bma, &lastx, &cur, + firstblock, flist, flags, &nallocs, + &tmp_logflags); logflags |= tmp_logflags; if (error) goto error0; - ep = xfs_iext_get_ext(ifp, lastx); - xfs_bmbt_get_all(ep, &got); - ASSERT(got.br_startoff <= aoff); - ASSERT(got.br_startoff + got.br_blockcount >= - aoff + alen); - ASSERT(got.br_state == XFS_EXT_NORM || - got.br_state == XFS_EXT_UNWRITTEN); - /* - * Fall down into the found allocated space case. - */ + if (flist && flist->xbf_low) + minleft = 0; + if (bma.rval == NULLFSBLOCK) + break; } else if (inhole) { /* * Reading in a hole. |