xfs: factor extent allocation out of xfs_bmapi
[pandora-kernel.git] / fs / xfs / xfs_bmap.c
index c9492e2..311cbc1 100644 (file)
@@ -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.