From 97d3ac75e5e0ebf7ca38ae74cebd201c09b97ab2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 24 Apr 2011 19:06:16 +0000 Subject: xfs: exact busy extent tracking Update the extent tree in case we have to reuse a busy extent, so that it always is kept uptodate. This is done by replacing the busy list searches with a new xfs_alloc_busy_reuse helper, which updates the busy extent tree in case of a reuse. This allows us to allow reusing metadata extents unconditionally, and thus avoid log forces especially for allocation btree blocks. Signed-off-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/xfs_alloc.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fs/xfs/xfs_alloc.h') diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h index d0b3bc72005..de5e27c9517 100644 --- a/fs/xfs/xfs_alloc.h +++ b/fs/xfs/xfs_alloc.h @@ -145,6 +145,10 @@ xfs_alloc_busy_clear(struct xfs_mount *mp, struct xfs_busy_extent *busyp); int xfs_alloc_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len); + +void +xfs_alloc_busy_reuse(struct xfs_mount *mp, xfs_agnumber_t agno, + xfs_agblock_t fbno, xfs_extlen_t flen, bool userdata); #endif /* __KERNEL__ */ /* -- cgit v1.2.3-70-g09d2 From 8a072a4d4c6a5b6ec32836c467d2996393c76c6f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 24 Apr 2011 19:06:17 +0000 Subject: xfs: reduce the number of pagb_lock roundtrips in xfs_alloc_clear_busy Instead of finding the per-ag and then taking and releasing the pagb_lock for every single busy extent completed sort the list of busy extents and only switch betweens AGs where nessecary. This becomes especially important with the online discard support which will hit this lock more often. Signed-off-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_buf.c | 1 - fs/xfs/linux-2.6/xfs_linux.h | 1 + fs/xfs/xfs_alloc.c | 56 ++++++++++++++++++++++++++++++++++++-------- fs/xfs/xfs_alloc.h | 11 ++++++++- fs/xfs/xfs_log_cil.c | 5 ++-- fs/xfs/xfs_trans.c | 6 ++--- 6 files changed, 61 insertions(+), 19 deletions(-) (limited to 'fs/xfs/xfs_alloc.h') diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 9ef9ed2cfe2..09889035765 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -33,7 +33,6 @@ #include #include #include -#include #include "xfs_sb.h" #include "xfs_inum.h" diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h index 244be9cbfe7..8633521b3b2 100644 --- a/fs/xfs/linux-2.6/xfs_linux.h +++ b/fs/xfs/linux-2.6/xfs_linux.h @@ -70,6 +70,7 @@ #include #include #include +#include #include #include diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 53157d4d5e8..44a51a7b4c3 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -2964,24 +2964,60 @@ 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); } + +void +xfs_alloc_busy_clear( + struct xfs_mount *mp, + struct list_head *list) +{ + 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; + } + + 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; +} diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h index de5e27c9517..240ad288f2f 100644 --- a/fs/xfs/xfs_alloc.h +++ b/fs/xfs/xfs_alloc.h @@ -140,7 +140,7 @@ xfs_alloc_busy_insert(struct xfs_trans *tp, xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len); void -xfs_alloc_busy_clear(struct xfs_mount *mp, struct xfs_busy_extent *busyp); +xfs_alloc_busy_clear(struct xfs_mount *mp, struct list_head *list); int xfs_alloc_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno, @@ -149,6 +149,15 @@ xfs_alloc_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno, void xfs_alloc_busy_reuse(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t fbno, xfs_extlen_t flen, bool userdata); + +int +xfs_busy_extent_ag_cmp(void *priv, struct list_head *a, struct list_head *b); + +static inline void xfs_alloc_busy_sort(struct list_head *list) +{ + list_sort(NULL, list, xfs_busy_extent_ag_cmp); +} + #endif /* __KERNEL__ */ /* diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c index 9ca59be0897..7d56e88a3f0 100644 --- a/fs/xfs/xfs_log_cil.c +++ b/fs/xfs/xfs_log_cil.c @@ -361,13 +361,12 @@ xlog_cil_committed( int abort) { struct xfs_cil_ctx *ctx = args; - struct xfs_busy_extent *busyp, *n; xfs_trans_committed_bulk(ctx->cil->xc_log->l_ailp, ctx->lv_chain, ctx->start_lsn, abort); - list_for_each_entry_safe(busyp, n, &ctx->busy_extents, list) - xfs_alloc_busy_clear(ctx->cil->xc_log->l_mp, busyp); + xfs_alloc_busy_sort(&ctx->busy_extents); + xfs_alloc_busy_clear(ctx->cil->xc_log->l_mp, &ctx->busy_extents); spin_lock(&ctx->cil->xc_cil_lock); list_del(&ctx->committing); diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 76922793f64..d1f24858ccc 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -608,10 +608,8 @@ STATIC void xfs_trans_free( struct xfs_trans *tp) { - struct xfs_busy_extent *busyp, *n; - - list_for_each_entry_safe(busyp, n, &tp->t_busy, list) - xfs_alloc_busy_clear(tp->t_mountp, busyp); + xfs_alloc_busy_sort(&tp->t_busy); + xfs_alloc_busy_clear(tp->t_mountp, &tp->t_busy); atomic_dec(&tp->t_mountp->m_active_trans); xfs_trans_free_dqinfo(tp); -- cgit v1.2.3-70-g09d2 From e84661aa84e2e003738563f65155d4f12dc474e7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 20 May 2011 13:45:32 +0000 Subject: xfs: add online discard support Now that we have reliably tracking of deleted extents in a transaction we can easily implement "online" discard support which calls blkdev_issue_discard once a transaction commits. The actual discard is a two stage operation as we first have to mark the busy extent as not available for reuse before we can start the actual discard. Note that we don't bother supporting discard for the non-delaylog mode. Signed-off-by: Christoph Hellwig Signed-off-by: Alex Elder --- Documentation/filesystems/xfs.txt | 6 ++++++ fs/xfs/linux-2.6/xfs_discard.c | 29 +++++++++++++++++++++++++++++ fs/xfs/linux-2.6/xfs_discard.h | 2 ++ fs/xfs/linux-2.6/xfs_super.c | 18 ++++++++++++++++-- fs/xfs/xfs_ag.h | 2 ++ fs/xfs/xfs_alloc.c | 28 +++++++++++++++++++++++++--- fs/xfs/xfs_alloc.h | 3 ++- fs/xfs/xfs_log_cil.c | 13 ++++++++++++- fs/xfs/xfs_mount.h | 1 + fs/xfs/xfs_trans.c | 2 +- 10 files changed, 96 insertions(+), 8 deletions(-) (limited to 'fs/xfs/xfs_alloc.h') diff --git a/Documentation/filesystems/xfs.txt b/Documentation/filesystems/xfs.txt index 7bff3e4f35d..3fc0c31a6f5 100644 --- a/Documentation/filesystems/xfs.txt +++ b/Documentation/filesystems/xfs.txt @@ -39,6 +39,12 @@ When mounting an XFS filesystem, the following options are accepted. drive level write caching to be enabled, for devices that support write barriers. + discard + Issue command to let the block device reclaim space freed by the + filesystem. This is useful for SSD devices, thinly provisioned + LUNs and virtual machine images, but may have a performance + impact. This option is incompatible with the nodelaylog option. + dmapi Enable the DMAPI (Data Management API) event callouts. Use with the "mtpt" option. diff --git a/fs/xfs/linux-2.6/xfs_discard.c b/fs/xfs/linux-2.6/xfs_discard.c index d61611c8801..244e797dae3 100644 --- a/fs/xfs/linux-2.6/xfs_discard.c +++ b/fs/xfs/linux-2.6/xfs_discard.c @@ -191,3 +191,32 @@ xfs_ioc_trim( return -XFS_ERROR(EFAULT); return 0; } + +int +xfs_discard_extents( + struct xfs_mount *mp, + struct list_head *list) +{ + struct xfs_busy_extent *busyp; + int error = 0; + + list_for_each_entry(busyp, list, list) { + trace_xfs_discard_extent(mp, busyp->agno, busyp->bno, + busyp->length); + + error = -blkdev_issue_discard(mp->m_ddev_targp->bt_bdev, + XFS_AGB_TO_DADDR(mp, busyp->agno, busyp->bno), + XFS_FSB_TO_BB(mp, busyp->length), + GFP_NOFS, 0); + if (error && error != EOPNOTSUPP) { + xfs_info(mp, + "discard failed for extent [0x%llu,%u], error %d", + (unsigned long long)busyp->bno, + busyp->length, + error); + return error; + } + } + + return 0; +} diff --git a/fs/xfs/linux-2.6/xfs_discard.h b/fs/xfs/linux-2.6/xfs_discard.h index e82b6dd3e12..344879aea64 100644 --- a/fs/xfs/linux-2.6/xfs_discard.h +++ b/fs/xfs/linux-2.6/xfs_discard.h @@ -2,7 +2,9 @@ #define XFS_DISCARD_H 1 struct fstrim_range; +struct list_head; extern int xfs_ioc_trim(struct xfs_mount *, struct fstrim_range __user *); +extern int xfs_discard_extents(struct xfs_mount *, struct list_head *); #endif /* XFS_DISCARD_H */ diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index b0aa59e51fd..98b9c91fcdf 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -110,8 +110,10 @@ mempool_t *xfs_ioend_pool; #define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */ #define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */ #define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */ -#define MNTOPT_DELAYLOG "delaylog" /* Delayed loging enabled */ -#define MNTOPT_NODELAYLOG "nodelaylog" /* Delayed loging disabled */ +#define MNTOPT_DELAYLOG "delaylog" /* Delayed logging enabled */ +#define MNTOPT_NODELAYLOG "nodelaylog" /* Delayed logging disabled */ +#define MNTOPT_DISCARD "discard" /* Discard unused blocks */ +#define MNTOPT_NODISCARD "nodiscard" /* Do not discard unused blocks */ /* * Table driven mount option parser. @@ -355,6 +357,10 @@ xfs_parseargs( mp->m_flags |= XFS_MOUNT_DELAYLOG; } else if (!strcmp(this_char, MNTOPT_NODELAYLOG)) { mp->m_flags &= ~XFS_MOUNT_DELAYLOG; + } else if (!strcmp(this_char, MNTOPT_DISCARD)) { + mp->m_flags |= XFS_MOUNT_DISCARD; + } else if (!strcmp(this_char, MNTOPT_NODISCARD)) { + mp->m_flags &= ~XFS_MOUNT_DISCARD; } else if (!strcmp(this_char, "ihashsize")) { xfs_warn(mp, "ihashsize no longer used, option is deprecated."); @@ -388,6 +394,13 @@ xfs_parseargs( return EINVAL; } + if ((mp->m_flags & XFS_MOUNT_DISCARD) && + !(mp->m_flags & XFS_MOUNT_DELAYLOG)) { + xfs_warn(mp, + "the discard option is incompatible with the nodelaylog option"); + return EINVAL; + } + #ifndef CONFIG_XFS_QUOTA if (XFS_IS_QUOTA_RUNNING(mp)) { xfs_warn(mp, "quota support not available in this kernel."); @@ -488,6 +501,7 @@ xfs_showargs( { XFS_MOUNT_FILESTREAMS, "," MNTOPT_FILESTREAM }, { XFS_MOUNT_GRPID, "," MNTOPT_GRPID }, { XFS_MOUNT_DELAYLOG, "," MNTOPT_DELAYLOG }, + { XFS_MOUNT_DISCARD, "," MNTOPT_DISCARD }, { 0, NULL } }; static struct proc_xfs_info xfs_info_unset[] = { diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h index da0a561ffba..8d52ba4c87e 100644 --- a/fs/xfs/xfs_ag.h +++ b/fs/xfs/xfs_ag.h @@ -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_DISCARDED 0x01 /* undergoing a discard op. */ }; /* diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index acdced86413..721db22c6ec 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -2608,6 +2608,18 @@ xfs_alloc_busy_update_extent( xfs_agblock_t bbno = busyp->bno; 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. @@ -2813,7 +2825,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)) @@ -2979,10 +2992,16 @@ xfs_alloc_busy_clear_one( 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) + struct list_head *list, + bool do_discard) { struct xfs_busy_extent *busyp, *n; struct xfs_perag *pag = NULL; @@ -2999,7 +3018,10 @@ xfs_alloc_busy_clear( agno = busyp->agno; } - xfs_alloc_busy_clear_one(mp, pag, busyp); + if (do_discard && busyp->length) + busyp->flags = XFS_ALLOC_BUSY_DISCARDED; + else + xfs_alloc_busy_clear_one(mp, pag, busyp); } if (pag) { diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h index 240ad288f2f..06aa8217452 100644 --- a/fs/xfs/xfs_alloc.h +++ b/fs/xfs/xfs_alloc.h @@ -140,7 +140,8 @@ xfs_alloc_busy_insert(struct xfs_trans *tp, xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len); void -xfs_alloc_busy_clear(struct xfs_mount *mp, struct list_head *list); +xfs_alloc_busy_clear(struct xfs_mount *mp, struct list_head *list, + bool do_discard); int xfs_alloc_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno, diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c index 7d56e88a3f0..c7755d5a5fb 100644 --- a/fs/xfs/xfs_log_cil.c +++ b/fs/xfs/xfs_log_cil.c @@ -29,6 +29,7 @@ #include "xfs_mount.h" #include "xfs_error.h" #include "xfs_alloc.h" +#include "xfs_discard.h" /* * Perform initial CIL structure initialisation. If the CIL is not @@ -361,18 +362,28 @@ xlog_cil_committed( int abort) { struct xfs_cil_ctx *ctx = args; + struct xfs_mount *mp = ctx->cil->xc_log->l_mp; xfs_trans_committed_bulk(ctx->cil->xc_log->l_ailp, ctx->lv_chain, ctx->start_lsn, abort); xfs_alloc_busy_sort(&ctx->busy_extents); - xfs_alloc_busy_clear(ctx->cil->xc_log->l_mp, &ctx->busy_extents); + xfs_alloc_busy_clear(mp, &ctx->busy_extents, + (mp->m_flags & XFS_MOUNT_DISCARD) && !abort); spin_lock(&ctx->cil->xc_cil_lock); list_del(&ctx->committing); spin_unlock(&ctx->cil->xc_cil_lock); xlog_cil_free_logvec(ctx->lv_chain); + + if (!list_empty(&ctx->busy_extents)) { + ASSERT(mp->m_flags & XFS_MOUNT_DISCARD); + + xfs_discard_extents(mp, &ctx->busy_extents); + xfs_alloc_busy_clear(mp, &ctx->busy_extents, false); + } + kmem_free(ctx); } diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 19af0ab0d0c..3d68bb267c5 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -224,6 +224,7 @@ typedef struct xfs_mount { #define XFS_MOUNT_FS_SHUTDOWN (1ULL << 4) /* atomic stop of all filesystem operations, typically for disk errors in metadata */ +#define XFS_MOUNT_DISCARD (1ULL << 5) /* discard unused blocks */ #define XFS_MOUNT_RETERR (1ULL << 6) /* return alignment errors to user */ #define XFS_MOUNT_NOALIGN (1ULL << 7) /* turn off stripe alignment diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index d1f24858ccc..7c7bc2b786b 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -609,7 +609,7 @@ xfs_trans_free( struct xfs_trans *tp) { xfs_alloc_busy_sort(&tp->t_busy); - xfs_alloc_busy_clear(tp->t_mountp, &tp->t_busy); + xfs_alloc_busy_clear(tp->t_mountp, &tp->t_busy, false); atomic_dec(&tp->t_mountp->m_active_trans); xfs_trans_free_dqinfo(tp); -- cgit v1.2.3-70-g09d2 From 55a7bc5a30ff2d30d8a34fea2af9fc601b32e61a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 4 May 2011 18:55:15 +0000 Subject: xfs: do not discard alloc btree blocks Blocks for the allocation btree are allocated from and released to the AGFL, and thus frequently reused. Even worse we do not have an easy way to avoid using an AGFL block when it is discarded due to the simple FILO list of free blocks, and thus can frequently stall on blocks that are currently undergoing a discard. Add a flag to the busy extent tracking structure to skip the discard for allocation btree blocks. In normal operation these blocks are reused frequently enough that there is no need to discard them anyway, but if they spill over to the allocation btree as part of a balance we "leak" blocks that we would otherwise discard. We could fix this by adding another flag and keeping these block in the rbtree even after they aren't busy any more so that we could discard them when they migrate out of the AGFL. Given that this would cause significant overhead I don't think it's worthwile for now. Signed-off-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/xfs_ag.h | 1 + fs/xfs/xfs_alloc.c | 9 ++++++--- fs/xfs/xfs_alloc.h | 2 +- fs/xfs/xfs_alloc_btree.c | 3 ++- 4 files changed, 10 insertions(+), 5 deletions(-) (limited to 'fs/xfs/xfs_alloc.h') diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h index 8d52ba4c87e..6530769a999 100644 --- a/fs/xfs/xfs_ag.h +++ b/fs/xfs/xfs_ag.h @@ -189,6 +189,7 @@ struct xfs_busy_extent { xfs_extlen_t length; unsigned int flags; #define XFS_ALLOC_BUSY_DISCARDED 0x01 /* undergoing a discard op. */ +#define XFS_ALLOC_BUSY_SKIP_DISCARD 0x02 /* do not discard */ }; /* diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 721db22c6ec..95862bbff56 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -2469,7 +2469,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; @@ -2480,7 +2480,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; @@ -2504,6 +2505,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); @@ -3018,7 +3020,8 @@ xfs_alloc_busy_clear( agno = busyp->agno; } - if (do_discard && busyp->length) + 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); diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h index 06aa8217452..2f52b924be7 100644 --- a/fs/xfs/xfs_alloc.h +++ b/fs/xfs/xfs_alloc.h @@ -137,7 +137,7 @@ xfs_alloc_longest_free_extent(struct xfs_mount *mp, #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, unsigned int flags); void xfs_alloc_busy_clear(struct xfs_mount *mp, struct list_head *list, diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index 8b469d53599..2b3518826a6 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c @@ -120,7 +120,8 @@ xfs_allocbt_free_block( if (error) return error; - 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, + XFS_ALLOC_BUSY_SKIP_DISCARD); xfs_trans_agbtree_delta(cur->bc_tp, -1); return 0; } -- cgit v1.2.3-70-g09d2