162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2008 Oracle.  All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/sched.h>
762306a36Sopenharmony_ci#include <linux/pagemap.h>
862306a36Sopenharmony_ci#include <linux/spinlock.h>
962306a36Sopenharmony_ci#include <linux/page-flags.h>
1062306a36Sopenharmony_ci#include <asm/bug.h>
1162306a36Sopenharmony_ci#include "misc.h"
1262306a36Sopenharmony_ci#include "ctree.h"
1362306a36Sopenharmony_ci#include "extent_io.h"
1462306a36Sopenharmony_ci#include "locking.h"
1562306a36Sopenharmony_ci#include "accessors.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * Lockdep class keys for extent_buffer->lock's in this root.  For a given
1962306a36Sopenharmony_ci * eb, the lockdep key is determined by the btrfs_root it belongs to and
2062306a36Sopenharmony_ci * the level the eb occupies in the tree.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * Different roots are used for different purposes and may nest inside each
2362306a36Sopenharmony_ci * other and they require separate keysets.  As lockdep keys should be
2462306a36Sopenharmony_ci * static, assign keysets according to the purpose of the root as indicated
2562306a36Sopenharmony_ci * by btrfs_root->root_key.objectid.  This ensures that all special purpose
2662306a36Sopenharmony_ci * roots have separate keysets.
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * Lock-nesting across peer nodes is always done with the immediate parent
2962306a36Sopenharmony_ci * node locked thus preventing deadlock.  As lockdep doesn't know this, use
3062306a36Sopenharmony_ci * subclass to avoid triggering lockdep warning in such cases.
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci * The key is set by the readpage_end_io_hook after the buffer has passed
3362306a36Sopenharmony_ci * csum validation but before the pages are unlocked.  It is also set by
3462306a36Sopenharmony_ci * btrfs_init_new_buffer on freshly allocated blocks.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * We also add a check to make sure the highest level of the tree is the
3762306a36Sopenharmony_ci * same as our lockdep setup here.  If BTRFS_MAX_LEVEL changes, this code
3862306a36Sopenharmony_ci * needs update as well.
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_LOCK_ALLOC
4162306a36Sopenharmony_ci#if BTRFS_MAX_LEVEL != 8
4262306a36Sopenharmony_ci#error
4362306a36Sopenharmony_ci#endif
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define DEFINE_LEVEL(stem, level)					\
4662306a36Sopenharmony_ci	.names[level] = "btrfs-" stem "-0" #level,
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define DEFINE_NAME(stem)						\
4962306a36Sopenharmony_ci	DEFINE_LEVEL(stem, 0)						\
5062306a36Sopenharmony_ci	DEFINE_LEVEL(stem, 1)						\
5162306a36Sopenharmony_ci	DEFINE_LEVEL(stem, 2)						\
5262306a36Sopenharmony_ci	DEFINE_LEVEL(stem, 3)						\
5362306a36Sopenharmony_ci	DEFINE_LEVEL(stem, 4)						\
5462306a36Sopenharmony_ci	DEFINE_LEVEL(stem, 5)						\
5562306a36Sopenharmony_ci	DEFINE_LEVEL(stem, 6)						\
5662306a36Sopenharmony_ci	DEFINE_LEVEL(stem, 7)
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic struct btrfs_lockdep_keyset {
5962306a36Sopenharmony_ci	u64			id;		/* root objectid */
6062306a36Sopenharmony_ci	/* Longest entry: btrfs-block-group-00 */
6162306a36Sopenharmony_ci	char			names[BTRFS_MAX_LEVEL][24];
6262306a36Sopenharmony_ci	struct lock_class_key	keys[BTRFS_MAX_LEVEL];
6362306a36Sopenharmony_ci} btrfs_lockdep_keysets[] = {
6462306a36Sopenharmony_ci	{ .id = BTRFS_ROOT_TREE_OBJECTID,	DEFINE_NAME("root")	},
6562306a36Sopenharmony_ci	{ .id = BTRFS_EXTENT_TREE_OBJECTID,	DEFINE_NAME("extent")	},
6662306a36Sopenharmony_ci	{ .id = BTRFS_CHUNK_TREE_OBJECTID,	DEFINE_NAME("chunk")	},
6762306a36Sopenharmony_ci	{ .id = BTRFS_DEV_TREE_OBJECTID,	DEFINE_NAME("dev")	},
6862306a36Sopenharmony_ci	{ .id = BTRFS_CSUM_TREE_OBJECTID,	DEFINE_NAME("csum")	},
6962306a36Sopenharmony_ci	{ .id = BTRFS_QUOTA_TREE_OBJECTID,	DEFINE_NAME("quota")	},
7062306a36Sopenharmony_ci	{ .id = BTRFS_TREE_LOG_OBJECTID,	DEFINE_NAME("log")	},
7162306a36Sopenharmony_ci	{ .id = BTRFS_TREE_RELOC_OBJECTID,	DEFINE_NAME("treloc")	},
7262306a36Sopenharmony_ci	{ .id = BTRFS_DATA_RELOC_TREE_OBJECTID,	DEFINE_NAME("dreloc")	},
7362306a36Sopenharmony_ci	{ .id = BTRFS_UUID_TREE_OBJECTID,	DEFINE_NAME("uuid")	},
7462306a36Sopenharmony_ci	{ .id = BTRFS_FREE_SPACE_TREE_OBJECTID,	DEFINE_NAME("free-space") },
7562306a36Sopenharmony_ci	{ .id = BTRFS_BLOCK_GROUP_TREE_OBJECTID, DEFINE_NAME("block-group") },
7662306a36Sopenharmony_ci	{ .id = 0,				DEFINE_NAME("tree")	},
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#undef DEFINE_LEVEL
8062306a36Sopenharmony_ci#undef DEFINE_NAME
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_civoid btrfs_set_buffer_lockdep_class(u64 objectid, struct extent_buffer *eb, int level)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct btrfs_lockdep_keyset *ks;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	BUG_ON(level >= ARRAY_SIZE(ks->keys));
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/* Find the matching keyset, id 0 is the default entry */
8962306a36Sopenharmony_ci	for (ks = btrfs_lockdep_keysets; ks->id; ks++)
9062306a36Sopenharmony_ci		if (ks->id == objectid)
9162306a36Sopenharmony_ci			break;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	lockdep_set_class_and_name(&eb->lock, &ks->keys[level], ks->names[level]);
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_civoid btrfs_maybe_reset_lockdep_class(struct btrfs_root *root, struct extent_buffer *eb)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	if (test_bit(BTRFS_ROOT_RESET_LOCKDEP_CLASS, &root->state))
9962306a36Sopenharmony_ci		btrfs_set_buffer_lockdep_class(root->root_key.objectid,
10062306a36Sopenharmony_ci					       eb, btrfs_header_level(eb));
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#endif
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/*
10662306a36Sopenharmony_ci * Extent buffer locking
10762306a36Sopenharmony_ci * =====================
10862306a36Sopenharmony_ci *
10962306a36Sopenharmony_ci * We use a rw_semaphore for tree locking, and the semantics are exactly the
11062306a36Sopenharmony_ci * same:
11162306a36Sopenharmony_ci *
11262306a36Sopenharmony_ci * - reader/writer exclusion
11362306a36Sopenharmony_ci * - writer/writer exclusion
11462306a36Sopenharmony_ci * - reader/reader sharing
11562306a36Sopenharmony_ci * - try-lock semantics for readers and writers
11662306a36Sopenharmony_ci *
11762306a36Sopenharmony_ci * The rwsem implementation does opportunistic spinning which reduces number of
11862306a36Sopenharmony_ci * times the locking task needs to sleep.
11962306a36Sopenharmony_ci */
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/*
12262306a36Sopenharmony_ci * __btrfs_tree_read_lock - lock extent buffer for read
12362306a36Sopenharmony_ci * @eb:		the eb to be locked
12462306a36Sopenharmony_ci * @nest:	the nesting level to be used for lockdep
12562306a36Sopenharmony_ci *
12662306a36Sopenharmony_ci * This takes the read lock on the extent buffer, using the specified nesting
12762306a36Sopenharmony_ci * level for lockdep purposes.
12862306a36Sopenharmony_ci */
12962306a36Sopenharmony_civoid __btrfs_tree_read_lock(struct extent_buffer *eb, enum btrfs_lock_nesting nest)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	u64 start_ns = 0;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (trace_btrfs_tree_read_lock_enabled())
13462306a36Sopenharmony_ci		start_ns = ktime_get_ns();
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	down_read_nested(&eb->lock, nest);
13762306a36Sopenharmony_ci	trace_btrfs_tree_read_lock(eb, start_ns);
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_civoid btrfs_tree_read_lock(struct extent_buffer *eb)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	__btrfs_tree_read_lock(eb, BTRFS_NESTING_NORMAL);
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/*
14662306a36Sopenharmony_ci * Try-lock for read.
14762306a36Sopenharmony_ci *
14862306a36Sopenharmony_ci * Return 1 if the rwlock has been taken, 0 otherwise
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_ciint btrfs_try_tree_read_lock(struct extent_buffer *eb)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	if (down_read_trylock(&eb->lock)) {
15362306a36Sopenharmony_ci		trace_btrfs_try_tree_read_lock(eb);
15462306a36Sopenharmony_ci		return 1;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci	return 0;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/*
16062306a36Sopenharmony_ci * Try-lock for write.
16162306a36Sopenharmony_ci *
16262306a36Sopenharmony_ci * Return 1 if the rwlock has been taken, 0 otherwise
16362306a36Sopenharmony_ci */
16462306a36Sopenharmony_ciint btrfs_try_tree_write_lock(struct extent_buffer *eb)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	if (down_write_trylock(&eb->lock)) {
16762306a36Sopenharmony_ci		eb->lock_owner = current->pid;
16862306a36Sopenharmony_ci		trace_btrfs_try_tree_write_lock(eb);
16962306a36Sopenharmony_ci		return 1;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci	return 0;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/*
17562306a36Sopenharmony_ci * Release read lock.
17662306a36Sopenharmony_ci */
17762306a36Sopenharmony_civoid btrfs_tree_read_unlock(struct extent_buffer *eb)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	trace_btrfs_tree_read_unlock(eb);
18062306a36Sopenharmony_ci	up_read(&eb->lock);
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/*
18462306a36Sopenharmony_ci * __btrfs_tree_lock - lock eb for write
18562306a36Sopenharmony_ci * @eb:		the eb to lock
18662306a36Sopenharmony_ci * @nest:	the nesting to use for the lock
18762306a36Sopenharmony_ci *
18862306a36Sopenharmony_ci * Returns with the eb->lock write locked.
18962306a36Sopenharmony_ci */
19062306a36Sopenharmony_civoid __btrfs_tree_lock(struct extent_buffer *eb, enum btrfs_lock_nesting nest)
19162306a36Sopenharmony_ci	__acquires(&eb->lock)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	u64 start_ns = 0;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	if (trace_btrfs_tree_lock_enabled())
19662306a36Sopenharmony_ci		start_ns = ktime_get_ns();
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	down_write_nested(&eb->lock, nest);
19962306a36Sopenharmony_ci	eb->lock_owner = current->pid;
20062306a36Sopenharmony_ci	trace_btrfs_tree_lock(eb, start_ns);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_civoid btrfs_tree_lock(struct extent_buffer *eb)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	__btrfs_tree_lock(eb, BTRFS_NESTING_NORMAL);
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci/*
20962306a36Sopenharmony_ci * Release the write lock.
21062306a36Sopenharmony_ci */
21162306a36Sopenharmony_civoid btrfs_tree_unlock(struct extent_buffer *eb)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	trace_btrfs_tree_unlock(eb);
21462306a36Sopenharmony_ci	eb->lock_owner = 0;
21562306a36Sopenharmony_ci	up_write(&eb->lock);
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci/*
21962306a36Sopenharmony_ci * This releases any locks held in the path starting at level and going all the
22062306a36Sopenharmony_ci * way up to the root.
22162306a36Sopenharmony_ci *
22262306a36Sopenharmony_ci * btrfs_search_slot will keep the lock held on higher nodes in a few corner
22362306a36Sopenharmony_ci * cases, such as COW of the block at slot zero in the node.  This ignores
22462306a36Sopenharmony_ci * those rules, and it should only be called when there are no more updates to
22562306a36Sopenharmony_ci * be done higher up in the tree.
22662306a36Sopenharmony_ci */
22762306a36Sopenharmony_civoid btrfs_unlock_up_safe(struct btrfs_path *path, int level)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	int i;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (path->keep_locks)
23262306a36Sopenharmony_ci		return;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	for (i = level; i < BTRFS_MAX_LEVEL; i++) {
23562306a36Sopenharmony_ci		if (!path->nodes[i])
23662306a36Sopenharmony_ci			continue;
23762306a36Sopenharmony_ci		if (!path->locks[i])
23862306a36Sopenharmony_ci			continue;
23962306a36Sopenharmony_ci		btrfs_tree_unlock_rw(path->nodes[i], path->locks[i]);
24062306a36Sopenharmony_ci		path->locks[i] = 0;
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci/*
24562306a36Sopenharmony_ci * Loop around taking references on and locking the root node of the tree until
24662306a36Sopenharmony_ci * we end up with a lock on the root node.
24762306a36Sopenharmony_ci *
24862306a36Sopenharmony_ci * Return: root extent buffer with write lock held
24962306a36Sopenharmony_ci */
25062306a36Sopenharmony_cistruct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	struct extent_buffer *eb;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	while (1) {
25562306a36Sopenharmony_ci		eb = btrfs_root_node(root);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci		btrfs_maybe_reset_lockdep_class(root, eb);
25862306a36Sopenharmony_ci		btrfs_tree_lock(eb);
25962306a36Sopenharmony_ci		if (eb == root->node)
26062306a36Sopenharmony_ci			break;
26162306a36Sopenharmony_ci		btrfs_tree_unlock(eb);
26262306a36Sopenharmony_ci		free_extent_buffer(eb);
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci	return eb;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/*
26862306a36Sopenharmony_ci * Loop around taking references on and locking the root node of the tree until
26962306a36Sopenharmony_ci * we end up with a lock on the root node.
27062306a36Sopenharmony_ci *
27162306a36Sopenharmony_ci * Return: root extent buffer with read lock held
27262306a36Sopenharmony_ci */
27362306a36Sopenharmony_cistruct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct extent_buffer *eb;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	while (1) {
27862306a36Sopenharmony_ci		eb = btrfs_root_node(root);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci		btrfs_maybe_reset_lockdep_class(root, eb);
28162306a36Sopenharmony_ci		btrfs_tree_read_lock(eb);
28262306a36Sopenharmony_ci		if (eb == root->node)
28362306a36Sopenharmony_ci			break;
28462306a36Sopenharmony_ci		btrfs_tree_read_unlock(eb);
28562306a36Sopenharmony_ci		free_extent_buffer(eb);
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci	return eb;
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci/*
29162306a36Sopenharmony_ci * Loop around taking references on and locking the root node of the tree in
29262306a36Sopenharmony_ci * nowait mode until we end up with a lock on the root node or returning to
29362306a36Sopenharmony_ci * avoid blocking.
29462306a36Sopenharmony_ci *
29562306a36Sopenharmony_ci * Return: root extent buffer with read lock held or -EAGAIN.
29662306a36Sopenharmony_ci */
29762306a36Sopenharmony_cistruct extent_buffer *btrfs_try_read_lock_root_node(struct btrfs_root *root)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct extent_buffer *eb;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	while (1) {
30262306a36Sopenharmony_ci		eb = btrfs_root_node(root);
30362306a36Sopenharmony_ci		if (!btrfs_try_tree_read_lock(eb)) {
30462306a36Sopenharmony_ci			free_extent_buffer(eb);
30562306a36Sopenharmony_ci			return ERR_PTR(-EAGAIN);
30662306a36Sopenharmony_ci		}
30762306a36Sopenharmony_ci		if (eb == root->node)
30862306a36Sopenharmony_ci			break;
30962306a36Sopenharmony_ci		btrfs_tree_read_unlock(eb);
31062306a36Sopenharmony_ci		free_extent_buffer(eb);
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci	return eb;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci/*
31662306a36Sopenharmony_ci * DREW locks
31762306a36Sopenharmony_ci * ==========
31862306a36Sopenharmony_ci *
31962306a36Sopenharmony_ci * DREW stands for double-reader-writer-exclusion lock. It's used in situation
32062306a36Sopenharmony_ci * where you want to provide A-B exclusion but not AA or BB.
32162306a36Sopenharmony_ci *
32262306a36Sopenharmony_ci * Currently implementation gives more priority to reader. If a reader and a
32362306a36Sopenharmony_ci * writer both race to acquire their respective sides of the lock the writer
32462306a36Sopenharmony_ci * would yield its lock as soon as it detects a concurrent reader. Additionally
32562306a36Sopenharmony_ci * if there are pending readers no new writers would be allowed to come in and
32662306a36Sopenharmony_ci * acquire the lock.
32762306a36Sopenharmony_ci */
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_civoid btrfs_drew_lock_init(struct btrfs_drew_lock *lock)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	atomic_set(&lock->readers, 0);
33262306a36Sopenharmony_ci	atomic_set(&lock->writers, 0);
33362306a36Sopenharmony_ci	init_waitqueue_head(&lock->pending_readers);
33462306a36Sopenharmony_ci	init_waitqueue_head(&lock->pending_writers);
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci/* Return true if acquisition is successful, false otherwise */
33862306a36Sopenharmony_cibool btrfs_drew_try_write_lock(struct btrfs_drew_lock *lock)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	if (atomic_read(&lock->readers))
34162306a36Sopenharmony_ci		return false;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	atomic_inc(&lock->writers);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* Ensure writers count is updated before we check for pending readers */
34662306a36Sopenharmony_ci	smp_mb__after_atomic();
34762306a36Sopenharmony_ci	if (atomic_read(&lock->readers)) {
34862306a36Sopenharmony_ci		btrfs_drew_write_unlock(lock);
34962306a36Sopenharmony_ci		return false;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	return true;
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_civoid btrfs_drew_write_lock(struct btrfs_drew_lock *lock)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	while (true) {
35862306a36Sopenharmony_ci		if (btrfs_drew_try_write_lock(lock))
35962306a36Sopenharmony_ci			return;
36062306a36Sopenharmony_ci		wait_event(lock->pending_writers, !atomic_read(&lock->readers));
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_civoid btrfs_drew_write_unlock(struct btrfs_drew_lock *lock)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	atomic_dec(&lock->writers);
36762306a36Sopenharmony_ci	cond_wake_up(&lock->pending_readers);
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_civoid btrfs_drew_read_lock(struct btrfs_drew_lock *lock)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	atomic_inc(&lock->readers);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	/*
37562306a36Sopenharmony_ci	 * Ensure the pending reader count is perceieved BEFORE this reader
37662306a36Sopenharmony_ci	 * goes to sleep in case of active writers. This guarantees new writers
37762306a36Sopenharmony_ci	 * won't be allowed and that the current reader will be woken up when
37862306a36Sopenharmony_ci	 * the last active writer finishes its jobs.
37962306a36Sopenharmony_ci	 */
38062306a36Sopenharmony_ci	smp_mb__after_atomic();
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	wait_event(lock->pending_readers, atomic_read(&lock->writers) == 0);
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_civoid btrfs_drew_read_unlock(struct btrfs_drew_lock *lock)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	/*
38862306a36Sopenharmony_ci	 * atomic_dec_and_test implies a full barrier, so woken up writers
38962306a36Sopenharmony_ci	 * are guaranteed to see the decrement
39062306a36Sopenharmony_ci	 */
39162306a36Sopenharmony_ci	if (atomic_dec_and_test(&lock->readers))
39262306a36Sopenharmony_ci		wake_up(&lock->pending_writers);
39362306a36Sopenharmony_ci}
394