xref: /linux-6.15/fs/btrfs/locking.c (revision 4048daed)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2008 Oracle.  All rights reserved.
4  */
5 
6 #include <linux/sched.h>
7 #include <linux/pagemap.h>
8 #include <linux/spinlock.h>
9 #include <linux/page-flags.h>
10 #include <asm/bug.h>
11 #include "misc.h"
12 #include "ctree.h"
13 #include "extent_io.h"
14 #include "locking.h"
15 
16 /*
17  * Extent buffer locking
18  * =====================
19  *
20  * We use a rw_semaphore for tree locking, and the semantics are exactly the
21  * same:
22  *
23  * - reader/writer exclusion
24  * - writer/writer exclusion
25  * - reader/reader sharing
26  * - try-lock semantics for readers and writers
27  *
28  * The rwsem implementation does opportunistic spinning which reduces number of
29  * times the locking task needs to sleep.
30  */
31 
32 /*
33  * __btrfs_tree_read_lock - lock extent buffer for read
34  * @eb:		the eb to be locked
35  * @nest:	the nesting level to be used for lockdep
36  * @recurse:	unused
37  *
38  * This takes the read lock on the extent buffer, using the specified nesting
39  * level for lockdep purposes.
40  */
41 void __btrfs_tree_read_lock(struct extent_buffer *eb, enum btrfs_lock_nesting nest,
42 			    bool recurse)
43 {
44 	u64 start_ns = 0;
45 
46 	if (trace_btrfs_tree_read_lock_enabled())
47 		start_ns = ktime_get_ns();
48 
49 	down_read_nested(&eb->lock, nest);
50 	eb->lock_owner = current->pid;
51 	trace_btrfs_tree_read_lock(eb, start_ns);
52 }
53 
54 void btrfs_tree_read_lock(struct extent_buffer *eb)
55 {
56 	__btrfs_tree_read_lock(eb, BTRFS_NESTING_NORMAL, false);
57 }
58 
59 /*
60  * Try-lock for read.
61  *
62  * Retrun 1 if the rwlock has been taken, 0 otherwise
63  */
64 int btrfs_try_tree_read_lock(struct extent_buffer *eb)
65 {
66 	if (down_read_trylock(&eb->lock)) {
67 		eb->lock_owner = current->pid;
68 		trace_btrfs_try_tree_read_lock(eb);
69 		return 1;
70 	}
71 	return 0;
72 }
73 
74 /*
75  * Try-lock for write.
76  *
77  * Retrun 1 if the rwlock has been taken, 0 otherwise
78  */
79 int btrfs_try_tree_write_lock(struct extent_buffer *eb)
80 {
81 	if (down_write_trylock(&eb->lock)) {
82 		eb->lock_owner = current->pid;
83 		trace_btrfs_try_tree_write_lock(eb);
84 		return 1;
85 	}
86 	return 0;
87 }
88 
89 /*
90  * Release read lock.
91  */
92 void btrfs_tree_read_unlock(struct extent_buffer *eb)
93 {
94 	trace_btrfs_tree_read_unlock(eb);
95 	eb->lock_owner = 0;
96 	up_read(&eb->lock);
97 }
98 
99 /*
100  * __btrfs_tree_lock - lock eb for write
101  * @eb:		the eb to lock
102  * @nest:	the nesting to use for the lock
103  *
104  * Returns with the eb->lock write locked.
105  */
106 void __btrfs_tree_lock(struct extent_buffer *eb, enum btrfs_lock_nesting nest)
107 	__acquires(&eb->lock)
108 {
109 	u64 start_ns = 0;
110 
111 	if (trace_btrfs_tree_lock_enabled())
112 		start_ns = ktime_get_ns();
113 
114 	down_write_nested(&eb->lock, nest);
115 	eb->lock_owner = current->pid;
116 	trace_btrfs_tree_lock(eb, start_ns);
117 }
118 
119 void btrfs_tree_lock(struct extent_buffer *eb)
120 {
121 	__btrfs_tree_lock(eb, BTRFS_NESTING_NORMAL);
122 }
123 
124 /*
125  * Release the write lock.
126  */
127 void btrfs_tree_unlock(struct extent_buffer *eb)
128 {
129 	trace_btrfs_tree_unlock(eb);
130 	eb->lock_owner = 0;
131 	up_write(&eb->lock);
132 }
133 
134 /*
135  * This releases any locks held in the path starting at level and going all the
136  * way up to the root.
137  *
138  * btrfs_search_slot will keep the lock held on higher nodes in a few corner
139  * cases, such as COW of the block at slot zero in the node.  This ignores
140  * those rules, and it should only be called when there are no more updates to
141  * be done higher up in the tree.
142  */
143 void btrfs_unlock_up_safe(struct btrfs_path *path, int level)
144 {
145 	int i;
146 
147 	if (path->keep_locks)
148 		return;
149 
150 	for (i = level; i < BTRFS_MAX_LEVEL; i++) {
151 		if (!path->nodes[i])
152 			continue;
153 		if (!path->locks[i])
154 			continue;
155 		btrfs_tree_unlock_rw(path->nodes[i], path->locks[i]);
156 		path->locks[i] = 0;
157 	}
158 }
159 
160 /*
161  * Loop around taking references on and locking the root node of the tree until
162  * we end up with a lock on the root node.
163  *
164  * Return: root extent buffer with write lock held
165  */
166 struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root)
167 {
168 	struct extent_buffer *eb;
169 
170 	while (1) {
171 		eb = btrfs_root_node(root);
172 		btrfs_tree_lock(eb);
173 		if (eb == root->node)
174 			break;
175 		btrfs_tree_unlock(eb);
176 		free_extent_buffer(eb);
177 	}
178 	return eb;
179 }
180 
181 /*
182  * Loop around taking references on and locking the root node of the tree until
183  * we end up with a lock on the root node.
184  *
185  * Return: root extent buffer with read lock held
186  */
187 struct extent_buffer *__btrfs_read_lock_root_node(struct btrfs_root *root,
188 						  bool recurse)
189 {
190 	struct extent_buffer *eb;
191 
192 	while (1) {
193 		eb = btrfs_root_node(root);
194 		__btrfs_tree_read_lock(eb, BTRFS_NESTING_NORMAL, recurse);
195 		if (eb == root->node)
196 			break;
197 		btrfs_tree_read_unlock(eb);
198 		free_extent_buffer(eb);
199 	}
200 	return eb;
201 }
202 
203 /*
204  * DREW locks
205  * ==========
206  *
207  * DREW stands for double-reader-writer-exclusion lock. It's used in situation
208  * where you want to provide A-B exclusion but not AA or BB.
209  *
210  * Currently implementation gives more priority to reader. If a reader and a
211  * writer both race to acquire their respective sides of the lock the writer
212  * would yield its lock as soon as it detects a concurrent reader. Additionally
213  * if there are pending readers no new writers would be allowed to come in and
214  * acquire the lock.
215  */
216 
217 int btrfs_drew_lock_init(struct btrfs_drew_lock *lock)
218 {
219 	int ret;
220 
221 	ret = percpu_counter_init(&lock->writers, 0, GFP_KERNEL);
222 	if (ret)
223 		return ret;
224 
225 	atomic_set(&lock->readers, 0);
226 	init_waitqueue_head(&lock->pending_readers);
227 	init_waitqueue_head(&lock->pending_writers);
228 
229 	return 0;
230 }
231 
232 void btrfs_drew_lock_destroy(struct btrfs_drew_lock *lock)
233 {
234 	percpu_counter_destroy(&lock->writers);
235 }
236 
237 /* Return true if acquisition is successful, false otherwise */
238 bool btrfs_drew_try_write_lock(struct btrfs_drew_lock *lock)
239 {
240 	if (atomic_read(&lock->readers))
241 		return false;
242 
243 	percpu_counter_inc(&lock->writers);
244 
245 	/* Ensure writers count is updated before we check for pending readers */
246 	smp_mb();
247 	if (atomic_read(&lock->readers)) {
248 		btrfs_drew_write_unlock(lock);
249 		return false;
250 	}
251 
252 	return true;
253 }
254 
255 void btrfs_drew_write_lock(struct btrfs_drew_lock *lock)
256 {
257 	while (true) {
258 		if (btrfs_drew_try_write_lock(lock))
259 			return;
260 		wait_event(lock->pending_writers, !atomic_read(&lock->readers));
261 	}
262 }
263 
264 void btrfs_drew_write_unlock(struct btrfs_drew_lock *lock)
265 {
266 	percpu_counter_dec(&lock->writers);
267 	cond_wake_up(&lock->pending_readers);
268 }
269 
270 void btrfs_drew_read_lock(struct btrfs_drew_lock *lock)
271 {
272 	atomic_inc(&lock->readers);
273 
274 	/*
275 	 * Ensure the pending reader count is perceieved BEFORE this reader
276 	 * goes to sleep in case of active writers. This guarantees new writers
277 	 * won't be allowed and that the current reader will be woken up when
278 	 * the last active writer finishes its jobs.
279 	 */
280 	smp_mb__after_atomic();
281 
282 	wait_event(lock->pending_readers,
283 		   percpu_counter_sum(&lock->writers) == 0);
284 }
285 
286 void btrfs_drew_read_unlock(struct btrfs_drew_lock *lock)
287 {
288 	/*
289 	 * atomic_dec_and_test implies a full barrier, so woken up writers
290 	 * are guaranteed to see the decrement
291 	 */
292 	if (atomic_dec_and_test(&lock->readers))
293 		wake_up(&lock->pending_writers);
294 }
295