diff options
Diffstat (limited to 'fs/xfs/xfs_alloc.c')
-rw-r--r-- | fs/xfs/xfs_alloc.c | 35 |
1 files changed, 30 insertions, 5 deletions
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index acdced86413c..95862bbff56b 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c | |||
@@ -2469,7 +2469,7 @@ xfs_free_extent( | |||
2469 | 2469 | ||
2470 | error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0); | 2470 | error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0); |
2471 | if (!error) | 2471 | if (!error) |
2472 | xfs_alloc_busy_insert(tp, args.agno, args.agbno, len); | 2472 | xfs_alloc_busy_insert(tp, args.agno, args.agbno, len, 0); |
2473 | error0: | 2473 | error0: |
2474 | xfs_perag_put(args.pag); | 2474 | xfs_perag_put(args.pag); |
2475 | return error; | 2475 | return error; |
@@ -2480,7 +2480,8 @@ xfs_alloc_busy_insert( | |||
2480 | struct xfs_trans *tp, | 2480 | struct xfs_trans *tp, |
2481 | xfs_agnumber_t agno, | 2481 | xfs_agnumber_t agno, |
2482 | xfs_agblock_t bno, | 2482 | xfs_agblock_t bno, |
2483 | xfs_extlen_t len) | 2483 | xfs_extlen_t len, |
2484 | unsigned int flags) | ||
2484 | { | 2485 | { |
2485 | struct xfs_busy_extent *new; | 2486 | struct xfs_busy_extent *new; |
2486 | struct xfs_busy_extent *busyp; | 2487 | struct xfs_busy_extent *busyp; |
@@ -2504,6 +2505,7 @@ xfs_alloc_busy_insert( | |||
2504 | new->bno = bno; | 2505 | new->bno = bno; |
2505 | new->length = len; | 2506 | new->length = len; |
2506 | INIT_LIST_HEAD(&new->list); | 2507 | INIT_LIST_HEAD(&new->list); |
2508 | new->flags = flags; | ||
2507 | 2509 | ||
2508 | /* trace before insert to be able to see failed inserts */ | 2510 | /* trace before insert to be able to see failed inserts */ |
2509 | trace_xfs_alloc_busy(tp->t_mountp, agno, bno, len); | 2511 | trace_xfs_alloc_busy(tp->t_mountp, agno, bno, len); |
@@ -2609,6 +2611,18 @@ xfs_alloc_busy_update_extent( | |||
2609 | xfs_agblock_t bend = bbno + busyp->length; | 2611 | xfs_agblock_t bend = bbno + busyp->length; |
2610 | 2612 | ||
2611 | /* | 2613 | /* |
2614 | * This extent is currently being discarded. Give the thread | ||
2615 | * performing the discard a chance to mark the extent unbusy | ||
2616 | * and retry. | ||
2617 | */ | ||
2618 | if (busyp->flags & XFS_ALLOC_BUSY_DISCARDED) { | ||
2619 | spin_unlock(&pag->pagb_lock); | ||
2620 | delay(1); | ||
2621 | spin_lock(&pag->pagb_lock); | ||
2622 | return false; | ||
2623 | } | ||
2624 | |||
2625 | /* | ||
2612 | * If there is a busy extent overlapping a user allocation, we have | 2626 | * If there is a busy extent overlapping a user allocation, we have |
2613 | * no choice but to force the log and retry the search. | 2627 | * no choice but to force the log and retry the search. |
2614 | * | 2628 | * |
@@ -2813,7 +2827,8 @@ restart: | |||
2813 | * If this is a metadata allocation, try to reuse the busy | 2827 | * If this is a metadata allocation, try to reuse the busy |
2814 | * extent instead of trimming the allocation. | 2828 | * extent instead of trimming the allocation. |
2815 | */ | 2829 | */ |
2816 | if (!args->userdata) { | 2830 | if (!args->userdata && |
2831 | !(busyp->flags & XFS_ALLOC_BUSY_DISCARDED)) { | ||
2817 | if (!xfs_alloc_busy_update_extent(args->mp, args->pag, | 2832 | if (!xfs_alloc_busy_update_extent(args->mp, args->pag, |
2818 | busyp, fbno, flen, | 2833 | busyp, fbno, flen, |
2819 | false)) | 2834 | false)) |
@@ -2979,10 +2994,16 @@ xfs_alloc_busy_clear_one( | |||
2979 | kmem_free(busyp); | 2994 | kmem_free(busyp); |
2980 | } | 2995 | } |
2981 | 2996 | ||
2997 | /* | ||
2998 | * Remove all extents on the passed in list from the busy extents tree. | ||
2999 | * If do_discard is set skip extents that need to be discarded, and mark | ||
3000 | * these as undergoing a discard operation instead. | ||
3001 | */ | ||
2982 | void | 3002 | void |
2983 | xfs_alloc_busy_clear( | 3003 | xfs_alloc_busy_clear( |
2984 | struct xfs_mount *mp, | 3004 | struct xfs_mount *mp, |
2985 | struct list_head *list) | 3005 | struct list_head *list, |
3006 | bool do_discard) | ||
2986 | { | 3007 | { |
2987 | struct xfs_busy_extent *busyp, *n; | 3008 | struct xfs_busy_extent *busyp, *n; |
2988 | struct xfs_perag *pag = NULL; | 3009 | struct xfs_perag *pag = NULL; |
@@ -2999,7 +3020,11 @@ xfs_alloc_busy_clear( | |||
2999 | agno = busyp->agno; | 3020 | agno = busyp->agno; |
3000 | } | 3021 | } |
3001 | 3022 | ||
3002 | xfs_alloc_busy_clear_one(mp, pag, busyp); | 3023 | if (do_discard && busyp->length && |
3024 | !(busyp->flags & XFS_ALLOC_BUSY_SKIP_DISCARD)) | ||
3025 | busyp->flags = XFS_ALLOC_BUSY_DISCARDED; | ||
3026 | else | ||
3027 | xfs_alloc_busy_clear_one(mp, pag, busyp); | ||
3003 | } | 3028 | } |
3004 | 3029 | ||
3005 | if (pag) { | 3030 | if (pag) { |