Skip to content

Commit 428c443

Browse files
Dave Chinnerdchinner
authored andcommitted
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>
1 parent 8a749fd commit 428c443

File tree

5 files changed

+113
-88
lines changed

5 files changed

+113
-88
lines changed

fs/xfs/xfs_discard.c

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0
22
/*
3-
* Copyright (C) 2010 Red Hat, Inc.
3+
* Copyright (C) 2010, 2023 Red Hat, Inc.
44
* All Rights Reserved.
55
*/
66
#include "xfs.h"
@@ -19,6 +19,81 @@
1919
#include "xfs_log.h"
2020
#include "xfs_ag.h"
2121

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+
96+
2297
STATIC int
2398
xfs_trim_extents(
2499
struct xfs_perag *pag,

fs/xfs/xfs_discard.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
#define XFS_DISCARD_H 1
44

55
struct fstrim_range;
6-
struct list_head;
6+
struct xfs_mount;
7+
struct xfs_busy_extents;
78

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);
911

1012
#endif /* XFS_DISCARD_H */

fs/xfs/xfs_extent_busy.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ struct xfs_alloc_arg;
1616
/*
1717
* Busy block/extent entry. Indexed by a rbtree in perag to mark blocks that
1818
* 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.
2219
*/
2320
struct xfs_extent_busy {
2421
struct rb_node rb_node; /* ag by-bno indexed search tree */
@@ -31,6 +28,23 @@ struct xfs_extent_busy {
3128
#define XFS_EXTENT_BUSY_SKIP_DISCARD 0x02 /* do not discard */
3229
};
3330

31+
/*
32+
* List used to track groups of related busy extents all the way through
33+
* to discard completion.
34+
*/
35+
struct xfs_busy_extents {
36+
struct xfs_mount *mount;
37+
struct list_head extent_list;
38+
struct work_struct endio_work;
39+
40+
/*
41+
* Owner is the object containing the struct xfs_busy_extents to free
42+
* once the busy extents have been processed. If only the
43+
* xfs_busy_extents object needs freeing, then point this at itself.
44+
*/
45+
void *owner;
46+
};
47+
3448
void
3549
xfs_extent_busy_insert(struct xfs_trans *tp, struct xfs_perag *pag,
3650
xfs_agblock_t bno, xfs_extlen_t len, unsigned int flags);

fs/xfs/xfs_log_cil.c

Lines changed: 13 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616
#include "xfs_log.h"
1717
#include "xfs_log_priv.h"
1818
#include "xfs_trace.h"
19-
20-
struct workqueue_struct *xfs_discard_wq;
19+
#include "xfs_discard.h"
2120

2221
/*
2322
* Allocate a new ticket. Failing to get a new ticket makes it really hard to
@@ -103,7 +102,7 @@ xlog_cil_ctx_alloc(void)
103102

104103
ctx = kmem_zalloc(sizeof(*ctx), KM_NOFS);
105104
INIT_LIST_HEAD(&ctx->committing);
106-
INIT_LIST_HEAD(&ctx->busy_extents);
105+
INIT_LIST_HEAD(&ctx->busy_extents.extent_list);
107106
INIT_LIST_HEAD(&ctx->log_items);
108107
INIT_LIST_HEAD(&ctx->lv_chain);
109108
INIT_WORK(&ctx->push_work, xlog_cil_push_work);
@@ -132,7 +131,7 @@ xlog_cil_push_pcp_aggregate(
132131

133132
if (!list_empty(&cilpcp->busy_extents)) {
134133
list_splice_init(&cilpcp->busy_extents,
135-
&ctx->busy_extents);
134+
&ctx->busy_extents.extent_list);
136135
}
137136
if (!list_empty(&cilpcp->log_items))
138137
list_splice_init(&cilpcp->log_items, &ctx->log_items);
@@ -708,76 +707,6 @@ xlog_cil_free_logvec(
708707
}
709708
}
710709

711-
static void
712-
xlog_discard_endio_work(
713-
struct work_struct *work)
714-
{
715-
struct xfs_cil_ctx *ctx =
716-
container_of(work, struct xfs_cil_ctx, discard_endio_work);
717-
struct xfs_mount *mp = ctx->cil->xc_log->l_mp;
718-
719-
xfs_extent_busy_clear(mp, &ctx->busy_extents, false);
720-
kmem_free(ctx);
721-
}
722-
723-
/*
724-
* Queue up the actual completion to a thread to avoid IRQ-safe locking for
725-
* pagb_lock. Note that we need a unbounded workqueue, otherwise we might
726-
* get the execution delayed up to 30 seconds for weird reasons.
727-
*/
728-
static void
729-
xlog_discard_endio(
730-
struct bio *bio)
731-
{
732-
struct xfs_cil_ctx *ctx = bio->bi_private;
733-
734-
INIT_WORK(&ctx->discard_endio_work, xlog_discard_endio_work);
735-
queue_work(xfs_discard_wq, &ctx->discard_endio_work);
736-
bio_put(bio);
737-
}
738-
739-
static void
740-
xlog_discard_busy_extents(
741-
struct xfs_mount *mp,
742-
struct xfs_cil_ctx *ctx)
743-
{
744-
struct list_head *list = &ctx->busy_extents;
745-
struct xfs_extent_busy *busyp;
746-
struct bio *bio = NULL;
747-
struct blk_plug plug;
748-
int error = 0;
749-
750-
ASSERT(xfs_has_discard(mp));
751-
752-
blk_start_plug(&plug);
753-
list_for_each_entry(busyp, list, list) {
754-
trace_xfs_discard_extent(mp, busyp->agno, busyp->bno,
755-
busyp->length);
756-
757-
error = __blkdev_issue_discard(mp->m_ddev_targp->bt_bdev,
758-
XFS_AGB_TO_DADDR(mp, busyp->agno, busyp->bno),
759-
XFS_FSB_TO_BB(mp, busyp->length),
760-
GFP_NOFS, &bio);
761-
if (error && error != -EOPNOTSUPP) {
762-
xfs_info(mp,
763-
"discard failed for extent [0x%llx,%u], error %d",
764-
(unsigned long long)busyp->bno,
765-
busyp->length,
766-
error);
767-
break;
768-
}
769-
}
770-
771-
if (bio) {
772-
bio->bi_private = ctx;
773-
bio->bi_end_io = xlog_discard_endio;
774-
submit_bio(bio);
775-
} else {
776-
xlog_discard_endio_work(&ctx->discard_endio_work);
777-
}
778-
blk_finish_plug(&plug);
779-
}
780-
781710
/*
782711
* Mark all items committed and clear busy extents. We free the log vector
783712
* chains in a separate pass so that we unpin the log items as quickly as
@@ -807,8 +736,8 @@ xlog_cil_committed(
807736
xfs_trans_committed_bulk(ctx->cil->xc_log->l_ailp, &ctx->lv_chain,
808737
ctx->start_lsn, abort);
809738

810-
xfs_extent_busy_sort(&ctx->busy_extents);
811-
xfs_extent_busy_clear(mp, &ctx->busy_extents,
739+
xfs_extent_busy_sort(&ctx->busy_extents.extent_list);
740+
xfs_extent_busy_clear(mp, &ctx->busy_extents.extent_list,
812741
xfs_has_discard(mp) && !abort);
813742

814743
spin_lock(&ctx->cil->xc_push_lock);
@@ -817,10 +746,14 @@ xlog_cil_committed(
817746

818747
xlog_cil_free_logvec(&ctx->lv_chain);
819748

820-
if (!list_empty(&ctx->busy_extents))
821-
xlog_discard_busy_extents(mp, ctx);
822-
else
823-
kmem_free(ctx);
749+
if (!list_empty(&ctx->busy_extents.extent_list)) {
750+
ctx->busy_extents.mount = mp;
751+
ctx->busy_extents.owner = ctx;
752+
xfs_discard_extents(mp, &ctx->busy_extents);
753+
return;
754+
}
755+
756+
kmem_free(ctx);
824757
}
825758

826759
void

fs/xfs/xfs_log_priv.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#ifndef __XFS_LOG_PRIV_H__
77
#define __XFS_LOG_PRIV_H__
88

9+
#include "xfs_extent_busy.h" /* for struct xfs_busy_extents */
10+
911
struct xfs_buf;
1012
struct xlog;
1113
struct xlog_ticket;
@@ -223,12 +225,11 @@ struct xfs_cil_ctx {
223225
struct xlog_in_core *commit_iclog;
224226
struct xlog_ticket *ticket; /* chkpt ticket */
225227
atomic_t space_used; /* aggregate size of regions */
226-
struct list_head busy_extents; /* busy extents in chkpt */
228+
struct xfs_busy_extents busy_extents;
227229
struct list_head log_items; /* log items in chkpt */
228230
struct list_head lv_chain; /* logvecs being pushed */
229231
struct list_head iclog_entry;
230232
struct list_head committing; /* ctx committing list */
231-
struct work_struct discard_endio_work;
232233
struct work_struct push_work;
233234
atomic_t order_id;
234235

0 commit comments

Comments
 (0)