History

Merge tag 'xfs-6.6-fixes-3' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull xfs fixes from Chandan Babu: - Prevent filesystem hang when executing fstrim operations on large and slow storage * tag 'xfs-6.6-fixes-3' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: abort fstrim if kernel is suspending xfs: reduce AGF hold times during fstrim operations xfs: move log discard work to xfs_discard.c

Linus Torvalds committed 3 years ago

Commit 102363a2 parents 4aef108 4e69f496 files · +311 −117Browse files

Unified · Split

6 files
  1. fs/xfs/xfs_discard.c +242 −24
  2. fs/xfs/xfs_discard.h +4 −2
  3. fs/xfs/xfs_extent_busy.c +28 −6
  4. fs/xfs/xfs_extent_busy.h +21 −3
  5. fs/xfs/xfs_log_cil.c +13 −80
  6. fs/xfs/xfs_log_priv.h +3 −2
fs/xfs/xfs_discard.c+242−24
@@ -1,6 +1,6 @@
1// SPDX-License-Identifier: GPL-2.01// SPDX-License-Identifier: GPL-2.0
2/*2/*
3 * Copyright (C) 2010 Red Hat, Inc.3 * Copyright (C) 2010, 2023 Red Hat, Inc.
4 * All Rights Reserved.4 * All Rights Reserved.
5 */5 */
6#include "xfs.h"6#include "xfs.h"
@@ -19,21 +19,147 @@ · 12 unmodified lines
19#include "xfs_log.h"19#include "xfs_log.h"
20#include "xfs_ag.h"20#include "xfs_ag.h"
21 21
22STATIC int22/*
23xfs_trim_extents(23 * Notes on an efficient, low latency fstrim algorithm
24 *
25 * We need to walk the filesystem free space and issue discards on the free
26 * space that meet the search criteria (size and location). We cannot issue
27 * discards on extents that might be in use, or are so recently in use they are
28 * still marked as busy. To serialise against extent state changes whilst we are
29 * gathering extents to trim, we must hold the AGF lock to lock out other
30 * allocations and extent free operations that might change extent state.
31 *
32 * However, we cannot just hold the AGF for the entire AG free space walk whilst
33 * we issue discards on each free space that is found. Storage devices can have
34 * extremely slow discard implementations (e.g. ceph RBD) and so walking a
35 * couple of million free extents and issuing synchronous discards on each
36 * extent can take a *long* time. Whilst we are doing this walk, nothing else
37 * can access the AGF, and we can stall transactions and hence the log whilst
38 * modifications wait for the AGF lock to be released. This can lead hung tasks
39 * kicking the hung task timer and rebooting the system. This is bad.
40 *
41 * Hence we need to take a leaf from the bulkstat playbook. It takes the AGI
42 * lock, gathers a range of inode cluster buffers that are allocated, drops the
43 * AGI lock and then reads all the inode cluster buffers and processes them. It
44 * loops doing this, using a cursor to keep track of where it is up to in the AG
45 * for each iteration to restart the INOBT lookup from.
46 *
47 * We can't do this exactly with free space - once we drop the AGF lock, the
48 * state of the free extent is out of our control and we cannot run a discard
49 * safely on it in this situation. Unless, of course, we've marked the free
50 * extent as busy and undergoing a discard operation whilst we held the AGF
51 * locked.
52 *
53 * This is exactly how online discard works - free extents are marked busy when
54 * they are freed, and once the extent free has been committed to the journal,
55 * the busy extent record is marked as "undergoing discard" and the discard is
56 * then issued on the free extent. Once the discard completes, the busy extent
57 * record is removed and the extent is able to be allocated again.
58 *
59 * In the context of fstrim, if we find a free extent we need to discard, we
60 * don't have to discard it immediately. All we need to do it record that free
61 * extent as being busy and under discard, and all the allocation routines will
62 * now avoid trying to allocate it. Hence if we mark the extent as busy under
63 * the AGF lock, we can safely discard it without holding the AGF lock because
64 * nothing will attempt to allocate that free space until the discard completes.
65 *
66 * This also allows us to issue discards asynchronously like we do with online
67 * discard, and so for fast devices fstrim will run much faster as we can have
68 * multiple discard operations in flight at once, as well as pipeline the free
69 * extent search so that it overlaps in flight discard IO.
70 */
71
72struct workqueue_struct *xfs_discard_wq;
73
74static void
75xfs_discard_endio_work(
76 struct work_struct *work)
77{
78 struct xfs_busy_extents *extents =
79 container_of(work, struct xfs_busy_extents, endio_work);
80
81 xfs_extent_busy_clear(extents->mount, &extents->extent_list, false);
82 kmem_free(extents->owner);
83}
84
85/*
86 * Queue up the actual completion to a thread to avoid IRQ-safe locking for
87 * pagb_lock.
88 */
89static void
90xfs_discard_endio(
91 struct bio *bio)
92{
93 struct xfs_busy_extents *extents = bio->bi_private;
94
95 INIT_WORK(&extents->endio_work, xfs_discard_endio_work);
96 queue_work(xfs_discard_wq, &extents->endio_work);
97 bio_put(bio);
98}
99
100/*
101 * Walk the discard list and issue discards on all the busy extents in the
102 * list. We plug and chain the bios so that we only need a single completion
103 * call to clear all the busy extents once the discards are complete.
104 */
105int
106xfs_discard_extents(
107 struct xfs_mount *mp,
108 struct xfs_busy_extents *extents)
109{
110 struct xfs_extent_busy *busyp;
111 struct bio *bio = NULL;
112 struct blk_plug plug;
113 int error = 0;
114
115 blk_start_plug(&plug);
116 list_for_each_entry(busyp, &extents->extent_list, list) {
117 trace_xfs_discard_extent(mp, busyp->agno, busyp->bno,
118 busyp->length);
119
120 error = __blkdev_issue_discard(mp->m_ddev_targp->bt_bdev,
121 XFS_AGB_TO_DADDR(mp, busyp->agno, busyp->bno),
122 XFS_FSB_TO_BB(mp, busyp->length),
123 GFP_NOFS, &bio);
124 if (error && error != -EOPNOTSUPP) {
125 xfs_info(mp,
126 "discard failed for extent [0x%llx,%u], error %d",
127 (unsigned long long)busyp->bno,
128 busyp->length,
129 error);
130 break;
131 }
132 }
133
134 if (bio) {
135 bio->bi_private = extents;
136 bio->bi_end_io = xfs_discard_endio;
137 submit_bio(bio);
138 } else {
139 xfs_discard_endio_work(&extents->endio_work);
140 }
141 blk_finish_plug(&plug);
142
143 return error;
144}
145
146
147static int
148xfs_trim_gather_extents(
24 struct xfs_perag *pag,149 struct xfs_perag *pag,
25 xfs_daddr_t start,150 xfs_daddr_t start,
26 xfs_daddr_t end,151 xfs_daddr_t end,
27 xfs_daddr_t minlen,152 xfs_daddr_t minlen,
153 struct xfs_alloc_rec_incore *tcur,
154 struct xfs_busy_extents *extents,
28 uint64_t *blocks_trimmed)155 uint64_t *blocks_trimmed)
29{156{
30 struct xfs_mount *mp = pag->pag_mount;157 struct xfs_mount *mp = pag->pag_mount;
31 struct block_device *bdev = mp->m_ddev_targp->bt_bdev;
32 struct xfs_btree_cur *cur;158 struct xfs_btree_cur *cur;
33 struct xfs_buf *agbp;159 struct xfs_buf *agbp;
34 struct xfs_agf *agf;
35 int error;160 int error;
36 int i;161 int i;
162 int batch = 100;
37 163
38 /*164 /*
39 * Force out the log. This means any transactions that might have freed165 * Force out the log. This means any transactions that might have freed
@@ -45,20 +171,28 @@ xfs_trim_extents( · 5 unmodified lines
45 error = xfs_alloc_read_agf(pag, NULL, 0, &agbp);171 error = xfs_alloc_read_agf(pag, NULL, 0, &agbp);
46 if (error)172 if (error)
47 return error;173 return error;
48 agf = agbp->b_addr;
49 174
50 cur = xfs_allocbt_init_cursor(mp, NULL, agbp, pag, XFS_BTNUM_CNT);175 cur = xfs_allocbt_init_cursor(mp, NULL, agbp, pag, XFS_BTNUM_CNT);
51 176
52 /*177 /*
53 * Look up the longest btree in the AGF and start with it.178 * Look up the extent length requested in the AGF and start with it.
54 */179 */
55 error = xfs_alloc_lookup_ge(cur, 0, be32_to_cpu(agf->agf_longest), &i);180 if (tcur->ar_startblock == NULLAGBLOCK)
181 error = xfs_alloc_lookup_ge(cur, 0, tcur->ar_blockcount, &i);
182 else
183 error = xfs_alloc_lookup_le(cur, tcur->ar_startblock,
184 tcur->ar_blockcount, &i);
56 if (error)185 if (error)
57 goto out_del_cursor;186 goto out_del_cursor;
187 if (i == 0) {
188 /* nothing of that length left in the AG, we are done */
189 tcur->ar_blockcount = 0;
190 goto out_del_cursor;
191 }
58 192
59 /*193 /*
60 * Loop until we are done with all extents that are large194 * Loop until we are done with all extents that are large
61 * enough to be worth discarding.195 * enough to be worth discarding or we hit batch limits.
62 */196 */
63 while (i) {197 while (i) {
64 xfs_agblock_t fbno;198 xfs_agblock_t fbno;
@@ -73,7 +207,16 @@ xfs_trim_extents( · 8 unmodified lines
73 error = -EFSCORRUPTED;207 error = -EFSCORRUPTED;
74 break;208 break;
75 }209 }
76 ASSERT(flen <= be32_to_cpu(agf->agf_longest));210
211 if (--batch <= 0) {
212 /*
213 * Update the cursor to point at this extent so we
214 * restart the next batch from this extent.
215 */
216 tcur->ar_startblock = fbno;
217 tcur->ar_blockcount = flen;
218 break;
219 }
77 220
78 /*221 /*
79 * use daddr format for all range/len calculations as that is222 * use daddr format for all range/len calculations as that is
@@ -88,6 +231,7 @@ xfs_trim_extents( · 8 unmodified lines
88 */231 */
89 if (dlen < minlen) {232 if (dlen < minlen) {
90 trace_xfs_discard_toosmall(mp, pag->pag_agno, fbno, flen);233 trace_xfs_discard_toosmall(mp, pag->pag_agno, fbno, flen);
234 tcur->ar_blockcount = 0;
91 break;235 break;
92 }236 }
93 237
@@ -110,29 +254,103 @@ xfs_trim_extents( · 16 unmodified lines
110 goto next_extent;254 goto next_extent;
111 }255 }
112 256
113 trace_xfs_discard_extent(mp, pag->pag_agno, fbno, flen);257 xfs_extent_busy_insert_discard(pag, fbno, flen,
114 error = blkdev_issue_discard(bdev, dbno, dlen, GFP_NOFS);258 &extents->extent_list);
115 if (error)
116 break;
117 *blocks_trimmed += flen;259 *blocks_trimmed += flen;
118
119next_extent:260next_extent:
120 error = xfs_btree_decrement(cur, 0, &i);261 error = xfs_btree_decrement(cur, 0, &i);
121 if (error)262 if (error)
122 break;263 break;
123 264
124 if (fatal_signal_pending(current)) {265 /*
125 error = -ERESTARTSYS;266 * If there's no more records in the tree, we are done. Set the
126 break;267 * cursor block count to 0 to indicate to the caller that there
127 }268 * is no more extents to search.
269 */
270 if (i == 0)
271 tcur->ar_blockcount = 0;
128 }272 }
129 273
274 /*
275 * If there was an error, release all the gathered busy extents because
276 * we aren't going to issue a discard on them any more.
277 */
278 if (error)
279 xfs_extent_busy_clear(mp, &extents->extent_list, false);
130out_del_cursor:280out_del_cursor:
131 xfs_btree_del_cursor(cur, error);281 xfs_btree_del_cursor(cur, error);
132 xfs_buf_relse(agbp);282 xfs_buf_relse(agbp);
133 return error;283 return error;
134}284}
135 285
286static bool
287xfs_trim_should_stop(void)
288{
289 return fatal_signal_pending(current) || freezing(current);
290}
291
292/*
293 * Iterate the free list gathering extents and discarding them. We need a cursor
294 * for the repeated iteration of gather/discard loop, so use the longest extent
295 * we found in the last batch as the key to start the next.
296 */
297static int
298xfs_trim_extents(
299 struct xfs_perag *pag,
300 xfs_daddr_t start,
301 xfs_daddr_t end,
302 xfs_daddr_t minlen,
303 uint64_t *blocks_trimmed)
304{
305 struct xfs_alloc_rec_incore tcur = {
306 .ar_blockcount = pag->pagf_longest,
307 .ar_startblock = NULLAGBLOCK,
308 };
309 int error = 0;
310
311 do {
312 struct xfs_busy_extents *extents;
313
314 extents = kzalloc(sizeof(*extents), GFP_KERNEL);
315 if (!extents) {
316 error = -ENOMEM;
317 break;
318 }
319
320 extents->mount = pag->pag_mount;
321 extents->owner = extents;
322 INIT_LIST_HEAD(&extents->extent_list);
323
324 error = xfs_trim_gather_extents(pag, start, end, minlen,
325 &tcur, extents, blocks_trimmed);
326 if (error) {
327 kfree(extents);
328 break;
329 }
330
331 /*
332 * We hand the extent list to the discard function here so the
333 * discarded extents can be removed from the busy extent list.
334 * This allows the discards to run asynchronously with gathering
335 * the next round of extents to discard.
336 *
337 * However, we must ensure that we do not reference the extent
338 * list after this function call, as it may have been freed by
339 * the time control returns to us.
340 */
341 error = xfs_discard_extents(pag->pag_mount, extents);
342 if (error)
343 break;
344
345 if (xfs_trim_should_stop())
346 break;
347
348 } while (tcur.ar_blockcount != 0);
349
350 return error;
351
352}
353
136/*354/*
137 * trim a range of the filesystem.355 * trim a range of the filesystem.
138 *356 *
@@ -195,12 +413,12 @@ xfs_ioc_trim( · 56 unmodified lines
195 for_each_perag_range(mp, agno, xfs_daddr_to_agno(mp, end), pag) {413 for_each_perag_range(mp, agno, xfs_daddr_to_agno(mp, end), pag) {
196 error = xfs_trim_extents(pag, start, end, minlen,414 error = xfs_trim_extents(pag, start, end, minlen,
197 &blocks_trimmed);415 &blocks_trimmed);
198 if (error) {416 if (error)
199 last_error = error;417 last_error = error;
200 if (error == -ERESTARTSYS) {418
201 xfs_perag_rele(pag);419 if (xfs_trim_should_stop()) {
202 break;420 xfs_perag_rele(pag);
203 }421 break;
204 }422 }
205 }423 }
206 424
fs/xfs/xfs_discard.h+4−2
@@ -3,8 +3,10 @@ · 2 unmodified lines
3#define XFS_DISCARD_H 13#define XFS_DISCARD_H 1
4 4
5struct fstrim_range;5struct fstrim_range;
6struct list_head;6struct xfs_mount;
7struct xfs_busy_extents;
7 8
8extern int xfs_ioc_trim(struct xfs_mount *, struct fstrim_range __user *);9int xfs_discard_extents(struct xfs_mount *mp, struct xfs_busy_extents *busy);
10int xfs_ioc_trim(struct xfs_mount *mp, struct fstrim_range __user *fstrim);
9 11
10#endif /* XFS_DISCARD_H */12#endif /* XFS_DISCARD_H */
fs/xfs/xfs_extent_busy.c+28−6
@@ -19,13 +19,13 @@ · 18 unmodified lines
19#include "xfs_log.h"19#include "xfs_log.h"
20#include "xfs_ag.h"20#include "xfs_ag.h"
21 21
22void22static void
23xfs_extent_busy_insert(23xfs_extent_busy_insert_list(
24 struct xfs_trans *tp,
25 struct xfs_perag *pag,24 struct xfs_perag *pag,
26 xfs_agblock_t bno,25 xfs_agblock_t bno,
27 xfs_extlen_t len,26 xfs_extlen_t len,
28 unsigned int flags)27 unsigned int flags,
28 struct list_head *busy_list)
29{29{
30 struct xfs_extent_busy *new;30 struct xfs_extent_busy *new;
31 struct xfs_extent_busy *busyp;31 struct xfs_extent_busy *busyp;
@@ -40,7 +40,7 @@ xfs_extent_busy_insert( · 8 unmodified lines
40 new->flags = flags;40 new->flags = flags;
41 41
42 /* trace before insert to be able to see failed inserts */42 /* trace before insert to be able to see failed inserts */
43 trace_xfs_extent_busy(tp->t_mountp, pag->pag_agno, bno, len);43 trace_xfs_extent_busy(pag->pag_mount, pag->pag_agno, bno, len);
44 44
45 spin_lock(&pag->pagb_lock);45 spin_lock(&pag->pagb_lock);
46 rbp = &pag->pagb_tree.rb_node;46 rbp = &pag->pagb_tree.rb_node;
@@ -62,10 +62,32 @@ xfs_extent_busy_insert( · 15 unmodified lines
62 rb_link_node(&new->rb_node, parent, rbp);62 rb_link_node(&new->rb_node, parent, rbp);
63 rb_insert_color(&new->rb_node, &pag->pagb_tree);63 rb_insert_color(&new->rb_node, &pag->pagb_tree);
64 64
65 list_add(&new->list, &tp->t_busy);65 list_add(&new->list, busy_list);
66 spin_unlock(&pag->pagb_lock);66 spin_unlock(&pag->pagb_lock);
67}67}
68 68
69void
70xfs_extent_busy_insert(
71 struct xfs_trans *tp,
72 struct xfs_perag *pag,
73 xfs_agblock_t bno,
74 xfs_extlen_t len,
75 unsigned int flags)
76{
77 xfs_extent_busy_insert_list(pag, bno, len, flags, &tp->t_busy);
78}
79
80void
81xfs_extent_busy_insert_discard(
82 struct xfs_perag *pag,
83 xfs_agblock_t bno,
84 xfs_extlen_t len,
85 struct list_head *busy_list)
86{
87 xfs_extent_busy_insert_list(pag, bno, len, XFS_EXTENT_BUSY_DISCARDED,
88 busy_list);
89}
90
69/*91/*
70 * Search for a busy extent within the range of the extent we are about to92 * Search for a busy extent within the range of the extent we are about to
71 * allocate. You need to be holding the busy extent tree lock when calling93 * allocate. You need to be holding the busy extent tree lock when calling
fs/xfs/xfs_extent_busy.h+21−3
@@ -16,9 +16,6 @@ struct xfs_alloc_arg; · 15 unmodified lines
16/*16/*
17 * Busy block/extent entry. Indexed by a rbtree in perag to mark blocks that17 * Busy block/extent entry. Indexed by a rbtree in perag to mark blocks that
18 * have been freed but whose transactions aren't committed to disk yet.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 */
23struct xfs_extent_busy {20struct xfs_extent_busy {
24 struct rb_node rb_node; /* ag by-bno indexed search tree */21 struct rb_node rb_node; /* ag by-bno indexed search tree */
@@ -31,10 +28,31 @@ struct xfs_extent_busy { · 6 unmodified lines
31#define XFS_EXTENT_BUSY_SKIP_DISCARD 0x02 /* do not discard */28#define XFS_EXTENT_BUSY_SKIP_DISCARD 0x02 /* do not discard */
32};29};
33 30
31/*
32 * List used to track groups of related busy extents all the way through
33 * to discard completion.
34 */
35struct 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
34void48void
35xfs_extent_busy_insert(struct xfs_trans *tp, struct xfs_perag *pag,49xfs_extent_busy_insert(struct xfs_trans *tp, struct xfs_perag *pag,
36 xfs_agblock_t bno, xfs_extlen_t len, unsigned int flags);50 xfs_agblock_t bno, xfs_extlen_t len, unsigned int flags);
37 51
52void
53xfs_extent_busy_insert_discard(struct xfs_perag *pag, xfs_agblock_t bno,
54 xfs_extlen_t len, struct list_head *busy_list);
55
38void56void
39xfs_extent_busy_clear(struct xfs_mount *mp, struct list_head *list,57xfs_extent_busy_clear(struct xfs_mount *mp, struct list_head *list,
40 bool do_discard);58 bool do_discard);
fs/xfs/xfs_log_cil.c+13−80
@@ -16,8 +16,7 @@ · 15 unmodified lines
16#include "xfs_log.h"16#include "xfs_log.h"
17#include "xfs_log_priv.h"17#include "xfs_log_priv.h"
18#include "xfs_trace.h"18#include "xfs_trace.h"
19 19#include "xfs_discard.h"
20struct workqueue_struct *xfs_discard_wq;
21 20
22/*21/*
23 * Allocate a new ticket. Failing to get a new ticket makes it really hard to22 * Allocate a new ticket. Failing to get a new ticket makes it really hard to
@@ -103,7 +102,7 @@ xlog_cil_ctx_alloc(void) · 79 unmodified lines
103 102
104 ctx = kmem_zalloc(sizeof(*ctx), KM_NOFS);103 ctx = kmem_zalloc(sizeof(*ctx), KM_NOFS);
105 INIT_LIST_HEAD(&ctx->committing);104 INIT_LIST_HEAD(&ctx->committing);
106 INIT_LIST_HEAD(&ctx->busy_extents);105 INIT_LIST_HEAD(&ctx->busy_extents.extent_list);
107 INIT_LIST_HEAD(&ctx->log_items);106 INIT_LIST_HEAD(&ctx->log_items);
108 INIT_LIST_HEAD(&ctx->lv_chain);107 INIT_LIST_HEAD(&ctx->lv_chain);
109 INIT_WORK(&ctx->push_work, xlog_cil_push_work);108 INIT_WORK(&ctx->push_work, xlog_cil_push_work);
@@ -132,7 +131,7 @@ xlog_cil_push_pcp_aggregate( · 22 unmodified lines
132 131
133 if (!list_empty(&cilpcp->busy_extents)) {132 if (!list_empty(&cilpcp->busy_extents)) {
134 list_splice_init(&cilpcp->busy_extents,133 list_splice_init(&cilpcp->busy_extents,
135 &ctx->busy_extents);134 &ctx->busy_extents.extent_list);
136 }135 }
137 if (!list_empty(&cilpcp->log_items))136 if (!list_empty(&cilpcp->log_items))
138 list_splice_init(&cilpcp->log_items, &ctx->log_items);137 list_splice_init(&cilpcp->log_items, &ctx->log_items);
@@ -708,76 +707,6 @@ xlog_cil_free_logvec( · 569 unmodified lines
708 }707 }
709}708}
710 709
711static void
712xlog_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 */
728static void
729xlog_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
739static void
740xlog_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
781/*710/*
782 * Mark all items committed and clear busy extents. We free the log vector711 * Mark all items committed and clear busy extents. We free the log vector
783 * chains in a separate pass so that we unpin the log items as quickly as712 * chains in a separate pass so that we unpin the log items as quickly as
@@ -807,8 +736,8 @@ xlog_cil_committed( · 23 unmodified lines
807 xfs_trans_committed_bulk(ctx->cil->xc_log->l_ailp, &ctx->lv_chain,736 xfs_trans_committed_bulk(ctx->cil->xc_log->l_ailp, &ctx->lv_chain,
808 ctx->start_lsn, abort);737 ctx->start_lsn, abort);
809 738
810 xfs_extent_busy_sort(&ctx->busy_extents);739 xfs_extent_busy_sort(&ctx->busy_extents.extent_list);
811 xfs_extent_busy_clear(mp, &ctx->busy_extents,740 xfs_extent_busy_clear(mp, &ctx->busy_extents.extent_list,
812 xfs_has_discard(mp) && !abort);741 xfs_has_discard(mp) && !abort);
813 742
814 spin_lock(&ctx->cil->xc_push_lock);743 spin_lock(&ctx->cil->xc_push_lock);
@@ -817,10 +746,14 @@ xlog_cil_committed( · 2 unmodified lines
817 746
818 xlog_cil_free_logvec(&ctx->lv_chain);747 xlog_cil_free_logvec(&ctx->lv_chain);
819 748
820 if (!list_empty(&ctx->busy_extents))749 if (!list_empty(&ctx->busy_extents.extent_list)) {
821 xlog_discard_busy_extents(mp, ctx);750 ctx->busy_extents.mount = mp;
822 else751 ctx->busy_extents.owner = ctx;
823 kmem_free(ctx);752 xfs_discard_extents(mp, &ctx->busy_extents);
753 return;
754 }
755
756 kmem_free(ctx);
824}757}
825 758
826void759void
fs/xfs/xfs_log_priv.h+3−2
@@ -6,6 +6,8 @@ · 5 unmodified lines
6#ifndef __XFS_LOG_PRIV_H__6#ifndef __XFS_LOG_PRIV_H__
7#define __XFS_LOG_PRIV_H__7#define __XFS_LOG_PRIV_H__
8 8
9#include "xfs_extent_busy.h" /* for struct xfs_busy_extents */
10
9struct xfs_buf;11struct xfs_buf;
10struct xlog;12struct xlog;
11struct xlog_ticket;13struct xlog_ticket;
@@ -223,12 +225,11 @@ struct xfs_cil_ctx { · 211 unmodified lines
223 struct xlog_in_core *commit_iclog;225 struct xlog_in_core *commit_iclog;
224 struct xlog_ticket *ticket; /* chkpt ticket */226 struct xlog_ticket *ticket; /* chkpt ticket */
225 atomic_t space_used; /* aggregate size of regions */227 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;
227 struct list_head log_items; /* log items in chkpt */229 struct list_head log_items; /* log items in chkpt */
228 struct list_head lv_chain; /* logvecs being pushed */230 struct list_head lv_chain; /* logvecs being pushed */
229 struct list_head iclog_entry;231 struct list_head iclog_entry;
230 struct list_head committing; /* ctx committing list */232 struct list_head committing; /* ctx committing list */
231 struct work_struct discard_endio_work;
232 struct work_struct push_work;233 struct work_struct push_work;
233 atomic_t order_id;234 atomic_t order_id;
234 235

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t