xfs: add xlog_grant_head_wake_all
[linux-2.6.git] / fs / xfs / xfs_alloc.c
index 53157d4..ce84ffd 100644 (file)
@@ -276,7 +276,6 @@ xfs_alloc_fix_minleft(
                return 1;
        agf = XFS_BUF_TO_AGF(args->agbp);
        diff = be32_to_cpu(agf->agf_freeblks)
-               + be32_to_cpu(agf->agf_flcount)
                - args->len - args->minleft;
        if (diff >= 0)
                return 1;
@@ -452,9 +451,8 @@ xfs_alloc_read_agfl(
                        XFS_FSS_TO_BB(mp, 1), 0, &bp);
        if (error)
                return error;
-       ASSERT(bp);
-       ASSERT(!XFS_BUF_GETERROR(bp));
-       XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGFL, XFS_AGFL_REF);
+       ASSERT(!xfs_buf_geterror(bp));
+       xfs_buf_set_ref(bp, XFS_AGFL_REF);
        *bpp = bp;
        return 0;
 }
@@ -571,9 +569,7 @@ xfs_alloc_ag_vextent_exact(
        xfs_agblock_t   tbno;   /* start block of trimmed extent */
        xfs_extlen_t    tlen;   /* length of trimmed extent */
        xfs_agblock_t   tend;   /* end block of trimmed extent */
-       xfs_agblock_t   end;    /* end of allocated extent */
        int             i;      /* success/failure of operation */
-       xfs_extlen_t    rlen;   /* length of returned extent */
 
        ASSERT(args->alignment == 1);
 
@@ -626,18 +622,16 @@ xfs_alloc_ag_vextent_exact(
         *
         * Fix the length according to mod and prod if given.
         */
-       end = XFS_AGBLOCK_MIN(tend, args->agbno + args->maxlen);
-       args->len = end - args->agbno;
+       args->len = XFS_AGBLOCK_MIN(tend, args->agbno + args->maxlen)
+                                               - args->agbno;
        xfs_alloc_fix_len(args);
        if (!xfs_alloc_fix_minleft(args))
                goto not_found;
 
-       rlen = args->len;
-       ASSERT(args->agbno + rlen <= tend);
-       end = args->agbno + rlen;
+       ASSERT(args->agbno + args->len <= tend);
 
        /*
-        * We are allocating agbno for rlen [agbno .. end]
+        * We are allocating agbno for args->len
         * Allocate/initialize a cursor for the by-size btree.
         */
        cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
@@ -2121,14 +2115,14 @@ xfs_read_agf(
        if (!*bpp)
                return 0;
 
-       ASSERT(!XFS_BUF_GETERROR(*bpp));
+       ASSERT(!(*bpp)->b_error);
        agf = XFS_BUF_TO_AGF(*bpp);
 
        /*
         * Validate the magic number of the agf block.
         */
        agf_ok =
-               be32_to_cpu(agf->agf_magicnum) == XFS_AGF_MAGIC &&
+               agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
                XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) &&
                be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) &&
                be32_to_cpu(agf->agf_flfirst) < XFS_AGFL_SIZE(mp) &&
@@ -2145,7 +2139,7 @@ xfs_read_agf(
                xfs_trans_brelse(tp, *bpp);
                return XFS_ERROR(EFSCORRUPTED);
        }
-       XFS_BUF_SET_VTYPE_REF(*bpp, B_FS_AGF, XFS_AGF_REF);
+       xfs_buf_set_ref(*bpp, XFS_AGF_REF);
        return 0;
 }
 
