xfs
[Top] [All Lists]

[PATCH 4/6] xfs: allow reusing busy extents where safe

To: xfs@xxxxxxxxxxx
Subject: [PATCH 4/6] xfs: allow reusing busy extents where safe
From: Christoph Hellwig <hch@xxxxxxxxxxxxx>
Date: Tue, 22 Mar 2011 15:55:54 -0400
References: <20110322195550.260682574@xxxxxxxxxxxxxxxxxxxxxx>
User-agent: quilt/0.48-1
Allow reusing any busy extent for metadata allocations, and reusing busy
userdata extents for userdata allocations.  Most of the complexity is
propagating the userdata information from the XFS_BMAPI_METADATA flag
to xfs_bunmapi into the low-level extent freeing routines.  After that
we can just track what type of busy extent we have and treat it accordingly.

Signed-off-by: Christoph Hellwig <hch@xxxxxx>

Index: xfs/fs/xfs/xfs_alloc.c
===================================================================
--- xfs.orig/fs/xfs/xfs_alloc.c 2011-03-21 14:49:14.000000000 +0100
+++ xfs/fs/xfs/xfs_alloc.c      2011-03-21 14:51:31.746155282 +0100
@@ -1396,7 +1396,8 @@ xfs_alloc_ag_vextent_small(
                if (error)
                        goto error0;
                if (fbno != NULLAGBLOCK) {
-                       xfs_alloc_busy_reuse(args->tp, args->agno, fbno, 1);
+                       xfs_alloc_busy_reuse(args->tp, args->agno, fbno, 1,
+                                            args->userdata);
 
                        if (args->userdata) {
                                xfs_buf_t       *bp;
@@ -2431,7 +2432,8 @@ int                               /* error */
 xfs_free_extent(
        xfs_trans_t     *tp,    /* transaction pointer */
        xfs_fsblock_t   bno,    /* starting block number of extent */
-       xfs_extlen_t    len)    /* length of extent */
+       xfs_extlen_t    len,
+       bool            userdata)/* length of extent */
 {
        xfs_alloc_arg_t args;
        int             error;
@@ -2444,6 +2446,7 @@ xfs_free_extent(
        ASSERT(args.agno < args.mp->m_sb.sb_agcount);
        args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno);
        args.pag = xfs_perag_get(args.mp, args.agno);
+       args.userdata = userdata;
        if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING)))
                goto error0;
 #ifdef DEBUG
@@ -2453,7 +2456,7 @@ xfs_free_extent(
 #endif
        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, userdata);
 error0:
        xfs_perag_put(args.pag);
        return error;
