xfs: move log discard work to xfs_discard.c

Because we are going to use the same list-based discard submission
interface for fstrim-based discards, too.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

authored by

Dave Chinner and committed by
Dave Chinner
428c4435 8a749fd1

+113 -88
+76 -1
fs/xfs/xfs_discard.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* 3 - * Copyright (C) 2010 Red Hat, Inc. 3 + * Copyright (C) 2010, 2023 Red Hat, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 6 #include "xfs.h" ··· 18 18 #include "xfs_trace.h" 19 19 #include "xfs_log.h" 20 20 #include "xfs_ag.h" 21 + 22 + struct workqueue_struct *xfs_discard_wq; 23 + 24 + static void 25 + xfs_discard_endio_work( 26 + struct work_struct *work) 27 + { 28 + struct xfs_busy_extents *extents = 29 + container_of(work, struct xfs_busy_extents, endio_work); 30 + 31 + xfs_extent_busy_clear(extents->mount, &extents->extent_list, false); 32 + kmem_free(extents->owner); 33 + } 34 + 35 + /* 36 + * Queue up the actual completion to a thread to avoid IRQ-safe locking for 37 + * pagb_lock. 38 + */ 39 + static void 40 + xfs_discard_endio( 41 + struct bio *bio) 42 + { 43 + struct xfs_busy_extents *extents = bio->bi_private; 44 + 45 + INIT_WORK(&extents->endio_work, xfs_discard_endio_work); 46 + queue_work(xfs_discard_wq, &extents->endio_work); 47 + bio_put(bio); 48 + } 49 + 50 + /* 51 + * Walk the discard list and issue discards on all the busy extents in the 52 + * list. We plug and chain the bios so that we only need a single completion 53 + * call to clear all the busy extents once the discards are complete. 54 + */ 55 + int 56 + xfs_discard_extents( 57 + struct xfs_mount *mp, 58 + struct xfs_busy_extents *extents) 59 + { 60 + struct xfs_extent_busy *busyp; 61 + struct bio *bio = NULL; 62 + struct blk_plug plug; 63 + int error = 0; 64 + 65 + blk_start_plug(&plug); 66 + list_for_each_entry(busyp, &extents->extent_list, list) { 67 + trace_xfs_discard_extent(mp, busyp->agno, busyp->bno, 68 + busyp->length); 69 + 70 + error = __blkdev_issue_discard(mp->m_ddev_targp->bt_bdev, 71 + XFS_AGB_TO_DADDR(mp, busyp->agno, busyp->bno), 72 + XFS_FSB_TO_BB(mp, busyp->length), 73 + GFP_NOFS, &bio); 74 + if (error && error != -EOPNOTSUPP) { 75 + xfs_info(mp, 76 + "discard failed for extent [0x%llx,%u], error %d", 77 + (unsigned long long)busyp->bno, 78 + busyp->length, 79 + error); 80 + break; 81 + } 82 + } 83 + 84 + if (bio) { 85 + bio->bi_private = extents; 86 + bio->bi_end_io = xfs_discard_endio; 87 + submit_bio(bio); 88 + } else { 89 + xfs_discard_endio_work(&extents->endio_work); 90 + } 91 + blk_finish_plug(&plug); 92 + 93 + return error; 94 + } 95 + 21 96 22 97 STATIC int 23 98 xfs_trim_extents(
+4 -2
fs/xfs/xfs_discard.h
··· 3 3 #define XFS_DISCARD_H 1 4 4 5 5 struct fstrim_range; 6 - struct list_head; 6 + struct xfs_mount; 7 + struct xfs_busy_extents; 7 8 8 - extern int xfs_ioc_trim(struct xfs_mount *, struct fstrim_range __user *); 9 + int xfs_discard_extents(struct xfs_mount *mp, struct xfs_busy_extents *busy); 10 + int xfs_ioc_trim(struct xfs_mount *mp, struct fstrim_range __user *fstrim); 9 11 10 12 #endif /* XFS_DISCARD_H */
+17 -3
fs/xfs/xfs_extent_busy.h
··· 16 16 /* 17 17 * Busy block/extent entry. Indexed by a rbtree in perag to mark blocks that 18 18 * have been freed but whose transactions aren't committed to disk yet. 19 - * 20 - * Note that we use the transaction ID to record the transaction, not the 21 - * transaction structure itself. See xfs_extent_busy_insert() for details. 22 19 */ 23 20 struct xfs_extent_busy { 24 21 struct rb_node rb_node; /* ag by-bno indexed search tree */ ··· 26 29 unsigned int flags; 27 30 #define XFS_EXTENT_BUSY_DISCARDED 0x01 /* undergoing a discard op. */ 28 31 #define XFS_EXTENT_BUSY_SKIP_DISCARD 0x02 /* do not discard */ 32 + }; 33 + 34 + /* 35 + * List used to track groups of related busy extents all the way through 36 + * to discard completion. 37 + */ 38 + struct xfs_busy_extents { 39 + struct xfs_mount *mount; 40 + struct list_head extent_list; 41 + struct work_struct endio_work; 42 + 43 + /* 44 + * Owner is the object containing the struct xfs_busy_extents to free 45 + * once the busy extents have been processed. If only the 46 + * xfs_busy_extents object needs freeing, then point this at itself. 47 + */ 48 + void *owner; 29 49 }; 30 50 31 51 void
+13 -80
fs/xfs/xfs_log_cil.c
··· 16 16 #include "xfs_log.h" 17 17 #include "xfs_log_priv.h" 18 18 #include "xfs_trace.h" 19 - 20 - struct workqueue_struct *xfs_discard_wq; 19 + #include "xfs_discard.h" 21 20 22 21 /* 23 22 * Allocate a new ticket. Failing to get a new ticket makes it really hard to ··· 102 103 103 104 ctx = kmem_zalloc(sizeof(*ctx), KM_NOFS); 104 105 INIT_LIST_HEAD(&ctx->committing); 105 - INIT_LIST_HEAD(&ctx->busy_extents); 106 + INIT_LIST_HEAD(&ctx->busy_extents.extent_list); 106 107 INIT_LIST_HEAD(&ctx->log_items); 107 108 INIT_LIST_HEAD(&ctx->lv_chain); 108 109 INIT_WORK(&ctx->push_work, xlog_cil_push_work); ··· 131 132 132 133 if (!list_empty(&cilpcp->busy_extents)) { 133 134 list_splice_init(&cilpcp->busy_extents, 134 - &ctx->busy_extents); 135 + &ctx->busy_extents.extent_list); 135 136 } 136 137 if (!list_empty(&cilpcp->log_items)) 137 138 list_splice_init(&cilpcp->log_items, &ctx->log_items); ··· 707 708 } 708 709 } 709 710 710 - static void 711 - xlog_discard_endio_work( 712 - struct work_struct *work) 713 - { 714 - struct xfs_cil_ctx *ctx = 715 - container_of(work, struct xfs_cil_ctx, discard_endio_work); 716 - struct xfs_mount *mp = ctx->cil->xc_log->l_mp; 717 - 718 - xfs_extent_busy_clear(mp, &ctx->busy_extents, false); 719 - kmem_free(ctx); 720 - } 721 - 722 - /* 723 - * Queue up the actual completion to a thread to avoid IRQ-safe locking for 724 - * pagb_lock. Note that we need a unbounded workqueue, otherwise we might 725 - * get the execution delayed up to 30 seconds for weird reasons. 726 - */ 727 - static void 728 - xlog_discard_endio( 729 - struct bio *bio) 730 - { 731 - struct xfs_cil_ctx *ctx = bio->bi_private; 732 - 733 - INIT_WORK(&ctx->discard_endio_work, xlog_discard_endio_work); 734 - queue_work(xfs_discard_wq, &ctx->discard_endio_work); 735 - bio_put(bio); 736 - } 737 - 738 - static void 739 - xlog_discard_busy_extents( 740 - struct xfs_mount *mp, 741 - struct xfs_cil_ctx *ctx) 742 - { 743 - struct list_head *list = &ctx->busy_extents; 744 - struct xfs_extent_busy *busyp; 745 - struct bio *bio = NULL; 746 - struct blk_plug plug; 747 - int error = 0; 748 - 749 - ASSERT(xfs_has_discard(mp)); 750 - 751 - blk_start_plug(&plug); 752 - list_for_each_entry(busyp, list, list) { 753 - trace_xfs_discard_extent(mp, busyp->agno, busyp->bno, 754 - busyp->length); 755 - 756 - error = __blkdev_issue_discard(mp->m_ddev_targp->bt_bdev, 757 - XFS_AGB_TO_DADDR(mp, busyp->agno, busyp->bno), 758 - XFS_FSB_TO_BB(mp, busyp->length), 759 - GFP_NOFS, &bio); 760 - if (error && error != -EOPNOTSUPP) { 761 - xfs_info(mp, 762 - "discard failed for extent [0x%llx,%u], error %d", 763 - (unsigned long long)busyp->bno, 764 - busyp->length, 765 - error); 766 - break; 767 - } 768 - } 769 - 770 - if (bio) { 771 - bio->bi_private = ctx; 772 - bio->bi_end_io = xlog_discard_endio; 773 - submit_bio(bio); 774 - } else { 775 - xlog_discard_endio_work(&ctx->discard_endio_work); 776 - } 777 - blk_finish_plug(&plug); 778 - } 779 - 780 711 /* 781 712 * Mark all items committed and clear busy extents. We free the log vector 782 713 * chains in a separate pass so that we unpin the log items as quickly as ··· 736 807 xfs_trans_committed_bulk(ctx->cil->xc_log->l_ailp, &ctx->lv_chain, 737 808 ctx->start_lsn, abort); 738 809 739 - xfs_extent_busy_sort(&ctx->busy_extents); 740 - xfs_extent_busy_clear(mp, &ctx->busy_extents, 810 + xfs_extent_busy_sort(&ctx->busy_extents.extent_list); 811 + xfs_extent_busy_clear(mp, &ctx->busy_extents.extent_list, 741 812 xfs_has_discard(mp) && !abort); 742 813 743 814 spin_lock(&ctx->cil->xc_push_lock); ··· 746 817 747 818 xlog_cil_free_logvec(&ctx->lv_chain); 748 819 749 - if (!list_empty(&ctx->busy_extents)) 750 - xlog_discard_busy_extents(mp, ctx); 751 - else 752 - kmem_free(ctx); 820 + if (!list_empty(&ctx->busy_extents.extent_list)) { 821 + ctx->busy_extents.mount = mp; 822 + ctx->busy_extents.owner = ctx; 823 + xfs_discard_extents(mp, &ctx->busy_extents); 824 + return; 825 + } 826 + 827 + kmem_free(ctx); 753 828 } 754 829 755 830 void
+3 -2
fs/xfs/xfs_log_priv.h
··· 6 6 #ifndef __XFS_LOG_PRIV_H__ 7 7 #define __XFS_LOG_PRIV_H__ 8 8 9 + #include "xfs_extent_busy.h" /* for struct xfs_busy_extents */ 10 + 9 11 struct xfs_buf; 10 12 struct xlog; 11 13 struct xlog_ticket; ··· 225 223 struct xlog_in_core *commit_iclog; 226 224 struct xlog_ticket *ticket; /* chkpt ticket */ 227 225 atomic_t space_used; /* aggregate size of regions */ 228 - struct list_head busy_extents; /* busy extents in chkpt */ 226 + struct xfs_busy_extents busy_extents; 229 227 struct list_head log_items; /* log items in chkpt */ 230 228 struct list_head lv_chain; /* logvecs being pushed */ 231 229 struct list_head iclog_entry; 232 230 struct list_head committing; /* ctx committing list */ 233 - struct work_struct discard_endio_work; 234 231 struct work_struct push_work; 235 232 atomic_t order_id; 236 233