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