@@ -2173,7 +2167,7 @@ xfs_alloc_read_agf(
                return error;
        if (!*bpp)
                return 0;
-       ASSERT(!XFS_BUF_GETERROR(*bpp));
+       ASSERT(!(*bpp)->b_error);
 
        agf = XFS_BUF_TO_AGF(*bpp);
        pag = xfs_perag_get(mp, agno);
@@ -2470,7 +2464,7 @@ xfs_free_extent(
 
        error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0);
        if (!error)
-               xfs_alloc_busy_insert(tp, args.agno, args.agbno, len);
+               xfs_alloc_busy_insert(tp, args.agno, args.agbno, len, 0);
 error0:
        xfs_perag_put(args.pag);
        return error;
@@ -2481,7 +2475,8 @@ xfs_alloc_busy_insert(
        struct xfs_trans        *tp,
        xfs_agnumber_t          agno,
        xfs_agblock_t           bno,
-       xfs_extlen_t            len)
+       xfs_extlen_t            len,
+       unsigned int            flags)
 {
        struct xfs_busy_extent  *new;
        struct xfs_busy_extent  *busyp;
@@ -2505,6 +2500,7 @@ xfs_alloc_busy_insert(
        new->bno = bno;
        new->length = len;
        INIT_LIST_HEAD(&new->list);
+       new->flags = flags;
 
        /* trace before insert to be able to see failed inserts */
        trace_xfs_alloc_busy(tp->t_mountp, agno, bno, len);
@@ -2610,6 +2606,18 @@ xfs_alloc_busy_update_extent(
        xfs_agblock_t           bend = bbno + busyp->length;
 
        /*
+        * This extent is currently being discarded.  Give the thread
+        * performing the discard a chance to mark the extent unbusy
+        * and retry.
+        */
+       if (busyp->flags & XFS_ALLOC_BUSY_DISCARDED) {
+               spin_unlock(&pag->pagb_lock);
+               delay(1);
+               spin_lock(&pag->pagb_lock);
+               return false;
+       }
+
+       /*
         * If there is a busy extent overlapping a user allocation, we have
         * no choice but to force the log and retry the search.
         *
@@ -2814,7 +2822,8 @@ restart:
                 * If this is a metadata allocation, try to reuse the busy
                 * extent instead of trimming the allocation.
                 */
-               if (!args->userdata) {
+               if (!args->userdata &&
+                   !(busyp->flags & XFS_ALLOC_BUSY_DISCARDED)) {
                        if (!xfs_alloc_busy_update_extent(args->mp, args->pag,
                                                          busyp, fbno, flen,
                                                          false))
@@ -2964,24 +2973,70 @@ fail:
        *rlen = 0;
 }
 
-void
-xfs_alloc_busy_clear(
+static void
+xfs_alloc_busy_clear_one(
        struct xfs_mount        *mp,
+       struct xfs_perag        *pag,
        struct xfs_busy_extent  *busyp)
 {
-       struct xfs_perag        *pag;
-
-       list_del_init(&busyp->list);
-
-       pag = xfs_perag_get(mp, busyp->agno);
-       spin_lock(&pag->pagb_lock);
        if (busyp->length) {
                trace_xfs_alloc_busy_clear(mp, busyp->agno, busyp->bno,
                                                busyp->length);
                rb_erase(&busyp->rb_node, &pag->pagb_tree);
        }
-       spin_unlock(&pag->pagb_lock);
-       xfs_perag_put(pag);
 
+       list_del_init(&busyp->list);
        kmem_free(busyp);
 }
+
+/*
+ * Remove all extents on the passed in list from the busy extents tree.
+ * If do_discard is set skip extents that need to be discarded, and mark
+ * these as undergoing a discard operation instead.
+ */
+void
+xfs_alloc_busy_clear(
+       struct xfs_mount        *mp,
+       struct list_head        *list,
+       bool                    do_discard)
+{
+       struct xfs_busy_extent  *busyp, *n;
+       struct xfs_perag        *pag = NULL;
+       xfs_agnumber_t          agno = NULLAGNUMBER;
+
+       list_for_each_entry_safe(busyp, n, list, list) {
+               if (busyp->agno != agno) {
+                       if (pag) {
+                               spin_unlock(&pag->pagb_lock);
+                               xfs_perag_put(pag);
+                       }
+                       pag = xfs_perag_get(mp, busyp->agno);
+                       spin_lock(&pag->pagb_lock);
+                       agno = busyp->agno;
+               }
+
+               if (do_discard && busyp->length &&
+                   !(busyp->flags & XFS_ALLOC_BUSY_SKIP_DISCARD))
+                       busyp->flags = XFS_ALLOC_BUSY_DISCARDED;
+               else
+                       xfs_alloc_busy_clear_one(mp, pag, busyp);
+       }
+
+       if (pag) {
+               spin_unlock(&pag->pagb_lock);
+               xfs_perag_put(pag);
+       }
+}
+
+/*
+ * Callback for list_sort to sort busy extents by the AG they reside in.
+ */
+int
+xfs_busy_extent_ag_cmp(
+       void                    *priv,
+       struct list_head        *a,
+       struct list_head        *b)
+{
+       return container_of(a, struct xfs_busy_extent, list)->agno -
+               container_of(b, struct xfs_busy_extent, list)->agno;
+}