FILE
xfs_drain.c
File preview with syntax highlighting.
linux-6.19.14/fs/xfs/xfs_drain.c
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#include "xfs.h" 7#include "xfs_fs.h" 8#include "xfs_shared.h" 9#include "xfs_format.h" 10#include "xfs_trans_resv.h" 11#include "xfs_mount.h" 12#include "xfs_ag.h" 13#include "xfs_trace.h" 14 15/* 16 * Use a static key here to reduce the overhead of xfs_defer_drain_rele. If 17 * the compiler supports jump labels, the static branch will be replaced by a 18 * nop sled when there are no xfs_defer_drain_wait callers. Online fsck is 19 * currently the only caller, so this is a reasonable tradeoff. 20 * 21 * Note: Patching the kernel code requires taking the cpu hotplug lock. Other 22 * parts of the kernel allocate memory with that lock held, which means that 23 * XFS callers cannot hold any locks that might be used by memory reclaim or 24 * writeback when calling the static_branch_{inc,dec} functions. 25 */ 26static DEFINE_STATIC_KEY_FALSE(xfs_defer_drain_waiter_gate); 27 28void 29xfs_defer_drain_wait_disable(void) 30{ 31 static_branch_dec(&xfs_defer_drain_waiter_gate); 32} 33 34void 35xfs_defer_drain_wait_enable(void) 36{ 37 static_branch_inc(&xfs_defer_drain_waiter_gate); 38} 39 40void 41xfs_defer_drain_init( 42 struct xfs_defer_drain *dr) 43{ 44 atomic_set(&dr->dr_count, 0); 45 init_waitqueue_head(&dr->dr_waiters); 46} 47 48void 49xfs_defer_drain_free(struct xfs_defer_drain *dr) 50{ 51 ASSERT(atomic_read(&dr->dr_count) == 0); 52} 53 54/* Increase the pending intent count. */ 55static inline void xfs_defer_drain_grab(struct xfs_defer_drain *dr) 56{ 57 atomic_inc(&dr->dr_count); 58} 59 60static inline bool has_waiters(struct wait_queue_head *wq_head) 61{ 62 /* 63 * This memory barrier is paired with the one in set_current_state on 64 * the waiting side. 65 */ 66 smp_mb__after_atomic(); 67 return waitqueue_active(wq_head); 68} 69 70/* Decrease the pending intent count, and wake any waiters, if appropriate. */ 71static inline void xfs_defer_drain_rele(struct xfs_defer_drain *dr) 72{ 73 if (atomic_dec_and_test(&dr->dr_count) && 74 static_branch_unlikely(&xfs_defer_drain_waiter_gate) && 75 has_waiters(&dr->dr_waiters)) 76 wake_up(&dr->dr_waiters); 77} 78 79/* Are there intents pending? */ 80static inline bool xfs_defer_drain_busy(struct xfs_defer_drain *dr) 81{ 82 return atomic_read(&dr->dr_count) > 0; 83} 84 85/* 86 * Wait for the pending intent count for a drain to hit zero. 87 * 88 * Callers must not hold any locks that would prevent intents from being 89 * finished. 90 */ 91static inline int xfs_defer_drain_wait(struct xfs_defer_drain *dr) 92{ 93 return wait_event_killable(dr->dr_waiters, !xfs_defer_drain_busy(dr)); 94} 95 96/* 97 * Get a passive reference to the group that contains a fsbno and declare an 98 * intent to update its metadata. 99 * 100 * Other threads that need exclusive access can decide to back off if they see 101 * declared intentions. 102 */ 103struct xfs_group * 104xfs_group_intent_get( 105 struct xfs_mount *mp, 106 xfs_fsblock_t fsbno, 107 enum xfs_group_type type) 108{ 109 struct xfs_group *xg; 110 111 xg = xfs_group_get_by_fsb(mp, fsbno, type); 112 if (!xg) 113 return NULL; 114 trace_xfs_group_intent_hold(xg, __return_address); 115 xfs_defer_drain_grab(&xg->xg_intents_drain); 116 return xg; 117} 118 119/* 120 * Release our intent to update this groups metadata, and then release our 121 * passive ref to it. 122 */ 123void 124xfs_group_intent_put( 125 struct xfs_group *xg) 126{ 127 trace_xfs_group_intent_rele(xg, __return_address); 128 xfs_defer_drain_rele(&xg->xg_intents_drain); 129 xfs_group_put(xg); 130} 131 132/* 133 * Wait for the intent update count for this AG to hit zero. 134 * Callers must not hold any AG header buffers. 135 */ 136int 137xfs_group_intent_drain( 138 struct xfs_group *xg) 139{ 140 trace_xfs_group_wait_intents(xg, __return_address); 141 return xfs_defer_drain_wait(&xg->xg_intents_drain); 142} 143 144/* 145 * Has anyone declared an intent to update this group? 146 */ 147bool 148xfs_group_intent_busy( 149 struct xfs_group *xg) 150{ 151 return xfs_defer_drain_busy(&xg->xg_intents_drain); 152}
~/
Read-only file preview.