xref: /linux-6.15/fs/btrfs/locking.c (revision 1bb96598)
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 {
189 	struct extent_buffer *eb;
190 
191 	while (1) {
192 		eb = btrfs_root_node(root);
193 		btrfs_tree_read_lock(eb);
194 		if (eb == root->node)
195 			break;
196 		btrfs_tree_read_unlock(eb);
197 		free_extent_buffer(eb);
198 	}
199 	return eb;
200 }
201 
202 /*
203  * DREW locks
204  * ==========
205  *
206  * DREW stands for double-reader-writer-exclusion lock. It's used in situation
207  * where you want to provide A-B exclusion but not AA or BB.
208  *
209  * Currently implementation gives more priority to reader. If a reader and a
210  * writer both race to acquire their respective sides of the lock the writer
211  * would yield its lock as soon as it detects a concurrent reader. Additionally
212  * if there are pending readers no new writers would be allowed to come in and
213  * acquire the lock.
214  */
215 
216 int btrfs_drew_lock_init(struct btrfs_drew_lock *lock)
217 {
218 	int ret;
219 
220 	ret = percpu_counter_init(&lock->writers, 0, GFP_KERNEL);
221 	if (ret)
222 		return ret;
223 
224 	atomic_set(&lock->readers, 0);
225 	init_waitqueue_head(&lock->pending_readers);
226 	init_waitqueue_head(&lock->pending_writers);
227 
228 	return 0;
229 }
230 
231 void btrfs_drew_lock_destroy(struct btrfs_drew_lock *lock)
232 {
233 	percpu_counter_destroy(&lock->writers);
234 }
235 
236 /* Return true if acquisition is successful, false otherwise */
237 bool btrfs_drew_try_write_lock(struct btrfs_drew_lock *lock)
238 {
239 	if (atomic_read(&lock->readers))
240 		return false;
241 
242 	percpu_counter_inc(&lock->writers);
243 
244 	/* Ensure writers count is updated before we check for pending readers */
245 	smp_mb();
246 	if (atomic_read(&lock->readers)) {
247 		btrfs_drew_write_unlock(lock);
248 		return false;
249 	}
250 
251 	return true;
252 }
253 
254 void btrfs_drew_write_lock(struct btrfs_drew_lock *lock)
255 {
256 	while (true) {
257 		if (btrfs_drew_try_write_lock(lock))
258 			return;
259 		wait_event(lock->pending_writers, !atomic_read(&lock->readers));
260 	}
261 }
262 
263 void btrfs_drew_write_unlock(struct btrfs_drew_lock *lock)
264 {
265 	percpu_counter_dec(&lock->writers);
266 	cond_wake_up(&lock->pending_readers);
267 }
268 
269 void btrfs_drew_read_lock(struct btrfs_drew_lock *lock)
270 {
271 	atomic_inc(&lock->readers);
272 
273 	/*
274 	 * Ensure the pending reader count is perceieved BEFORE this reader
275 	 * goes to sleep in case of active writers. This guarantees new writers
276 	 * won't be allowed and that the current reader will be woken up when
277 	 * the last active writer finishes its jobs.
278 	 */
279 	smp_mb__after_atomic();
280 
281 	wait_event(lock->pending_readers,
282 		   percpu_counter_sum(&lock->writers) == 0);
283 }
284 
285 void btrfs_drew_read_unlock(struct btrfs_drew_lock *lock)
286 {
287 	/*
288 	 * atomic_dec_and_test implies a full barrier, so woken up writers
289 	 * are guaranteed to see the decrement
290 	 */
291 	if (atomic_dec_and_test(&lock->readers))
292 		wake_up(&lock->pending_writers);
293 }
294