1c1d7c514SDavid Sterba // SPDX-License-Identifier: GPL-2.0
2925baeddSChris Mason /*
3925baeddSChris Mason * Copyright (C) 2008 Oracle. All rights reserved.
4925baeddSChris Mason */
5c1d7c514SDavid Sterba
6925baeddSChris Mason #include <linux/sched.h>
7925baeddSChris Mason #include <linux/pagemap.h>
8925baeddSChris Mason #include <linux/spinlock.h>
9925baeddSChris Mason #include <linux/page-flags.h>
104881ee5aSChris Mason #include <asm/bug.h>
11602cbe91SDavid Sterba #include "misc.h"
12925baeddSChris Mason #include "ctree.h"
13925baeddSChris Mason #include "extent_io.h"
14925baeddSChris Mason #include "locking.h"
1507e81dc9SJosef Bacik #include "accessors.h"
16925baeddSChris Mason
17d4e253bbSDavid Sterba /*
180a27a047SJosef Bacik * Lockdep class keys for extent_buffer->lock's in this root. For a given
190a27a047SJosef Bacik * eb, the lockdep key is determined by the btrfs_root it belongs to and
200a27a047SJosef Bacik * the level the eb occupies in the tree.
210a27a047SJosef Bacik *
220a27a047SJosef Bacik * Different roots are used for different purposes and may nest inside each
230a27a047SJosef Bacik * other and they require separate keysets. As lockdep keys should be
240a27a047SJosef Bacik * static, assign keysets according to the purpose of the root as indicated
250a27a047SJosef Bacik * by btrfs_root->root_key.objectid. This ensures that all special purpose
260a27a047SJosef Bacik * roots have separate keysets.
270a27a047SJosef Bacik *
280a27a047SJosef Bacik * Lock-nesting across peer nodes is always done with the immediate parent
290a27a047SJosef Bacik * node locked thus preventing deadlock. As lockdep doesn't know this, use
300a27a047SJosef Bacik * subclass to avoid triggering lockdep warning in such cases.
310a27a047SJosef Bacik *
320a27a047SJosef Bacik * The key is set by the readpage_end_io_hook after the buffer has passed
330a27a047SJosef Bacik * csum validation but before the pages are unlocked. It is also set by
340a27a047SJosef Bacik * btrfs_init_new_buffer on freshly allocated blocks.
350a27a047SJosef Bacik *
360a27a047SJosef Bacik * We also add a check to make sure the highest level of the tree is the
370a27a047SJosef Bacik * same as our lockdep setup here. If BTRFS_MAX_LEVEL changes, this code
380a27a047SJosef Bacik * needs update as well.
390a27a047SJosef Bacik */
400a27a047SJosef Bacik #ifdef CONFIG_DEBUG_LOCK_ALLOC
410a27a047SJosef Bacik #if BTRFS_MAX_LEVEL != 8
420a27a047SJosef Bacik #error
430a27a047SJosef Bacik #endif
440a27a047SJosef Bacik
450a27a047SJosef Bacik #define DEFINE_LEVEL(stem, level) \
460a27a047SJosef Bacik .names[level] = "btrfs-" stem "-0" #level,
470a27a047SJosef Bacik
480a27a047SJosef Bacik #define DEFINE_NAME(stem) \
490a27a047SJosef Bacik DEFINE_LEVEL(stem, 0) \
500a27a047SJosef Bacik DEFINE_LEVEL(stem, 1) \
510a27a047SJosef Bacik DEFINE_LEVEL(stem, 2) \
520a27a047SJosef Bacik DEFINE_LEVEL(stem, 3) \
530a27a047SJosef Bacik DEFINE_LEVEL(stem, 4) \
540a27a047SJosef Bacik DEFINE_LEVEL(stem, 5) \
550a27a047SJosef Bacik DEFINE_LEVEL(stem, 6) \
560a27a047SJosef Bacik DEFINE_LEVEL(stem, 7)
570a27a047SJosef Bacik
580a27a047SJosef Bacik static struct btrfs_lockdep_keyset {
590a27a047SJosef Bacik u64 id; /* root objectid */
600a27a047SJosef Bacik /* Longest entry: btrfs-block-group-00 */
610a27a047SJosef Bacik char names[BTRFS_MAX_LEVEL][24];
620a27a047SJosef Bacik struct lock_class_key keys[BTRFS_MAX_LEVEL];
630a27a047SJosef Bacik } btrfs_lockdep_keysets[] = {
640a27a047SJosef Bacik { .id = BTRFS_ROOT_TREE_OBJECTID, DEFINE_NAME("root") },
650a27a047SJosef Bacik { .id = BTRFS_EXTENT_TREE_OBJECTID, DEFINE_NAME("extent") },
660a27a047SJosef Bacik { .id = BTRFS_CHUNK_TREE_OBJECTID, DEFINE_NAME("chunk") },
670a27a047SJosef Bacik { .id = BTRFS_DEV_TREE_OBJECTID, DEFINE_NAME("dev") },
680a27a047SJosef Bacik { .id = BTRFS_CSUM_TREE_OBJECTID, DEFINE_NAME("csum") },
690a27a047SJosef Bacik { .id = BTRFS_QUOTA_TREE_OBJECTID, DEFINE_NAME("quota") },
700a27a047SJosef Bacik { .id = BTRFS_TREE_LOG_OBJECTID, DEFINE_NAME("log") },
710a27a047SJosef Bacik { .id = BTRFS_TREE_RELOC_OBJECTID, DEFINE_NAME("treloc") },
720a27a047SJosef Bacik { .id = BTRFS_DATA_RELOC_TREE_OBJECTID, DEFINE_NAME("dreloc") },
730a27a047SJosef Bacik { .id = BTRFS_UUID_TREE_OBJECTID, DEFINE_NAME("uuid") },
740a27a047SJosef Bacik { .id = BTRFS_FREE_SPACE_TREE_OBJECTID, DEFINE_NAME("free-space") },
750a27a047SJosef Bacik { .id = BTRFS_BLOCK_GROUP_TREE_OBJECTID, DEFINE_NAME("block-group") },
760a27a047SJosef Bacik { .id = 0, DEFINE_NAME("tree") },
770a27a047SJosef Bacik };
780a27a047SJosef Bacik
790a27a047SJosef Bacik #undef DEFINE_LEVEL
800a27a047SJosef Bacik #undef DEFINE_NAME
810a27a047SJosef Bacik
btrfs_set_buffer_lockdep_class(u64 objectid,struct extent_buffer * eb,int level)820a27a047SJosef Bacik void btrfs_set_buffer_lockdep_class(u64 objectid, struct extent_buffer *eb, int level)
830a27a047SJosef Bacik {
840a27a047SJosef Bacik struct btrfs_lockdep_keyset *ks;
850a27a047SJosef Bacik
860a27a047SJosef Bacik BUG_ON(level >= ARRAY_SIZE(ks->keys));
870a27a047SJosef Bacik
880a27a047SJosef Bacik /* Find the matching keyset, id 0 is the default entry */
890a27a047SJosef Bacik for (ks = btrfs_lockdep_keysets; ks->id; ks++)
900a27a047SJosef Bacik if (ks->id == objectid)
910a27a047SJosef Bacik break;
920a27a047SJosef Bacik
930a27a047SJosef Bacik lockdep_set_class_and_name(&eb->lock, &ks->keys[level], ks->names[level]);
940a27a047SJosef Bacik }
95b40130b2SJosef Bacik
btrfs_maybe_reset_lockdep_class(struct btrfs_root * root,struct extent_buffer * eb)96b40130b2SJosef Bacik void btrfs_maybe_reset_lockdep_class(struct btrfs_root *root, struct extent_buffer *eb)
97b40130b2SJosef Bacik {
98b40130b2SJosef Bacik if (test_bit(BTRFS_ROOT_RESET_LOCKDEP_CLASS, &root->state))
99b40130b2SJosef Bacik btrfs_set_buffer_lockdep_class(root->root_key.objectid,
100b40130b2SJosef Bacik eb, btrfs_header_level(eb));
101b40130b2SJosef Bacik }
1020a27a047SJosef Bacik
1030a27a047SJosef Bacik #endif
1040a27a047SJosef Bacik
105d4e253bbSDavid Sterba /*
106d4e253bbSDavid Sterba * Extent buffer locking
107d4e253bbSDavid Sterba * =====================
108196d59abSJosef Bacik *
109196d59abSJosef Bacik * We use a rw_semaphore for tree locking, and the semantics are exactly the
110d4e253bbSDavid Sterba * same:
111d4e253bbSDavid Sterba *
112d4e253bbSDavid Sterba * - reader/writer exclusion
113d4e253bbSDavid Sterba * - writer/writer exclusion
114d4e253bbSDavid Sterba * - reader/reader sharing
115d4e253bbSDavid Sterba * - try-lock semantics for readers and writers
1164048daedSJosef Bacik *
1174048daedSJosef Bacik * The rwsem implementation does opportunistic spinning which reduces number of
118d4e253bbSDavid Sterba * times the locking task needs to sleep.
119d4e253bbSDavid Sterba */
120d4e253bbSDavid Sterba
121196d59abSJosef Bacik /*
122196d59abSJosef Bacik * __btrfs_tree_read_lock - lock extent buffer for read
123196d59abSJosef Bacik * @eb: the eb to be locked
124d4e253bbSDavid Sterba * @nest: the nesting level to be used for lockdep
125196d59abSJosef Bacik *
126196d59abSJosef Bacik * This takes the read lock on the extent buffer, using the specified nesting
127b4ce94deSChris Mason * level for lockdep purposes.
1280ecae6ffSJosef Bacik */
__btrfs_tree_read_lock(struct extent_buffer * eb,enum btrfs_lock_nesting nest)129b4ce94deSChris Mason void __btrfs_tree_read_lock(struct extent_buffer *eb, enum btrfs_lock_nesting nest)
13034e73cc9SQu Wenruo {
13134e73cc9SQu Wenruo u64 start_ns = 0;
13234e73cc9SQu Wenruo
13334e73cc9SQu Wenruo if (trace_btrfs_tree_read_lock_enabled())
134196d59abSJosef Bacik start_ns = ktime_get_ns();
135196d59abSJosef Bacik
13634e73cc9SQu Wenruo down_read_nested(&eb->lock, nest);
137b4ce94deSChris Mason trace_btrfs_tree_read_lock(eb, start_ns);
138b4ce94deSChris Mason }
13951899412SJosef Bacik
btrfs_tree_read_lock(struct extent_buffer * eb)14051899412SJosef Bacik void btrfs_tree_read_lock(struct extent_buffer *eb)
1410ecae6ffSJosef Bacik {
14251899412SJosef Bacik __btrfs_tree_read_lock(eb, BTRFS_NESTING_NORMAL);
14351899412SJosef Bacik }
144b4ce94deSChris Mason
145196d59abSJosef Bacik /*
146d4e253bbSDavid Sterba * Try-lock for read.
1471a9fd417SDavid Sterba *
148b4ce94deSChris Mason * Return 1 if the rwlock has been taken, 0 otherwise
149bd681513SChris Mason */
btrfs_try_tree_read_lock(struct extent_buffer * eb)150b4ce94deSChris Mason int btrfs_try_tree_read_lock(struct extent_buffer *eb)
151196d59abSJosef Bacik {
15231aab402SQu Wenruo if (down_read_trylock(&eb->lock)) {
153bd681513SChris Mason trace_btrfs_try_tree_read_lock(eb);
154bd681513SChris Mason return 1;
155196d59abSJosef Bacik }
156196d59abSJosef Bacik return 0;
157b4ce94deSChris Mason }
158b4ce94deSChris Mason
159196d59abSJosef Bacik /*
160d4e253bbSDavid Sterba * Try-lock for write.
1611a9fd417SDavid Sterba *
162b4ce94deSChris Mason * Return 1 if the rwlock has been taken, 0 otherwise
163bd681513SChris Mason */
btrfs_try_tree_write_lock(struct extent_buffer * eb)164925baeddSChris Mason int btrfs_try_tree_write_lock(struct extent_buffer *eb)
165196d59abSJosef Bacik {
1665b25f70fSArne Jansen if (down_write_trylock(&eb->lock)) {
16731aab402SQu Wenruo eb->lock_owner = current->pid;
168b4ce94deSChris Mason trace_btrfs_try_tree_write_lock(eb);
169b4ce94deSChris Mason return 1;
170196d59abSJosef Bacik }
171196d59abSJosef Bacik return 0;
172b4ce94deSChris Mason }
173b4ce94deSChris Mason
1744048daedSJosef Bacik /*
175bd681513SChris Mason * Release read lock.
176bd681513SChris Mason */
btrfs_tree_read_unlock(struct extent_buffer * eb)177bd681513SChris Mason void btrfs_tree_read_unlock(struct extent_buffer *eb)
17831aab402SQu Wenruo {
179196d59abSJosef Bacik trace_btrfs_tree_read_unlock(eb);
180bd681513SChris Mason up_read(&eb->lock);
181bd681513SChris Mason }
182bd681513SChris Mason
183196d59abSJosef Bacik /*
184196d59abSJosef Bacik * __btrfs_tree_lock - lock eb for write
185196d59abSJosef Bacik * @eb: the eb to lock
186d4e253bbSDavid Sterba * @nest: the nesting to use for the lock
187196d59abSJosef Bacik *
188b4ce94deSChris Mason * Returns with the eb->lock write locked.
189fd7ba1c1SJosef Bacik */
__btrfs_tree_lock(struct extent_buffer * eb,enum btrfs_lock_nesting nest)19078d933c7SJules Irenge void __btrfs_tree_lock(struct extent_buffer *eb, enum btrfs_lock_nesting nest)
191b4ce94deSChris Mason __acquires(&eb->lock)
19234e73cc9SQu Wenruo {
19334e73cc9SQu Wenruo u64 start_ns = 0;
19434e73cc9SQu Wenruo
19534e73cc9SQu Wenruo if (trace_btrfs_tree_lock_enabled())
19634e73cc9SQu Wenruo start_ns = ktime_get_ns();
197196d59abSJosef Bacik
1985b25f70fSArne Jansen down_write_nested(&eb->lock, nest);
19934e73cc9SQu Wenruo eb->lock_owner = current->pid;
200b4ce94deSChris Mason trace_btrfs_tree_lock(eb, start_ns);
201b4ce94deSChris Mason }
202fd7ba1c1SJosef Bacik
btrfs_tree_lock(struct extent_buffer * eb)203fd7ba1c1SJosef Bacik void btrfs_tree_lock(struct extent_buffer *eb)
204fd7ba1c1SJosef Bacik {
205fd7ba1c1SJosef Bacik __btrfs_tree_lock(eb, BTRFS_NESTING_NORMAL);
206fd7ba1c1SJosef Bacik }
207bd681513SChris Mason
208196d59abSJosef Bacik /*
209bd681513SChris Mason * Release the write lock.
210143bede5SJeff Mahoney */
btrfs_tree_unlock(struct extent_buffer * eb)211925baeddSChris Mason void btrfs_tree_unlock(struct extent_buffer *eb)
21231aab402SQu Wenruo {
213ea4ebde0SChris Mason trace_btrfs_tree_unlock(eb);
214196d59abSJosef Bacik eb->lock_owner = 0;
215925baeddSChris Mason up_write(&eb->lock);
216ed2b1d36SDavid Sterba }
217ed2b1d36SDavid Sterba
2181f95ec01SDavid Sterba /*
2191f95ec01SDavid Sterba * This releases any locks held in the path starting at level and going all the
2201f95ec01SDavid Sterba * way up to the root.
2211f95ec01SDavid Sterba *
2221f95ec01SDavid Sterba * btrfs_search_slot will keep the lock held on higher nodes in a few corner
2231f95ec01SDavid Sterba * cases, such as COW of the block at slot zero in the node. This ignores
2241f95ec01SDavid Sterba * those rules, and it should only be called when there are no more updates to
2251f95ec01SDavid Sterba * be done higher up in the tree.
2261f95ec01SDavid Sterba */
btrfs_unlock_up_safe(struct btrfs_path * path,int level)2271f95ec01SDavid Sterba void btrfs_unlock_up_safe(struct btrfs_path *path, int level)
2281f95ec01SDavid Sterba {
2291f95ec01SDavid Sterba int i;
2301f95ec01SDavid Sterba
2311f95ec01SDavid Sterba if (path->keep_locks)
2321f95ec01SDavid Sterba return;
2331f95ec01SDavid Sterba
2341f95ec01SDavid Sterba for (i = level; i < BTRFS_MAX_LEVEL; i++) {
2351f95ec01SDavid Sterba if (!path->nodes[i])
2361f95ec01SDavid Sterba continue;
2371f95ec01SDavid Sterba if (!path->locks[i])
2381f95ec01SDavid Sterba continue;
2391f95ec01SDavid Sterba btrfs_tree_unlock_rw(path->nodes[i], path->locks[i]);
2401f95ec01SDavid Sterba path->locks[i] = 0;
2411f95ec01SDavid Sterba }
242b908c334SDavid Sterba }
243b908c334SDavid Sterba
244b908c334SDavid Sterba /*
245b908c334SDavid Sterba * Loop around taking references on and locking the root node of the tree until
246b908c334SDavid Sterba * we end up with a lock on the root node.
247b908c334SDavid Sterba *
248b908c334SDavid Sterba * Return: root extent buffer with write lock held
249b908c334SDavid Sterba */
btrfs_lock_root_node(struct btrfs_root * root)250b908c334SDavid Sterba struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root)
251b908c334SDavid Sterba {
252b908c334SDavid Sterba struct extent_buffer *eb;
253b908c334SDavid Sterba
254b908c334SDavid Sterba while (1) {
255b40130b2SJosef Bacik eb = btrfs_root_node(root);
256b40130b2SJosef Bacik
257b908c334SDavid Sterba btrfs_maybe_reset_lockdep_class(root, eb);
258b908c334SDavid Sterba btrfs_tree_lock(eb);
259b908c334SDavid Sterba if (eb == root->node)
260b908c334SDavid Sterba break;
261b908c334SDavid Sterba btrfs_tree_unlock(eb);
262b908c334SDavid Sterba free_extent_buffer(eb);
263b908c334SDavid Sterba }
264b908c334SDavid Sterba return eb;
265b908c334SDavid Sterba }
266b908c334SDavid Sterba
267b908c334SDavid Sterba /*
268b908c334SDavid Sterba * Loop around taking references on and locking the root node of the tree until
269b908c334SDavid Sterba * we end up with a lock on the root node.
270b908c334SDavid Sterba *
271b908c334SDavid Sterba * Return: root extent buffer with read lock held
2721bb96598SJosef Bacik */
btrfs_read_lock_root_node(struct btrfs_root * root)273b908c334SDavid Sterba struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root)
274b908c334SDavid Sterba {
275b908c334SDavid Sterba struct extent_buffer *eb;
276b908c334SDavid Sterba
277b908c334SDavid Sterba while (1) {
278b40130b2SJosef Bacik eb = btrfs_root_node(root);
279b40130b2SJosef Bacik
2801bb96598SJosef Bacik btrfs_maybe_reset_lockdep_class(root, eb);
281b908c334SDavid Sterba btrfs_tree_read_lock(eb);
282b908c334SDavid Sterba if (eb == root->node)
283b908c334SDavid Sterba break;
284b908c334SDavid Sterba btrfs_tree_read_unlock(eb);
285b908c334SDavid Sterba free_extent_buffer(eb);
286b908c334SDavid Sterba }
287b908c334SDavid Sterba return eb;
2882992df73SNikolay Borisov }
2892992df73SNikolay Borisov
290857bc13fSJosef Bacik /*
291857bc13fSJosef Bacik * Loop around taking references on and locking the root node of the tree in
292857bc13fSJosef Bacik * nowait mode until we end up with a lock on the root node or returning to
293857bc13fSJosef Bacik * avoid blocking.
294857bc13fSJosef Bacik *
295857bc13fSJosef Bacik * Return: root extent buffer with read lock held or -EAGAIN.
296857bc13fSJosef Bacik */
btrfs_try_read_lock_root_node(struct btrfs_root * root)297857bc13fSJosef Bacik struct extent_buffer *btrfs_try_read_lock_root_node(struct btrfs_root *root)
298857bc13fSJosef Bacik {
299857bc13fSJosef Bacik struct extent_buffer *eb;
300857bc13fSJosef Bacik
301857bc13fSJosef Bacik while (1) {
302857bc13fSJosef Bacik eb = btrfs_root_node(root);
303857bc13fSJosef Bacik if (!btrfs_try_tree_read_lock(eb)) {
304857bc13fSJosef Bacik free_extent_buffer(eb);
305857bc13fSJosef Bacik return ERR_PTR(-EAGAIN);
306857bc13fSJosef Bacik }
307857bc13fSJosef Bacik if (eb == root->node)
308857bc13fSJosef Bacik break;
309857bc13fSJosef Bacik btrfs_tree_read_unlock(eb);
310857bc13fSJosef Bacik free_extent_buffer(eb);
311857bc13fSJosef Bacik }
312857bc13fSJosef Bacik return eb;
313857bc13fSJosef Bacik }
314857bc13fSJosef Bacik
3152992df73SNikolay Borisov /*
3162992df73SNikolay Borisov * DREW locks
3172992df73SNikolay Borisov * ==========
3182992df73SNikolay Borisov *
3192992df73SNikolay Borisov * DREW stands for double-reader-writer-exclusion lock. It's used in situation
3202992df73SNikolay Borisov * where you want to provide A-B exclusion but not AA or BB.
3212992df73SNikolay Borisov *
3222992df73SNikolay Borisov * Currently implementation gives more priority to reader. If a reader and a
3232992df73SNikolay Borisov * writer both race to acquire their respective sides of the lock the writer
3242992df73SNikolay Borisov * would yield its lock as soon as it detects a concurrent reader. Additionally
3252992df73SNikolay Borisov * if there are pending readers no new writers would be allowed to come in and
3262992df73SNikolay Borisov * acquire the lock.
3272992df73SNikolay Borisov */
328*0b548539SDavid Sterba
btrfs_drew_lock_init(struct btrfs_drew_lock * lock)3292992df73SNikolay Borisov void btrfs_drew_lock_init(struct btrfs_drew_lock *lock)
3302992df73SNikolay Borisov {
331*0b548539SDavid Sterba atomic_set(&lock->readers, 0);
3322992df73SNikolay Borisov atomic_set(&lock->writers, 0);
3332992df73SNikolay Borisov init_waitqueue_head(&lock->pending_readers);
3342992df73SNikolay Borisov init_waitqueue_head(&lock->pending_writers);
3352992df73SNikolay Borisov }
3362992df73SNikolay Borisov
3372992df73SNikolay Borisov /* Return true if acquisition is successful, false otherwise */
btrfs_drew_try_write_lock(struct btrfs_drew_lock * lock)3382992df73SNikolay Borisov bool btrfs_drew_try_write_lock(struct btrfs_drew_lock *lock)
3392992df73SNikolay Borisov {
3402992df73SNikolay Borisov if (atomic_read(&lock->readers))
3412992df73SNikolay Borisov return false;
342*0b548539SDavid Sterba
3432992df73SNikolay Borisov atomic_inc(&lock->writers);
3442992df73SNikolay Borisov
345*0b548539SDavid Sterba /* Ensure writers count is updated before we check for pending readers */
3462992df73SNikolay Borisov smp_mb__after_atomic();
3472992df73SNikolay Borisov if (atomic_read(&lock->readers)) {
3482992df73SNikolay Borisov btrfs_drew_write_unlock(lock);
3492992df73SNikolay Borisov return false;
3502992df73SNikolay Borisov }
3512992df73SNikolay Borisov
3522992df73SNikolay Borisov return true;
3532992df73SNikolay Borisov }
3542992df73SNikolay Borisov
btrfs_drew_write_lock(struct btrfs_drew_lock * lock)3552992df73SNikolay Borisov void btrfs_drew_write_lock(struct btrfs_drew_lock *lock)
3562992df73SNikolay Borisov {
3572992df73SNikolay Borisov while (true) {
3582992df73SNikolay Borisov if (btrfs_drew_try_write_lock(lock))
3592992df73SNikolay Borisov return;
3602992df73SNikolay Borisov wait_event(lock->pending_writers, !atomic_read(&lock->readers));
3612992df73SNikolay Borisov }
3622992df73SNikolay Borisov }
3632992df73SNikolay Borisov
btrfs_drew_write_unlock(struct btrfs_drew_lock * lock)3642992df73SNikolay Borisov void btrfs_drew_write_unlock(struct btrfs_drew_lock *lock)
365*0b548539SDavid Sterba {
3662992df73SNikolay Borisov atomic_dec(&lock->writers);
3672992df73SNikolay Borisov cond_wake_up(&lock->pending_readers);
3682992df73SNikolay Borisov }
3692992df73SNikolay Borisov
btrfs_drew_read_lock(struct btrfs_drew_lock * lock)3702992df73SNikolay Borisov void btrfs_drew_read_lock(struct btrfs_drew_lock *lock)
3712992df73SNikolay Borisov {
3722992df73SNikolay Borisov atomic_inc(&lock->readers);
3732992df73SNikolay Borisov
3742992df73SNikolay Borisov /*
3752992df73SNikolay Borisov * Ensure the pending reader count is perceieved BEFORE this reader
3762992df73SNikolay Borisov * goes to sleep in case of active writers. This guarantees new writers
3772992df73SNikolay Borisov * won't be allowed and that the current reader will be woken up when
3782992df73SNikolay Borisov * the last active writer finishes its jobs.
3792992df73SNikolay Borisov */
3802992df73SNikolay Borisov smp_mb__after_atomic();
381*0b548539SDavid Sterba
3822992df73SNikolay Borisov wait_event(lock->pending_readers, atomic_read(&lock->writers) == 0);
3832992df73SNikolay Borisov }
3842992df73SNikolay Borisov
btrfs_drew_read_unlock(struct btrfs_drew_lock * lock)3852992df73SNikolay Borisov void btrfs_drew_read_unlock(struct btrfs_drew_lock *lock)
3862992df73SNikolay Borisov {
3872992df73SNikolay Borisov /*
3882992df73SNikolay Borisov * atomic_dec_and_test implies a full barrier, so woken up writers
3892992df73SNikolay Borisov * are guaranteed to see the decrement
3902992df73SNikolay Borisov */
3912992df73SNikolay Borisov if (atomic_dec_and_test(&lock->readers))
3922992df73SNikolay Borisov wake_up(&lock->pending_writers);
393 }
394