Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v5.2-rc4 362 lines 10 kB view raw
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 "ctree.h" 12#include "extent_io.h" 13#include "locking.h" 14 15#ifdef CONFIG_BTRFS_DEBUG 16static void btrfs_assert_spinning_writers_get(struct extent_buffer *eb) 17{ 18 WARN_ON(atomic_read(&eb->spinning_writers)); 19 atomic_inc(&eb->spinning_writers); 20} 21 22static void btrfs_assert_spinning_writers_put(struct extent_buffer *eb) 23{ 24 WARN_ON(atomic_read(&eb->spinning_writers) != 1); 25 atomic_dec(&eb->spinning_writers); 26} 27 28static void btrfs_assert_no_spinning_writers(struct extent_buffer *eb) 29{ 30 WARN_ON(atomic_read(&eb->spinning_writers)); 31} 32 33static void btrfs_assert_spinning_readers_get(struct extent_buffer *eb) 34{ 35 atomic_inc(&eb->spinning_readers); 36} 37 38static void btrfs_assert_spinning_readers_put(struct extent_buffer *eb) 39{ 40 WARN_ON(atomic_read(&eb->spinning_readers) == 0); 41 atomic_dec(&eb->spinning_readers); 42} 43 44static void btrfs_assert_tree_read_locks_get(struct extent_buffer *eb) 45{ 46 atomic_inc(&eb->read_locks); 47} 48 49static void btrfs_assert_tree_read_locks_put(struct extent_buffer *eb) 50{ 51 atomic_dec(&eb->read_locks); 52} 53 54static void btrfs_assert_tree_read_locked(struct extent_buffer *eb) 55{ 56 BUG_ON(!atomic_read(&eb->read_locks)); 57} 58 59static void btrfs_assert_tree_write_locks_get(struct extent_buffer *eb) 60{ 61 atomic_inc(&eb->write_locks); 62} 63 64static void btrfs_assert_tree_write_locks_put(struct extent_buffer *eb) 65{ 66 atomic_dec(&eb->write_locks); 67} 68 69void btrfs_assert_tree_locked(struct extent_buffer *eb) 70{ 71 BUG_ON(!atomic_read(&eb->write_locks)); 72} 73 74#else 75static void btrfs_assert_spinning_writers_get(struct extent_buffer *eb) { } 76static void btrfs_assert_spinning_writers_put(struct extent_buffer *eb) { } 77static void btrfs_assert_no_spinning_writers(struct extent_buffer *eb) { } 78static void btrfs_assert_spinning_readers_put(struct extent_buffer *eb) { } 79static void btrfs_assert_spinning_readers_get(struct extent_buffer *eb) { } 80static void btrfs_assert_tree_read_locked(struct extent_buffer *eb) { } 81static void btrfs_assert_tree_read_locks_get(struct extent_buffer *eb) { } 82static void btrfs_assert_tree_read_locks_put(struct extent_buffer *eb) { } 83void btrfs_assert_tree_locked(struct extent_buffer *eb) { } 84static void btrfs_assert_tree_write_locks_get(struct extent_buffer *eb) { } 85static void btrfs_assert_tree_write_locks_put(struct extent_buffer *eb) { } 86#endif 87 88void btrfs_set_lock_blocking_read(struct extent_buffer *eb) 89{ 90 trace_btrfs_set_lock_blocking_read(eb); 91 /* 92 * No lock is required. The lock owner may change if we have a read 93 * lock, but it won't change to or away from us. If we have the write 94 * lock, we are the owner and it'll never change. 95 */ 96 if (eb->lock_nested && current->pid == eb->lock_owner) 97 return; 98 btrfs_assert_tree_read_locked(eb); 99 atomic_inc(&eb->blocking_readers); 100 btrfs_assert_spinning_readers_put(eb); 101 read_unlock(&eb->lock); 102} 103 104void btrfs_set_lock_blocking_write(struct extent_buffer *eb) 105{ 106 trace_btrfs_set_lock_blocking_write(eb); 107 /* 108 * No lock is required. The lock owner may change if we have a read 109 * lock, but it won't change to or away from us. If we have the write 110 * lock, we are the owner and it'll never change. 111 */ 112 if (eb->lock_nested && current->pid == eb->lock_owner) 113 return; 114 if (atomic_read(&eb->blocking_writers) == 0) { 115 btrfs_assert_spinning_writers_put(eb); 116 btrfs_assert_tree_locked(eb); 117 atomic_inc(&eb->blocking_writers); 118 write_unlock(&eb->lock); 119 } 120} 121 122void btrfs_clear_lock_blocking_read(struct extent_buffer *eb) 123{ 124 trace_btrfs_clear_lock_blocking_read(eb); 125 /* 126 * No lock is required. The lock owner may change if we have a read 127 * lock, but it won't change to or away from us. If we have the write 128 * lock, we are the owner and it'll never change. 129 */ 130 if (eb->lock_nested && current->pid == eb->lock_owner) 131 return; 132 BUG_ON(atomic_read(&eb->blocking_readers) == 0); 133 read_lock(&eb->lock); 134 btrfs_assert_spinning_readers_get(eb); 135 /* atomic_dec_and_test implies a barrier */ 136 if (atomic_dec_and_test(&eb->blocking_readers)) 137 cond_wake_up_nomb(&eb->read_lock_wq); 138} 139 140void btrfs_clear_lock_blocking_write(struct extent_buffer *eb) 141{ 142 trace_btrfs_clear_lock_blocking_write(eb); 143 /* 144 * no lock is required. The lock owner may change if 145 * we have a read lock, but it won't change to or away 146 * from us. If we have the write lock, we are the owner 147 * and it'll never change. 148 */ 149 if (eb->lock_nested && current->pid == eb->lock_owner) 150 return; 151 BUG_ON(atomic_read(&eb->blocking_writers) != 1); 152 write_lock(&eb->lock); 153 btrfs_assert_spinning_writers_get(eb); 154 /* atomic_dec_and_test implies a barrier */ 155 if (atomic_dec_and_test(&eb->blocking_writers)) 156 cond_wake_up_nomb(&eb->write_lock_wq); 157} 158 159/* 160 * take a spinning read lock. This will wait for any blocking 161 * writers 162 */ 163void btrfs_tree_read_lock(struct extent_buffer *eb) 164{ 165 u64 start_ns = 0; 166 167 if (trace_btrfs_tree_read_lock_enabled()) 168 start_ns = ktime_get_ns(); 169again: 170 BUG_ON(!atomic_read(&eb->blocking_writers) && 171 current->pid == eb->lock_owner); 172 173 read_lock(&eb->lock); 174 if (atomic_read(&eb->blocking_writers) && 175 current->pid == eb->lock_owner) { 176 /* 177 * This extent is already write-locked by our thread. We allow 178 * an additional read lock to be added because it's for the same 179 * thread. btrfs_find_all_roots() depends on this as it may be 180 * called on a partly (write-)locked tree. 181 */ 182 BUG_ON(eb->lock_nested); 183 eb->lock_nested = true; 184 read_unlock(&eb->lock); 185 trace_btrfs_tree_read_lock(eb, start_ns); 186 return; 187 } 188 if (atomic_read(&eb->blocking_writers)) { 189 read_unlock(&eb->lock); 190 wait_event(eb->write_lock_wq, 191 atomic_read(&eb->blocking_writers) == 0); 192 goto again; 193 } 194 btrfs_assert_tree_read_locks_get(eb); 195 btrfs_assert_spinning_readers_get(eb); 196 trace_btrfs_tree_read_lock(eb, start_ns); 197} 198 199/* 200 * take a spinning read lock. 201 * returns 1 if we get the read lock and 0 if we don't 202 * this won't wait for blocking writers 203 */ 204int btrfs_tree_read_lock_atomic(struct extent_buffer *eb) 205{ 206 if (atomic_read(&eb->blocking_writers)) 207 return 0; 208 209 read_lock(&eb->lock); 210 if (atomic_read(&eb->blocking_writers)) { 211 read_unlock(&eb->lock); 212 return 0; 213 } 214 btrfs_assert_tree_read_locks_get(eb); 215 btrfs_assert_spinning_readers_get(eb); 216 trace_btrfs_tree_read_lock_atomic(eb); 217 return 1; 218} 219 220/* 221 * returns 1 if we get the read lock and 0 if we don't 222 * this won't wait for blocking writers 223 */ 224int btrfs_try_tree_read_lock(struct extent_buffer *eb) 225{ 226 if (atomic_read(&eb->blocking_writers)) 227 return 0; 228 229 if (!read_trylock(&eb->lock)) 230 return 0; 231 232 if (atomic_read(&eb->blocking_writers)) { 233 read_unlock(&eb->lock); 234 return 0; 235 } 236 btrfs_assert_tree_read_locks_get(eb); 237 btrfs_assert_spinning_readers_get(eb); 238 trace_btrfs_try_tree_read_lock(eb); 239 return 1; 240} 241 242/* 243 * returns 1 if we get the read lock and 0 if we don't 244 * this won't wait for blocking writers or readers 245 */ 246int btrfs_try_tree_write_lock(struct extent_buffer *eb) 247{ 248 if (atomic_read(&eb->blocking_writers) || 249 atomic_read(&eb->blocking_readers)) 250 return 0; 251 252 write_lock(&eb->lock); 253 if (atomic_read(&eb->blocking_writers) || 254 atomic_read(&eb->blocking_readers)) { 255 write_unlock(&eb->lock); 256 return 0; 257 } 258 btrfs_assert_tree_write_locks_get(eb); 259 btrfs_assert_spinning_writers_get(eb); 260 eb->lock_owner = current->pid; 261 trace_btrfs_try_tree_write_lock(eb); 262 return 1; 263} 264 265/* 266 * drop a spinning read lock 267 */ 268void btrfs_tree_read_unlock(struct extent_buffer *eb) 269{ 270 trace_btrfs_tree_read_unlock(eb); 271 /* 272 * if we're nested, we have the write lock. No new locking 273 * is needed as long as we are the lock owner. 274 * The write unlock will do a barrier for us, and the lock_nested 275 * field only matters to the lock owner. 276 */ 277 if (eb->lock_nested && current->pid == eb->lock_owner) { 278 eb->lock_nested = false; 279 return; 280 } 281 btrfs_assert_tree_read_locked(eb); 282 btrfs_assert_spinning_readers_put(eb); 283 btrfs_assert_tree_read_locks_put(eb); 284 read_unlock(&eb->lock); 285} 286 287/* 288 * drop a blocking read lock 289 */ 290void btrfs_tree_read_unlock_blocking(struct extent_buffer *eb) 291{ 292 trace_btrfs_tree_read_unlock_blocking(eb); 293 /* 294 * if we're nested, we have the write lock. No new locking 295 * is needed as long as we are the lock owner. 296 * The write unlock will do a barrier for us, and the lock_nested 297 * field only matters to the lock owner. 298 */ 299 if (eb->lock_nested && current->pid == eb->lock_owner) { 300 eb->lock_nested = false; 301 return; 302 } 303 btrfs_assert_tree_read_locked(eb); 304 WARN_ON(atomic_read(&eb->blocking_readers) == 0); 305 /* atomic_dec_and_test implies a barrier */ 306 if (atomic_dec_and_test(&eb->blocking_readers)) 307 cond_wake_up_nomb(&eb->read_lock_wq); 308 btrfs_assert_tree_read_locks_put(eb); 309} 310 311/* 312 * take a spinning write lock. This will wait for both 313 * blocking readers or writers 314 */ 315void btrfs_tree_lock(struct extent_buffer *eb) 316{ 317 u64 start_ns = 0; 318 319 if (trace_btrfs_tree_lock_enabled()) 320 start_ns = ktime_get_ns(); 321 322 WARN_ON(eb->lock_owner == current->pid); 323again: 324 wait_event(eb->read_lock_wq, atomic_read(&eb->blocking_readers) == 0); 325 wait_event(eb->write_lock_wq, atomic_read(&eb->blocking_writers) == 0); 326 write_lock(&eb->lock); 327 if (atomic_read(&eb->blocking_readers) || 328 atomic_read(&eb->blocking_writers)) { 329 write_unlock(&eb->lock); 330 goto again; 331 } 332 btrfs_assert_spinning_writers_get(eb); 333 btrfs_assert_tree_write_locks_get(eb); 334 eb->lock_owner = current->pid; 335 trace_btrfs_tree_lock(eb, start_ns); 336} 337 338/* 339 * drop a spinning or a blocking write lock. 340 */ 341void btrfs_tree_unlock(struct extent_buffer *eb) 342{ 343 int blockers = atomic_read(&eb->blocking_writers); 344 345 BUG_ON(blockers > 1); 346 347 btrfs_assert_tree_locked(eb); 348 trace_btrfs_tree_unlock(eb); 349 eb->lock_owner = 0; 350 btrfs_assert_tree_write_locks_put(eb); 351 352 if (blockers) { 353 btrfs_assert_no_spinning_writers(eb); 354 atomic_dec(&eb->blocking_writers); 355 /* Use the lighter barrier after atomic */ 356 smp_mb__after_atomic(); 357 cond_wake_up_nomb(&eb->write_lock_wq); 358 } else { 359 btrfs_assert_spinning_writers_put(eb); 360 write_unlock(&eb->lock); 361 } 362}