xfs: support min/max agbno args in block allocator
[cascardo/linux.git] / fs / xfs / libxfs / xfs_alloc.c
index a6fbf44..bc78ac0 100644 (file)
@@ -149,13 +149,27 @@ xfs_alloc_compute_aligned(
 {
        xfs_agblock_t   bno;
        xfs_extlen_t    len;
+       xfs_extlen_t    diff;
 
        /* Trim busy sections out of found extent */
        xfs_extent_busy_trim(args, foundbno, foundlen, &bno, &len);
 
+       /*
+        * If we have a largish extent that happens to start before min_agbno,
+        * see if we can shift it into range...
+        */
+       if (bno < args->min_agbno && bno + len > args->min_agbno) {
+               diff = args->min_agbno - bno;
+               if (len > diff) {
+                       bno += diff;
+                       len -= diff;
+               }
+       }
+
        if (args->alignment > 1 && len >= args->minlen) {
                xfs_agblock_t   aligned_bno = roundup(bno, args->alignment);
-               xfs_extlen_t    diff = aligned_bno - bno;
+
+               diff = aligned_bno - bno;
 
                *resbno = aligned_bno;
                *reslen = diff >= len ? 0 : len - diff;
@@ -260,6 +274,7 @@ xfs_alloc_fix_len(
                rlen = rlen - (k - args->mod);
        else
                rlen = rlen - args->prod + (args->mod - k);
+       /* casts to (int) catch length underflows */
        if ((int)rlen < (int)args->minlen)
                return;
        ASSERT(rlen >= args->minlen && rlen <= args->maxlen);
@@ -286,7 +301,8 @@ xfs_alloc_fix_minleft(
        if (diff >= 0)
                return 1;
        args->len += diff;              /* shrink the allocated space */
-       if (args->len >= args->minlen)
+       /* casts to (int) catch length underflows */
+       if ((int)args->len >= (int)args->minlen)
                return 1;
        args->agbno = NULLAGBLOCK;
        return 0;
@@ -315,6 +331,9 @@ xfs_alloc_fixup_trees(
        xfs_agblock_t   nfbno2;         /* second new free startblock */
        xfs_extlen_t    nflen1=0;       /* first new free length */
        xfs_extlen_t    nflen2=0;       /* second new free length */
+       struct xfs_mount *mp;
+
+       mp = cnt_cur->bc_mp;
 
        /*
         * Look up the record in the by-size tree if necessary.
@@ -323,13 +342,13 @@ xfs_alloc_fixup_trees(
 #ifdef DEBUG
                if ((error = xfs_alloc_get_rec(cnt_cur, &nfbno1, &nflen1, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(
+               XFS_WANT_CORRUPTED_RETURN(mp,
                        i == 1 && nfbno1 == fbno && nflen1 == flen);
 #endif
        } else {
                if ((error = xfs_alloc_lookup_eq(cnt_cur, fbno, flen, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(i == 1);
+               XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
        }
        /*
         * Look up the record in the by-block tree if necessary.
@@ -338,13 +357,13 @@ xfs_alloc_fixup_trees(
 #ifdef DEBUG
                if ((error = xfs_alloc_get_rec(bno_cur, &nfbno1, &nflen1, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(
+               XFS_WANT_CORRUPTED_RETURN(mp,
                        i == 1 && nfbno1 == fbno && nflen1 == flen);
 #endif
        } else {
                if ((error = xfs_alloc_lookup_eq(bno_cur, fbno, flen, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(i == 1);
+               XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
        }
 
 #ifdef DEBUG
@@ -355,7 +374,7 @@ xfs_alloc_fixup_trees(
                bnoblock = XFS_BUF_TO_BLOCK(bno_cur->bc_bufs[0]);
                cntblock = XFS_BUF_TO_BLOCK(cnt_cur->bc_bufs[0]);
 
-               XFS_WANT_CORRUPTED_RETURN(
+               XFS_WANT_CORRUPTED_RETURN(mp,
                        bnoblock->bb_numrecs == cntblock->bb_numrecs);
        }
 #endif
@@ -386,25 +405,25 @@ xfs_alloc_fixup_trees(
         */
        if ((error = xfs_btree_delete(cnt_cur, &i)))
                return error;
-       XFS_WANT_CORRUPTED_RETURN(i == 1);
+       XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
        /*
         * Add new by-size btree entry(s).
         */
        if (nfbno1 != NULLAGBLOCK) {
                if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno1, nflen1, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(i == 0);
+               XFS_WANT_CORRUPTED_RETURN(mp, i == 0);
                if ((error = xfs_btree_insert(cnt_cur, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(i == 1);
+               XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
        }
        if (nfbno2 != NULLAGBLOCK) {
                if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno2, nflen2, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(i == 0);
+               XFS_WANT_CORRUPTED_RETURN(mp, i == 0);
                if ((error = xfs_btree_insert(cnt_cur, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(i == 1);
+               XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
        }
        /*
         * Fix up the by-block btree entry(s).
@@ -415,7 +434,7 @@ xfs_alloc_fixup_trees(
                 */
                if ((error = xfs_btree_delete(bno_cur, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(i == 1);
+               XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
        } else {
                /*
                 * Update the by-block entry to start later|be shorter.
@@ -429,10 +448,10 @@ xfs_alloc_fixup_trees(
                 */
                if ((error = xfs_alloc_lookup_eq(bno_cur, nfbno2, nflen2, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(i == 0);
+               XFS_WANT_CORRUPTED_RETURN(mp, i == 0);
                if ((error = xfs_btree_insert(bno_cur, &i)))
                        return error;
-               XFS_WANT_CORRUPTED_RETURN(i == 1);
+               XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
        }
        return 0;
 }
@@ -682,7 +701,7 @@ xfs_alloc_ag_vextent_exact(
        error = xfs_alloc_get_rec(bno_cur, &fbno, &flen, &i);
        if (error)
                goto error0;
-       XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+       XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
        ASSERT(fbno <= args->agbno);
 
        /*
@@ -783,16 +802,20 @@ xfs_alloc_find_best_extent(
                error = xfs_alloc_get_rec(*scur, sbno, slen, &i);
                if (error)
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
                xfs_alloc_compute_aligned(args, *sbno, *slen, sbnoa, slena);
 
                /*
                 * The good extent is closer than this one.
                 */
                if (!dir) {
+                       if (*sbnoa > args->max_agbno)
+                               goto out_use_good;
                        if (*sbnoa >= args->agbno + gdiff)
                                goto out_use_good;
                } else {
+                       if (*sbnoa < args->min_agbno)
+                               goto out_use_good;
                        if (*sbnoa <= args->agbno - gdiff)
                                goto out_use_good;
                }
@@ -879,6 +902,17 @@ xfs_alloc_ag_vextent_near(
        dofirst = prandom_u32() & 1;
 #endif
 
+       /* handle unitialized agbno range so caller doesn't have to */
+       if (!args->min_agbno && !args->max_agbno)
+               args->max_agbno = args->mp->m_sb.sb_agblocks - 1;
+       ASSERT(args->min_agbno <= args->max_agbno);
+
+       /* clamp agbno to the range if it's outside */
+       if (args->agbno < args->min_agbno)
+               args->agbno = args->min_agbno;
+       if (args->agbno > args->max_agbno)
+               args->agbno = args->max_agbno;
+
 restart:
        bno_cur_lt = NULL;
        bno_cur_gt = NULL;
@@ -946,7 +980,7 @@ restart:
                                if ((error = xfs_alloc_get_rec(cnt_cur, &ltbno,
                                                &ltlen, &i)))
                                        goto error0;
-                               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+                               XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
                                if (ltlen >= args->minlen)
                                        break;
                                if ((error = xfs_btree_increment(cnt_cur, 0, &i)))
@@ -966,11 +1000,13 @@ restart:
                         */
                        if ((error = xfs_alloc_get_rec(cnt_cur, &ltbno, &ltlen, &i)))
                                goto error0;
-                       XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+                       XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
                        xfs_alloc_compute_aligned(args, ltbno, ltlen,
                                                  &ltbnoa, &ltlena);
                        if (ltlena < args->minlen)
                                continue;
+                       if (ltbnoa < args->min_agbno || ltbnoa > args->max_agbno)
+                               continue;
                        args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen);
                        xfs_alloc_fix_len(args);
                        ASSERT(args->len >= args->minlen);
@@ -999,7 +1035,7 @@ restart:
                cnt_cur->bc_ptrs[0] = besti;
                if ((error = xfs_alloc_get_rec(cnt_cur, &ltbno, &ltlen, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
                ASSERT(ltbno + ltlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
                args->len = blen;
                if (!xfs_alloc_fix_minleft(args)) {
@@ -1088,14 +1124,14 @@ restart:
                if (bno_cur_lt) {
                        if ((error = xfs_alloc_get_rec(bno_cur_lt, &ltbno, &ltlen, &i)))
                                goto error0;
-                       XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+                       XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
                        xfs_alloc_compute_aligned(args, ltbno, ltlen,
                                                  &ltbnoa, &ltlena);
-                       if (ltlena >= args->minlen)
+                       if (ltlena >= args->minlen && ltbnoa >= args->min_agbno)
                                break;
                        if ((error = xfs_btree_decrement(bno_cur_lt, 0, &i)))
                                goto error0;
-                       if (!i) {
+                       if (!i || ltbnoa < args->min_agbno) {
                                xfs_btree_del_cursor(bno_cur_lt,
                                                     XFS_BTREE_NOERROR);
                                bno_cur_lt = NULL;
@@ -1104,14 +1140,14 @@ restart:
                if (bno_cur_gt) {
                        if ((error = xfs_alloc_get_rec(bno_cur_gt, &gtbno, &gtlen, &i)))
                                goto error0;
-                       XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+                       XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
                        xfs_alloc_compute_aligned(args, gtbno, gtlen,
                                                  &gtbnoa, &gtlena);
-                       if (gtlena >= args->minlen)
+                       if (gtlena >= args->minlen && gtbnoa <= args->max_agbno)
                                break;
                        if ((error = xfs_btree_increment(bno_cur_gt, 0, &i)))
                                goto error0;
-                       if (!i) {
+                       if (!i || gtbnoa > args->max_agbno) {
                                xfs_btree_del_cursor(bno_cur_gt,
                                                     XFS_BTREE_NOERROR);
                                bno_cur_gt = NULL;
@@ -1211,6 +1247,7 @@ restart:
        ASSERT(ltnew >= ltbno);
        ASSERT(ltnew + rlen <= ltbnoa + ltlena);
        ASSERT(ltnew + rlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
+       ASSERT(ltnew >= args->min_agbno && ltnew <= args->max_agbno);
        args->agbno = ltnew;
 
        if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, ltlen,
@@ -1303,7 +1340,7 @@ restart:
                        error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, &i);
                        if (error)
                                goto error0;
-                       XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+                       XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
 
                        xfs_alloc_compute_aligned(args, fbno, flen,
                                                  &rbno, &rlen);
@@ -1342,7 +1379,7 @@ restart:
         * This can't happen in the second case above.
         */
        rlen = XFS_EXTLEN_MIN(args->maxlen, rlen);
-       XFS_WANT_CORRUPTED_GOTO(rlen == 0 ||
+       XFS_WANT_CORRUPTED_GOTO(args->mp, rlen == 0 ||
                        (rlen <= flen && rbno + rlen <= fbno + flen), error0);
        if (rlen < args->maxlen) {
                xfs_agblock_t   bestfbno;
@@ -1362,13 +1399,13 @@ restart:
                        if ((error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen,
                                        &i)))
                                goto error0;
-                       XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+                       XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
                        if (flen < bestrlen)
                                break;
                        xfs_alloc_compute_aligned(args, fbno, flen,
                                                  &rbno, &rlen);
                        rlen = XFS_EXTLEN_MIN(args->maxlen, rlen);
-                       XFS_WANT_CORRUPTED_GOTO(rlen == 0 ||
+                       XFS_WANT_CORRUPTED_GOTO(args->mp, rlen == 0 ||
                                (rlen <= flen && rbno + rlen <= fbno + flen),
                                error0);
                        if (rlen > bestrlen) {
@@ -1383,7 +1420,7 @@ restart:
                if ((error = xfs_alloc_lookup_eq(cnt_cur, bestfbno, bestflen,
                                &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
                rlen = bestrlen;
                rbno = bestrbno;
                flen = bestflen;
@@ -1408,7 +1445,7 @@ restart:
        if (!xfs_alloc_fix_minleft(args))
                goto out_nominleft;
        rlen = args->len;
-       XFS_WANT_CORRUPTED_GOTO(rlen <= flen, error0);
+       XFS_WANT_CORRUPTED_GOTO(args->mp, rlen <= flen, error0);
        /*
         * Allocate and initialize a cursor for the by-block tree.
         */
@@ -1422,7 +1459,7 @@ restart:
        cnt_cur = bno_cur = NULL;
        args->len = rlen;
        args->agbno = rbno;
-       XFS_WANT_CORRUPTED_GOTO(
+       XFS_WANT_CORRUPTED_GOTO(args->mp,
                args->agbno + args->len <=
                        be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length),
                error0);
@@ -1467,7 +1504,7 @@ xfs_alloc_ag_vextent_small(
        if (i) {
                if ((error = xfs_alloc_get_rec(ccur, &fbno, &flen, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
        }
        /*
         * Nothing in the btree, try the freelist.  Make sure
@@ -1493,7 +1530,7 @@ xfs_alloc_ag_vextent_small(
                        }
                        args->len = 1;
                        args->agbno = fbno;
-                       XFS_WANT_CORRUPTED_GOTO(
+                       XFS_WANT_CORRUPTED_GOTO(args->mp,
                                args->agbno + args->len <=
                                be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length),
                                error0);
@@ -1579,7 +1616,7 @@ xfs_free_ag_extent(
                 */
                if ((error = xfs_alloc_get_rec(bno_cur, &ltbno, &ltlen, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
                /*
                 * It's not contiguous, though.
                 */
@@ -1591,7 +1628,8 @@ xfs_free_ag_extent(
                         * space was invalid, it's (partly) already free.
                         * Very bad.
                         */
-                       XFS_WANT_CORRUPTED_GOTO(ltbno + ltlen <= bno, error0);
+                       XFS_WANT_CORRUPTED_GOTO(mp,
+                                               ltbno + ltlen <= bno, error0);
                }
        }
        /*
@@ -1606,7 +1644,7 @@ xfs_free_ag_extent(
                 */
                if ((error = xfs_alloc_get_rec(bno_cur, &gtbno, &gtlen, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
                /*
                 * It's not contiguous, though.
                 */
@@ -1618,7 +1656,7 @@ xfs_free_ag_extent(
                         * space was invalid, it's (partly) already free.
                         * Very bad.
                         */
-                       XFS_WANT_CORRUPTED_GOTO(gtbno >= bno + len, error0);
+                       XFS_WANT_CORRUPTED_GOTO(mp, gtbno >= bno + len, error0);
                }
        }
        /*
@@ -1635,31 +1673,31 @@ xfs_free_ag_extent(
                 */
                if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
                if ((error = xfs_btree_delete(cnt_cur, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
                /*
                 * Delete the old by-size entry on the right.
                 */
                if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
                if ((error = xfs_btree_delete(cnt_cur, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
                /*
                 * Delete the old by-block entry for the right block.
                 */
                if ((error = xfs_btree_delete(bno_cur, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
                /*
                 * Move the by-block cursor back to the left neighbor.
                 */
                if ((error = xfs_btree_decrement(bno_cur, 0, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
 #ifdef DEBUG
                /*
                 * Check that this is the right record: delete didn't
@@ -1672,7 +1710,7 @@ xfs_free_ag_extent(
                        if ((error = xfs_alloc_get_rec(bno_cur, &xxbno, &xxlen,
                                        &i)))
                                goto error0;
-                       XFS_WANT_CORRUPTED_GOTO(
+                       XFS_WANT_CORRUPTED_GOTO(mp,
                                i == 1 && xxbno == ltbno && xxlen == ltlen,
                                error0);
                }
@@ -1695,17 +1733,17 @@ xfs_free_ag_extent(
                 */
                if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
                if ((error = xfs_btree_delete(cnt_cur, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
                /*
                 * Back up the by-block cursor to the left neighbor, and
                 * update its length.
                 */
                if ((error = xfs_btree_decrement(bno_cur, 0, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
                nbno = ltbno;
                nlen = len + ltlen;
                if ((error = xfs_alloc_update(bno_cur, nbno, nlen)))
@@ -1721,10 +1759,10 @@ xfs_free_ag_extent(
                 */
                if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
                if ((error = xfs_btree_delete(cnt_cur, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
                /*
                 * Update the starting block and length of the right
                 * neighbor in the by-block tree.
@@ -1743,7 +1781,7 @@ xfs_free_ag_extent(
                nlen = len;
                if ((error = xfs_btree_insert(bno_cur, &i)))
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
        }
        xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR);
        bno_cur = NULL;
@@ -1752,10 +1790,10 @@ xfs_free_ag_extent(
         */
        if ((error = xfs_alloc_lookup_eq(cnt_cur, nbno, nlen, &i)))
                goto error0;
-       XFS_WANT_CORRUPTED_GOTO(i == 0, error0);
+       XFS_WANT_CORRUPTED_GOTO(mp, i == 0, error0);
        if ((error = xfs_btree_insert(cnt_cur, &i)))
                goto error0;
-       XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0);
        xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
        cnt_cur = NULL;