xref: /linux/fs/xfs/xfs_drain.h (revision c8b90d40d5bba8e6fba457b8a7c10d3c0d467e37)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2022-2023 Oracle.  All Rights Reserved.
4  * Author: Darrick J. Wong <djwong@kernel.org>
5  */
6 #ifndef XFS_DRAIN_H_
7 #define XFS_DRAIN_H_
8 
9 struct xfs_group;
10 struct xfs_perag;
11 
12 #ifdef CONFIG_XFS_DRAIN_INTENTS
13 /*
14  * Passive drain mechanism.  This data structure tracks a count of some items
15  * and contains a waitqueue for callers who would like to wake up when the
16  * count hits zero.
17  */
18 struct xfs_defer_drain {
19 	/* Number of items pending in some part of the filesystem. */
20 	atomic_t		dr_count;
21 
22 	/* Queue to wait for dri_count to go to zero */
23 	struct wait_queue_head	dr_waiters;
24 };
25 
26 void xfs_defer_drain_init(struct xfs_defer_drain *dr);
27 void xfs_defer_drain_free(struct xfs_defer_drain *dr);
28 
29 void xfs_drain_wait_disable(void);
30 void xfs_drain_wait_enable(void);
31 
32 /*
33  * Deferred Work Intent Drains
34  * ===========================
35  *
36  * When a writer thread executes a chain of log intent items, the AG header
37  * buffer locks will cycle during a transaction roll to get from one intent
38  * item to the next in a chain.  Although scrub takes all AG header buffer
39  * locks, this isn't sufficient to guard against scrub checking an AG while
40  * that writer thread is in the middle of finishing a chain because there's no
41  * higher level locking primitive guarding allocation groups.
42  *
43  * When there's a collision, cross-referencing between data structures (e.g.
44  * rmapbt and refcountbt) yields false corruption events; if repair is running,
45  * this results in incorrect repairs, which is catastrophic.
46  *
47  * The solution is to the perag structure the count of active intents and make
48  * scrub wait until it has both AG header buffer locks and the intent counter
49  * reaches zero.  It is therefore critical that deferred work threads hold the
50  * AGI or AGF buffers when decrementing the intent counter.
51  *
52  * Given a list of deferred work items, the deferred work manager will complete
53  * a work item and all the sub-items that the parent item creates before moving
54  * on to the next work item in the list.  This is also true for all levels of
55  * sub-items.  Writer threads are permitted to queue multiple work items
56  * targetting the same AG, so a deferred work item (such as a BUI) that creates
57  * sub-items (such as RUIs) must bump the intent counter and maintain it until
58  * the sub-items can themselves bump the intent counter.
59  *
60  * Therefore, the intent count tracks entire lifetimes of deferred work items.
61  * All functions that create work items must increment the intent counter as
62  * soon as the item is added to the transaction and cannot drop the counter
63  * until the item is finished or cancelled.
64  */
65 struct xfs_group *xfs_group_intent_get(struct xfs_mount *mp,
66 		xfs_fsblock_t fsbno, enum xfs_group_type type);
67 void xfs_group_intent_put(struct xfs_group *rtg);
68 
69 int xfs_group_intent_drain(struct xfs_group *xg);
70 bool xfs_group_intent_busy(struct xfs_group *xg);
71 
72 #else
73 struct xfs_defer_drain { /* empty */ };
74 
75 #define xfs_defer_drain_free(dr)		((void)0)
76 #define xfs_defer_drain_init(dr)		((void)0)
77 
78 #define xfs_group_intent_get(_mp, _fsbno, _type) \
79 	xfs_group_get_by_fsb((_mp), (_fsbno), (_type))
80 #define xfs_group_intent_put(xg)		xfs_group_put(xg)
81 
82 #endif /* CONFIG_XFS_DRAIN_INTENTS */
83 
84 #endif /* XFS_DRAIN_H_ */
85