@@ -2464,7 +2467,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,
+       bool                    userdata)
 {
        struct xfs_busy_extent  *new;
        struct xfs_busy_extent  *busyp;
@@ -2487,6 +2491,7 @@ xfs_alloc_busy_insert(
        new->agno = agno;
        new->bno = bno;
        new->length = len;
+       new->flags = userdata ? XFS_ALLOC_BUSY_USERDATA : 0;
        INIT_LIST_HEAD(&new->list);
 
        /* trace before insert to be able to see failed inserts */
@@ -2688,7 +2693,8 @@ xfs_alloc_busy_reuse(
        struct xfs_trans        *tp,
        xfs_agnumber_t          agno,
        xfs_agblock_t           fbno,
-       xfs_extlen_t            flen)
+       xfs_extlen_t            flen,
+       bool                    userdata)
 {
        struct xfs_perag        *pag;
        struct rb_node          *rbp;
@@ -2717,7 +2723,7 @@ restart:
 
                overlap = xfs_alloc_busy_try_reuse(pag, busyp,
                                                   fbno, fbno + flen);
-               if (overlap) {
+               if (overlap == -1 || (overlap && userdata)) {
                        spin_unlock(&pag->pagb_lock);
                        xfs_log_force(tp->t_mountp, XFS_LOG_SYNC);
                        goto restart;
@@ -2754,6 +2760,7 @@ xfs_alloc_busy_trim(
 
        ASSERT(flen > 0);
 
+restart:
        spin_lock(&args->pag->pagb_lock);
        rbp = args->pag->pagb_tree.rb_node;
        while (rbp && flen >= args->minlen) {
@@ -2771,6 +2778,31 @@ xfs_alloc_busy_trim(
                        continue;
                }
 
+               if (!args->userdata ||
+                   (busyp->flags & XFS_ALLOC_BUSY_USERDATA)) {
+                       int overlap;
+
+                       overlap = xfs_alloc_busy_try_reuse(args->pag, busyp,
+                                                          fbno, fbno + flen);
+                       if (unlikely(overlap == -1)) {
+                               spin_unlock(&args->pag->pagb_lock);
+                               xfs_log_force(args->mp, XFS_LOG_SYNC);
+                               goto restart;
+                       }
+
+                       /*
+                        * No more busy extents to search.
+                        */
+                       if (bbno <= fbno && bend >= fend)
+                               goto out;
+
+                       if (fbno < bbno)
+                               rbp = rbp->rb_left;
+                       else
+                               rbp = rbp->rb_right;
+                       continue;
+               }
+
                if (bbno <= fbno) {
                        /* start overlap */
 
@@ -2898,8 +2930,8 @@ xfs_alloc_busy_trim(
 
                flen = fend - fbno;
        }
+out:
        spin_unlock(&args->pag->pagb_lock);
-
        *rbno = fbno;
        *rlen = flen;
        return;
Index: xfs/fs/xfs/xfs_alloc.h
===================================================================
--- xfs.orig/fs/xfs/xfs_alloc.h 2011-03-21 14:48:04.000000000 +0100
+++ xfs/fs/xfs/xfs_alloc.h      2011-03-21 14:49:21.933973842 +0100
@@ -137,7 +137,7 @@ xfs_alloc_longest_free_extent(struct xfs
 #ifdef __KERNEL__
 void
 xfs_alloc_busy_insert(struct xfs_trans *tp, xfs_agnumber_t agno,
-       xfs_agblock_t bno, xfs_extlen_t len);
+       xfs_agblock_t bno, xfs_extlen_t len, bool userdata);
 
 void
 xfs_alloc_busy_clear(struct xfs_mount *mp, struct xfs_busy_extent *busyp);
@@ -148,7 +148,7 @@ xfs_alloc_busy_search(struct xfs_mount *
 
 void
 xfs_alloc_busy_reuse(struct xfs_trans *tp, xfs_agnumber_t agno,
-       xfs_agblock_t fbno, xfs_extlen_t flen);
+       xfs_agblock_t fbno, xfs_extlen_t flen, bool userdata);
 #endif /* __KERNEL__ */
 
 /*
@@ -224,7 +224,8 @@ int                         /* error */
 xfs_free_extent(
        struct xfs_trans *tp,   /* transaction pointer */
        xfs_fsblock_t   bno,    /* starting block number of extent */
-       xfs_extlen_t    len);   /* length of extent */
+       xfs_extlen_t    len,
+       bool            userdata);/* length of extent */
 
 int                                    /* error */
 xfs_alloc_lookup_le(
Index: xfs/fs/xfs/xfs_alloc_btree.c
===================================================================
--- xfs.orig/fs/xfs/xfs_alloc_btree.c   2011-03-21 14:48:04.000000000 +0100
+++ xfs/fs/xfs/xfs_alloc_btree.c        2011-03-21 14:49:21.937977488 +0100
@@ -95,7 +95,7 @@ xfs_allocbt_alloc_block(
                return 0;
        }
 
-       xfs_alloc_busy_reuse(cur->bc_tp, cur->bc_private.a.agno, bno, 1);
+       xfs_alloc_busy_reuse(cur->bc_tp, cur->bc_private.a.agno, bno, 1, false);
 
        xfs_trans_agbtree_delta(cur->bc_tp, 1);
        new->s = cpu_to_be32(bno);
@@ -120,18 +120,8 @@ xfs_allocbt_free_block(
        if (error)
                return error;
 
-       /*
-        * Since blocks move to the free list without the coordination used in
-        * xfs_bmap_finish, we can't allow block to be available for
-        * reallocation and non-transaction writing (user data) until we know
-        * that the transaction that moved it to the free list is permanently
-        * on disk. We track the blocks by declaring these blocks as "busy";
-        * the busy list is maintained on a per-ag basis and each transaction
-        * records which entries should be removed when the iclog commits to
-        * disk. If a busy block is allocated, the iclog is pushed up to the
-        * LSN that freed the block.
-        */
-       xfs_alloc_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1);
+       xfs_alloc_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno,
+                             1, false);
        xfs_trans_agbtree_delta(cur->bc_tp, -1);
        return 0;
 }
Index: xfs/fs/xfs/xfs_ag.h
===================================================================
--- xfs.orig/fs/xfs/xfs_ag.h    2011-03-21 14:48:04.000000000 +0100
+++ xfs/fs/xfs/xfs_ag.h 2011-03-21 14:49:21.941981228 +0100
@@ -187,6 +187,8 @@ struct xfs_busy_extent {
        xfs_agnumber_t  agno;
        xfs_agblock_t   bno;
        xfs_extlen_t    length;
+       unsigned int    flags;
+#define XFS_ALLOC_BUSY_USERDATA                0x01    /* freed data extents */
 };
 
 /*
Index: xfs/fs/xfs/xfs_bmap.c
===================================================================
--- xfs.orig/fs/xfs/xfs_bmap.c  2011-03-21 14:48:04.238474593 +0100
+++ xfs/fs/xfs/xfs_bmap.c       2011-03-21 14:49:21.949973870 +0100
@@ -180,22 +180,6 @@ xfs_bmap_btree_to_extents(
        int                     whichfork); /* data or attr fork */
 
 /*
- * Called by xfs_bmapi to update file extent records and the btree
- * after removing space (or undoing a delayed allocation).
- */
-STATIC int                             /* error */
-xfs_bmap_del_extent(
-       xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_trans_t             *tp,    /* current trans pointer */
-       xfs_extnum_t            idx,    /* extent number to update/insert */
-       xfs_bmap_free_t         *flist, /* list of extents to be freed */
-       xfs_btree_cur_t         *cur,   /* if null, not a btree */
-       xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       int                     *logflagsp,/* inode logging flags */
-       int                     whichfork, /* data or attr fork */
-       int                     rsvd);   /* OK to allocate reserved blocks */
-
-/*
  * Remove the entry "free" from the free item list.  Prev points to the
  * previous entry, unless "free" is the head of the list.
  */
@@ -2811,7 +2795,7 @@ xfs_bmap_btree_to_extents(
        cblock = XFS_BUF_TO_BLOCK(cbp);
        if ((error = xfs_btree_check_block(cur, cblock, 0, cbp)))
                return error;
-       xfs_bmap_add_free(cbno, 1, cur->bc_private.b.flist, mp);
+       xfs_bmap_add_free(mp, cur->bc_private.b.flist, cbno, 1, 0);
        ip->i_d.di_nblocks--;
        xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
        xfs_trans_binval(tp, cbp);
@@ -2838,8 +2822,7 @@ xfs_bmap_del_extent(
        xfs_btree_cur_t         *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *del,   /* data to remove from extents */
        int                     *logflagsp, /* inode logging flags */
-       int                     whichfork, /* data or attr fork */
-       int                     rsvd)   /* OK to allocate reserved blocks */
+       int                     flags)  /* XFS_BMAPI_* flags */
 {
        xfs_filblks_t           da_new; /* new delay-alloc indirect blocks */
        xfs_filblks_t           da_old; /* old delay-alloc indirect blocks */
@@ -2849,7 +2832,6 @@ xfs_bmap_del_extent(
        int                     do_fx;  /* free extent at end of routine */
        xfs_bmbt_rec_host_t     *ep;    /* current extent entry pointer */
        int                     error;  /* error return value */
-       int                     flags;  /* inode logging flags */
        xfs_bmbt_irec_t         got;    /* current extent entry */
        xfs_fileoff_t           got_endoff;     /* first offset past got */
        int                     i;      /* temp state */
@@ -2861,12 +2843,17 @@ xfs_bmap_del_extent(
        uint                    qfield; /* quota field to update */
        xfs_filblks_t           temp;   /* for indirect length calculations */
        xfs_filblks_t           temp2;  /* for indirect length calculations */
-       int                     state = 0;
+       int                     state, whichfork;
 
        XFS_STATS_INC(xs_del_exlist);
 
-       if (whichfork == XFS_ATTR_FORK)
-               state |= BMAP_ATTRFORK;
+       if (flags & XFS_BMAPI_ATTRFORK) {
+               whichfork = XFS_ATTR_FORK;
+               state = BMAP_ATTRFORK;
+       } else {
+               whichfork = XFS_DATA_FORK;
+               state = 0;
+       }
 
        mp = ip->i_mount;
        ifp = XFS_IFORK_PTR(ip, whichfork);
@@ -3121,9 +3108,13 @@ xfs_bmap_del_extent(
        /*
         * If we need to, add to list of extents to delete.
         */
-       if (do_fx)
-               xfs_bmap_add_free(del->br_startblock, del->br_blockcount, flist,
-                       mp);
+       if (do_fx) {
+               xfs_bmap_add_free(mp, flist, del->br_startblock,
+                                 del->br_blockcount,
+                                 (flags & XFS_BMAPI_METADATA) ? 0 :
+                                  XFS_BFI_USERDATA);
+       }
+
        /*
         * Adjust inode # blocks in the file.
         */
@@ -3142,7 +3133,9 @@ xfs_bmap_del_extent(
        ASSERT(da_old >= da_new);
        if (da_old > da_new) {
                xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS,
-                       (int64_t)(da_old - da_new), rsvd);
+                       (int64_t)(da_old - da_new),
+                       !!(flags & XFS_BMAPI_RSVBLOCKS));
+
        }
 done:
        *logflagsp = flags;
@@ -3723,10 +3716,11 @@ error0:
 /* ARGSUSED */
 void
 xfs_bmap_add_free(
+       struct xfs_mount        *mp,            /* mount point structure */
+       struct xfs_bmap_free    *flist,         /* list of extents */
        xfs_fsblock_t           bno,            /* fs block number of extent */
        xfs_filblks_t           len,            /* length of extent */
-       xfs_bmap_free_t         *flist,         /* list of extents */
-       xfs_mount_t             *mp)            /* mount point structure */
+       unsigned int            flags)
 {
        xfs_bmap_free_item_t    *cur;           /* current (next) element */
        xfs_bmap_free_item_t    *new;           /* new element */
@@ -3750,6 +3744,7 @@ xfs_bmap_add_free(
        new = kmem_zone_alloc(xfs_bmap_free_item_zone, KM_SLEEP);
        new->xbfi_startblock = bno;
        new->xbfi_blockcount = (xfs_extlen_t)len;
+       new->xbfi_flags = XFS_BFI_USERDATA;
        for (prev = NULL, cur = flist->xbf_first;
             cur != NULL;
             prev = cur, cur = cur->xbfi_next) {
@@ -3883,8 +3878,11 @@ xfs_bmap_finish(
        efd = xfs_trans_get_efd(ntp, efi, flist->xbf_count);
        for (free = flist->xbf_first; free != NULL; free = next) {
                next = free->xbfi_next;
-               if ((error = xfs_free_extent(ntp, free->xbfi_startblock,
-                               free->xbfi_blockcount))) {
+
+               error = xfs_free_extent(ntp, free->xbfi_startblock,
+                               free->xbfi_blockcount,
+                               !!(free->xbfi_flags & XFS_BFI_USERDATA));
+               if (error) {
                        /*
                         * The bmap free list will be cleaned up at a
                         * higher level.  The EFI will be canceled when
@@ -5278,7 +5276,7 @@ xfs_bunmapi(
                        goto error0;
                }
                error = xfs_bmap_del_extent(ip, tp, lastx, flist, cur, &del,
-                               &tmp_logflags, whichfork, rsvd);
+                               &tmp_logflags, flags);
                logflags |= tmp_logflags;
                if (error)
                        goto error0;
Index: xfs/fs/xfs/xfs_bmap.h
===================================================================
--- xfs.orig/fs/xfs/xfs_bmap.h  2011-03-21 14:48:04.000000000 +0100
+++ xfs/fs/xfs/xfs_bmap.h       2011-03-21 14:49:21.953974825 +0100
@@ -35,6 +35,8 @@ typedef struct xfs_bmap_free_item
 {
        xfs_fsblock_t           xbfi_startblock;/* starting fs block number */
        xfs_extlen_t            xbfi_blockcount;/* number of blocks in extent */
+       unsigned int            xbfi_flags;
+#define XFS_BFI_USERDATA       0x01            /* userdata extent */
        struct xfs_bmap_free_item *xbfi_next;   /* link to next entry */
 } xfs_bmap_free_item_t;
 
@@ -188,10 +190,11 @@ xfs_bmap_add_attrfork(
  */
 void
 xfs_bmap_add_free(
+       struct xfs_mount        *mp,            /* mount point structure */
+       struct xfs_bmap_free    *flist,         /* list of extents */
        xfs_fsblock_t           bno,            /* fs block number of extent */
        xfs_filblks_t           len,            /* length of extent */
-       xfs_bmap_free_t         *flist,         /* list of extents */
-       struct xfs_mount        *mp);           /* mount point structure */
+       unsigned int            flags);
 
 /*
  * Routine to clean up the free list data structure when
Index: xfs/fs/xfs/xfs_bmap_btree.c
===================================================================
--- xfs.orig/fs/xfs/xfs_bmap_btree.c    2011-03-21 14:48:04.000000000 +0100
+++ xfs/fs/xfs/xfs_bmap_btree.c 2011-03-21 14:49:21.957973331 +0100
@@ -598,7 +598,7 @@ xfs_bmbt_free_block(
        struct xfs_trans        *tp = cur->bc_tp;
        xfs_fsblock_t           fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp));
 
-       xfs_bmap_add_free(fsbno, 1, cur->bc_private.b.flist, mp);
+       xfs_bmap_add_free(mp, cur->bc_private.b.flist, fsbno, 1, 0);
        ip->i_d.di_nblocks--;
 
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
Index: xfs/fs/xfs/xfs_fsops.c
===================================================================
--- xfs.orig/fs/xfs/xfs_fsops.c 2011-03-21 14:48:04.000000000 +0100
+++ xfs/fs/xfs/xfs_fsops.c      2011-03-21 14:49:21.961974307 +0100
@@ -344,7 +344,7 @@ xfs_growfs_data_private(
                 * Free the new space.
                 */
                error = xfs_free_extent(tp, XFS_AGB_TO_FSB(mp, agno,
-                       be32_to_cpu(agf->agf_length) - new), new);
+                       be32_to_cpu(agf->agf_length) - new), new, false);
                if (error) {
                        goto error0;
                }
Index: xfs/fs/xfs/xfs_ialloc.c
===================================================================
--- xfs.orig/fs/xfs/xfs_ialloc.c        2011-03-21 14:48:04.000000000 +0100
+++ xfs/fs/xfs/xfs_ialloc.c     2011-03-21 14:49:21.965975280 +0100
@@ -1154,9 +1154,10 @@ xfs_difree(
                        goto error0;
                }
 
-               xfs_bmap_add_free(XFS_AGB_TO_FSB(mp,
-                               agno, XFS_INO_TO_AGBNO(mp,rec.ir_startino)),
-                               XFS_IALLOC_BLOCKS(mp), flist, mp);
+               xfs_bmap_add_free(mp, flist,
+                                 XFS_AGB_TO_FSB(mp, agno,
+                                       XFS_INO_TO_AGBNO(mp,rec.ir_startino)),
+                                 XFS_IALLOC_BLOCKS(mp), 0);
        } else {
                *delete = 0;
 
Index: xfs/fs/xfs/xfs_ialloc_btree.c
===================================================================
--- xfs.orig/fs/xfs/xfs_ialloc_btree.c  2011-03-21 14:48:04.000000000 +0100
+++ xfs/fs/xfs/xfs_ialloc_btree.c       2011-03-21 14:49:21.973975583 +0100
@@ -117,7 +117,7 @@ xfs_inobt_free_block(
        int                     error;
 
        fsbno = XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(bp));
-       error = xfs_free_extent(cur->bc_tp, fsbno, 1);
+       error = xfs_free_extent(cur->bc_tp, fsbno, 1, false);
        if (error)
                return error;
 
Index: xfs/fs/xfs/xfs_log_recover.c
===================================================================
--- xfs.orig/fs/xfs/xfs_log_recover.c   2011-03-21 14:48:04.000000000 +0100
+++ xfs/fs/xfs/xfs_log_recover.c        2011-03-21 14:49:21.973975583 +0100
@@ -2907,8 +2907,9 @@ xlog_recover_process_efi(
        efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents);
 
        for (i = 0; i < efip->efi_format.efi_nextents; i++) {
-               extp = &(efip->efi_format.efi_extents[i]);
-               error = xfs_free_extent(tp, extp->ext_start, extp->ext_len);
+               extp = &efip->efi_format.efi_extents[i];
+               error = xfs_free_extent(tp, extp->ext_start, extp->ext_len,
+                                       false);
                if (error)
                        goto abort_error;
                xfs_trans_log_efd_extent(tp, efdp, extp->ext_start,

<Prev in Thread] Current Thread [Next in Thread>