1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3 * This file and its contents are supplied under the terms of the
4 * Common Development and Distribution License ("CDDL"), version 1.0.
5 * You may only use this file in accordance with the terms of version
6 * 1.0 of the CDDL.
7 *
8 * A full copy of the text of the CDDL should have accompanied this
9 * source. A copy of the CDDL is also available via the Internet at
10 * https://opensource.org/license/CDDL-1.0.
11 */
12 /*
13 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
14 * Use is subject to license terms.
15 */
16 /*
17 * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
18 */
19
20 /*
21 * This file contains the code to implement file range locking in
22 * ZFS, although there isn't much specific to ZFS (all that comes to mind is
23 * support for growing the blocksize).
24 *
25 * Interface
26 * ---------
27 * Defined in zfs_rlock.h but essentially:
28 * lr = rangelock_enter(zp, off, len, lock_type);
29 * rangelock_reduce(lr, off, len); // optional
30 * rangelock_exit(lr);
31 *
32 * Range locking rules
33 * --------------------
34 * 1. When truncating a file (zfs_create, zfs_setattr, zfs_space) the whole
35 * file range needs to be locked as RL_WRITER. Only then can the pages be
36 * freed etc and zp_size reset. zp_size must be set within range lock.
37 * 2. For writes and punching holes (zfs_write & zfs_space) just the range
38 * being written or freed needs to be locked as RL_WRITER.
39 * Multiple writes at the end of the file must coordinate zp_size updates
40 * to ensure data isn't lost. A compare and swap loop is currently used
41 * to ensure the file size is at least the offset last written.
42 * 3. For reads (zfs_read, zfs_get_data & zfs_putapage) just the range being
43 * read needs to be locked as RL_READER. A check against zp_size can then
44 * be made for reading beyond end of file.
45 *
46 * AVL tree
47 * --------
48 * An AVL tree is used to maintain the state of the existing ranges
49 * that are locked for exclusive (writer) or shared (reader) use.
50 * The starting range offset is used for searching and sorting the tree.
51 *
52 * Common case
53 * -----------
54 * The (hopefully) usual case is of no overlaps or contention for locks. On
55 * entry to rangelock_enter(), a locked_range_t is allocated; the tree
56 * searched that finds no overlap, and *this* locked_range_t is placed in the
57 * tree.
58 *
59 * Overlaps/Reference counting/Proxy locks
60 * ---------------------------------------
61 * The avl code only allows one node at a particular offset. Also it's very
62 * inefficient to search through all previous entries looking for overlaps
63 * (because the very 1st in the ordered list might be at offset 0 but
64 * cover the whole file).
65 * So this implementation uses reference counts and proxy range locks.
66 * Firstly, only reader locks use reference counts and proxy locks,
67 * because writer locks are exclusive.
68 * When a reader lock overlaps with another then a proxy lock is created
69 * for that range and replaces the original lock. If the overlap
70 * is exact then the reference count of the proxy is simply incremented.
71 * Otherwise, the proxy lock is split into smaller lock ranges and
72 * new proxy locks created for non overlapping ranges.
73 * The reference counts are adjusted accordingly.
74 * Meanwhile, the original lock is kept around (this is the callers handle)
75 * and its offset and length are used when releasing the lock.
76 *
77 * Thread coordination
78 * -------------------
79 * In order to make wakeups efficient and to ensure multiple continuous
80 * readers on a range don't starve a writer for the same range lock,
81 * two condition variables are allocated in each rl_t.
82 * If a writer (or reader) can't get a range it initialises the writer
83 * (or reader) cv; sets a flag saying there's a writer (or reader) waiting;
84 * and waits on that cv. When a thread unlocks that range it wakes up all
85 * writers then all readers before destroying the lock.
86 *
87 * Append mode writes
88 * ------------------
89 * Append mode writes need to lock a range at the end of a file.
90 * The offset of the end of the file is determined under the
91 * range locking mutex, and the lock type converted from RL_APPEND to
92 * RL_WRITER and the range locked.
93 *
94 * Grow block handling
95 * -------------------
96 * ZFS supports multiple block sizes, up to 16MB. The smallest
97 * block size is used for the file which is grown as needed. During this
98 * growth all other writers and readers must be excluded.
99 * So if the block size needs to be grown then the whole file is
100 * exclusively locked, then later the caller will reduce the lock
101 * range to just the range to be written using rangelock_reduce().
102 */
103
104 #include <sys/zfs_context.h>
105 #include <sys/zfs_rlock.h>
106
107
108 /*
109 * AVL comparison function used to order range locks
110 * Locks are ordered on the start offset of the range.
111 */
112 static int
zfs_rangelock_compare(const void * arg1,const void * arg2)113 zfs_rangelock_compare(const void *arg1, const void *arg2)
114 {
115 const zfs_locked_range_t *rl1 = (const zfs_locked_range_t *)arg1;
116 const zfs_locked_range_t *rl2 = (const zfs_locked_range_t *)arg2;
117
118 return (TREE_CMP(rl1->lr_offset, rl2->lr_offset));
119 }
120
121 /*
122 * The callback is invoked when acquiring a RL_WRITER or RL_APPEND lock.
123 * It must convert RL_APPEND to RL_WRITER (starting at the end of the file),
124 * and may increase the range that's locked for RL_WRITER.
125 */
126 void
zfs_rangelock_init(zfs_rangelock_t * rl,zfs_rangelock_cb_t * cb,void * arg)127 zfs_rangelock_init(zfs_rangelock_t *rl, zfs_rangelock_cb_t *cb, void *arg)
128 {
129 mutex_init(&rl->rl_lock, NULL, MUTEX_DEFAULT, NULL);
130 avl_create(&rl->rl_tree, zfs_rangelock_compare,
131 sizeof (zfs_locked_range_t), offsetof(zfs_locked_range_t, lr_node));
132 rl->rl_cb = cb;
133 rl->rl_arg = arg;
134 }
135
136 void
zfs_rangelock_fini(zfs_rangelock_t * rl)137 zfs_rangelock_fini(zfs_rangelock_t *rl)
138 {
139 mutex_destroy(&rl->rl_lock);
140 avl_destroy(&rl->rl_tree);
141 }
142
143 /*
144 * Check if a write lock can be grabbed. If not, fail immediately or sleep and
145 * recheck until available, depending on the value of the "nonblock" parameter.
146 */
147 static boolean_t
zfs_rangelock_enter_writer(zfs_rangelock_t * rl,zfs_locked_range_t * new,boolean_t nonblock)148 zfs_rangelock_enter_writer(zfs_rangelock_t *rl, zfs_locked_range_t *new,
149 boolean_t nonblock)
150 {
151 avl_tree_t *tree = &rl->rl_tree;
152 zfs_locked_range_t *lr;
153 avl_index_t where;
154 uint64_t orig_off = new->lr_offset;
155 uint64_t orig_len = new->lr_length;
156 zfs_rangelock_type_t orig_type = new->lr_type;
157
158 for (;;) {
159 /*
160 * Call callback which can modify new->r_off,len,type.
161 * Note, the callback is used by the ZPL to handle appending
162 * and changing blocksizes. It isn't needed for zvols.
163 */
164 if (rl->rl_cb != NULL) {
165 rl->rl_cb(new, rl->rl_arg);
166 }
167
168 /*
169 * If the type was APPEND, the callback must convert it to
170 * WRITER.
171 */
172 ASSERT3U(new->lr_type, ==, RL_WRITER);
173
174 /*
175 * First check for the usual case of no locks
176 */
177 if (avl_numnodes(tree) == 0) {
178 avl_add(tree, new);
179 return (B_TRUE);
180 }
181
182 /*
183 * Look for any locks in the range.
184 */
185 lr = avl_find(tree, new, &where);
186 if (lr != NULL)
187 goto wait; /* already locked at same offset */
188
189 lr = avl_nearest(tree, where, AVL_AFTER);
190 if (lr != NULL &&
191 lr->lr_offset < new->lr_offset + new->lr_length)
192 goto wait;
193
194 lr = avl_nearest(tree, where, AVL_BEFORE);
195 if (lr != NULL &&
196 lr->lr_offset + lr->lr_length > new->lr_offset)
197 goto wait;
198
199 avl_insert(tree, new, where);
200 return (B_TRUE);
201 wait:
202 if (nonblock)
203 return (B_FALSE);
204 if (!lr->lr_write_wanted) {
205 cv_init(&lr->lr_write_cv, NULL, CV_DEFAULT, NULL);
206 lr->lr_write_wanted = B_TRUE;
207 }
208 cv_wait(&lr->lr_write_cv, &rl->rl_lock);
209
210 /* reset to original */
211 new->lr_offset = orig_off;
212 new->lr_length = orig_len;
213 new->lr_type = orig_type;
214 }
215 }
216
217 /*
218 * If this is an original (non-proxy) lock then replace it by
219 * a proxy and return the proxy.
220 */
221 static zfs_locked_range_t *
zfs_rangelock_proxify(avl_tree_t * tree,zfs_locked_range_t * lr)222 zfs_rangelock_proxify(avl_tree_t *tree, zfs_locked_range_t *lr)
223 {
224 zfs_locked_range_t *proxy;
225
226 if (lr->lr_proxy)
227 return (lr); /* already a proxy */
228
229 ASSERT3U(lr->lr_count, ==, 1);
230 ASSERT(lr->lr_write_wanted == B_FALSE);
231 ASSERT(lr->lr_read_wanted == B_FALSE);
232 avl_remove(tree, lr);
233 lr->lr_count = 0;
234
235 /* create a proxy range lock */
236 proxy = kmem_alloc(sizeof (zfs_locked_range_t), KM_SLEEP);
237 proxy->lr_offset = lr->lr_offset;
238 proxy->lr_length = lr->lr_length;
239 proxy->lr_count = 1;
240 proxy->lr_type = RL_READER;
241 proxy->lr_proxy = B_TRUE;
242 proxy->lr_write_wanted = B_FALSE;
243 proxy->lr_read_wanted = B_FALSE;
244 avl_add(tree, proxy);
245
246 return (proxy);
247 }
248
249 /*
250 * Split the range lock at the supplied offset
251 * returning the *front* proxy.
252 */
253 static zfs_locked_range_t *
zfs_rangelock_split(avl_tree_t * tree,zfs_locked_range_t * lr,uint64_t off)254 zfs_rangelock_split(avl_tree_t *tree, zfs_locked_range_t *lr, uint64_t off)
255 {
256 zfs_locked_range_t *rear;
257
258 ASSERT3U(lr->lr_length, >, 1);
259 ASSERT3U(off, >, lr->lr_offset);
260 ASSERT3U(off, <, lr->lr_offset + lr->lr_length);
261 ASSERT(lr->lr_write_wanted == B_FALSE);
262 ASSERT(lr->lr_read_wanted == B_FALSE);
263
264 /* create the rear proxy range lock */
265 rear = kmem_alloc(sizeof (zfs_locked_range_t), KM_SLEEP);
266 rear->lr_offset = off;
267 rear->lr_length = lr->lr_offset + lr->lr_length - off;
268 rear->lr_count = lr->lr_count;
269 rear->lr_type = RL_READER;
270 rear->lr_proxy = B_TRUE;
271 rear->lr_write_wanted = B_FALSE;
272 rear->lr_read_wanted = B_FALSE;
273
274 zfs_locked_range_t *front = zfs_rangelock_proxify(tree, lr);
275 front->lr_length = off - lr->lr_offset;
276
277 avl_insert_here(tree, rear, front, AVL_AFTER);
278 return (front);
279 }
280
281 /*
282 * Create and add a new proxy range lock for the supplied range.
283 */
284 static void
zfs_rangelock_new_proxy(avl_tree_t * tree,uint64_t off,uint64_t len)285 zfs_rangelock_new_proxy(avl_tree_t *tree, uint64_t off, uint64_t len)
286 {
287 zfs_locked_range_t *lr;
288
289 ASSERT(len != 0);
290 lr = kmem_alloc(sizeof (zfs_locked_range_t), KM_SLEEP);
291 lr->lr_offset = off;
292 lr->lr_length = len;
293 lr->lr_count = 1;
294 lr->lr_type = RL_READER;
295 lr->lr_proxy = B_TRUE;
296 lr->lr_write_wanted = B_FALSE;
297 lr->lr_read_wanted = B_FALSE;
298 avl_add(tree, lr);
299 }
300
301 static void
zfs_rangelock_add_reader(avl_tree_t * tree,zfs_locked_range_t * new,zfs_locked_range_t * prev,avl_index_t where)302 zfs_rangelock_add_reader(avl_tree_t *tree, zfs_locked_range_t *new,
303 zfs_locked_range_t *prev, avl_index_t where)
304 {
305 zfs_locked_range_t *next;
306 uint64_t off = new->lr_offset;
307 uint64_t len = new->lr_length;
308
309 /*
310 * prev arrives either:
311 * - pointing to an entry at the same offset
312 * - pointing to the entry with the closest previous offset whose
313 * range may overlap with the new range
314 * - null, if there were no ranges starting before the new one
315 */
316 if (prev != NULL) {
317 if (prev->lr_offset + prev->lr_length <= off) {
318 prev = NULL;
319 } else if (prev->lr_offset != off) {
320 /*
321 * convert to proxy if needed then
322 * split this entry and bump ref count
323 */
324 prev = zfs_rangelock_split(tree, prev, off);
325 prev = AVL_NEXT(tree, prev); /* move to rear range */
326 }
327 }
328 ASSERT((prev == NULL) || (prev->lr_offset == off));
329
330 if (prev != NULL)
331 next = prev;
332 else
333 next = avl_nearest(tree, where, AVL_AFTER);
334
335 if (next == NULL || off + len <= next->lr_offset) {
336 /* no overlaps, use the original new rl_t in the tree */
337 avl_insert(tree, new, where);
338 return;
339 }
340
341 if (off < next->lr_offset) {
342 /* Add a proxy for initial range before the overlap */
343 zfs_rangelock_new_proxy(tree, off, next->lr_offset - off);
344 }
345
346 new->lr_count = 0; /* will use proxies in tree */
347 /*
348 * We now search forward through the ranges, until we go past the end
349 * of the new range. For each entry we make it a proxy if it
350 * isn't already, then bump its reference count. If there's any
351 * gaps between the ranges then we create a new proxy range.
352 */
353 for (prev = NULL; next; prev = next, next = AVL_NEXT(tree, next)) {
354 if (off + len <= next->lr_offset)
355 break;
356 if (prev != NULL && prev->lr_offset + prev->lr_length <
357 next->lr_offset) {
358 /* there's a gap */
359 ASSERT3U(next->lr_offset, >,
360 prev->lr_offset + prev->lr_length);
361 zfs_rangelock_new_proxy(tree,
362 prev->lr_offset + prev->lr_length,
363 next->lr_offset -
364 (prev->lr_offset + prev->lr_length));
365 }
366 if (off + len == next->lr_offset + next->lr_length) {
367 /* exact overlap with end */
368 next = zfs_rangelock_proxify(tree, next);
369 next->lr_count++;
370 return;
371 }
372 if (off + len < next->lr_offset + next->lr_length) {
373 /* new range ends in the middle of this block */
374 next = zfs_rangelock_split(tree, next, off + len);
375 next->lr_count++;
376 return;
377 }
378 ASSERT3U(off + len, >, next->lr_offset + next->lr_length);
379 next = zfs_rangelock_proxify(tree, next);
380 next->lr_count++;
381 }
382
383 /* Add the remaining end range. */
384 zfs_rangelock_new_proxy(tree, prev->lr_offset + prev->lr_length,
385 (off + len) - (prev->lr_offset + prev->lr_length));
386 }
387
388 /*
389 * Check if a reader lock can be grabbed. If not, fail immediately or sleep and
390 * recheck until available, depending on the value of the "nonblock" parameter.
391 */
392 static boolean_t
zfs_rangelock_enter_reader(zfs_rangelock_t * rl,zfs_locked_range_t * new,boolean_t nonblock)393 zfs_rangelock_enter_reader(zfs_rangelock_t *rl, zfs_locked_range_t *new,
394 boolean_t nonblock)
395 {
396 avl_tree_t *tree = &rl->rl_tree;
397 zfs_locked_range_t *prev, *next;
398 avl_index_t where;
399 uint64_t off = new->lr_offset;
400 uint64_t len = new->lr_length;
401
402 /*
403 * Look for any writer locks in the range.
404 */
405 retry:
406 prev = avl_find(tree, new, &where);
407 if (prev == NULL)
408 prev = avl_nearest(tree, where, AVL_BEFORE);
409
410 /*
411 * Check the previous range for a writer lock overlap.
412 */
413 if (prev && (off < prev->lr_offset + prev->lr_length)) {
414 if ((prev->lr_type == RL_WRITER) || (prev->lr_write_wanted)) {
415 if (nonblock)
416 return (B_FALSE);
417 if (!prev->lr_read_wanted) {
418 cv_init(&prev->lr_read_cv,
419 NULL, CV_DEFAULT, NULL);
420 prev->lr_read_wanted = B_TRUE;
421 }
422 cv_wait(&prev->lr_read_cv, &rl->rl_lock);
423 goto retry;
424 }
425 if (off + len < prev->lr_offset + prev->lr_length)
426 goto got_lock;
427 }
428
429 /*
430 * Search through the following ranges to see if there's
431 * write lock any overlap.
432 */
433 if (prev != NULL)
434 next = AVL_NEXT(tree, prev);
435 else
436 next = avl_nearest(tree, where, AVL_AFTER);
437 for (; next != NULL; next = AVL_NEXT(tree, next)) {
438 if (off + len <= next->lr_offset)
439 goto got_lock;
440 if ((next->lr_type == RL_WRITER) || (next->lr_write_wanted)) {
441 if (nonblock)
442 return (B_FALSE);
443 if (!next->lr_read_wanted) {
444 cv_init(&next->lr_read_cv,
445 NULL, CV_DEFAULT, NULL);
446 next->lr_read_wanted = B_TRUE;
447 }
448 cv_wait(&next->lr_read_cv, &rl->rl_lock);
449 goto retry;
450 }
451 if (off + len <= next->lr_offset + next->lr_length)
452 goto got_lock;
453 }
454
455 got_lock:
456 /*
457 * Add the read lock, which may involve splitting existing
458 * locks and bumping ref counts (r_count).
459 */
460 zfs_rangelock_add_reader(tree, new, prev, where);
461 return (B_TRUE);
462 }
463
464 /*
465 * Lock a range (offset, length) as either shared (RL_READER) or exclusive
466 * (RL_WRITER or RL_APPEND). If RL_APPEND is specified, rl_cb() will convert
467 * it to a RL_WRITER lock (with the offset at the end of the file). Returns
468 * the range lock structure for later unlocking (or reduce range if the
469 * entire file is locked as RL_WRITER), or NULL if nonblock is true and the
470 * lock could not be acquired immediately.
471 */
472 static zfs_locked_range_t *
zfs_rangelock_enter_impl(zfs_rangelock_t * rl,uint64_t off,uint64_t len,zfs_rangelock_type_t type,boolean_t nonblock)473 zfs_rangelock_enter_impl(zfs_rangelock_t *rl, uint64_t off, uint64_t len,
474 zfs_rangelock_type_t type, boolean_t nonblock)
475 {
476 zfs_locked_range_t *new;
477
478 ASSERT(type == RL_READER || type == RL_WRITER || type == RL_APPEND);
479
480 new = kmem_alloc(sizeof (zfs_locked_range_t), KM_SLEEP);
481 new->lr_rangelock = rl;
482 new->lr_offset = off;
483 if (len + off < off) /* overflow */
484 len = UINT64_MAX - off;
485 new->lr_length = len;
486 new->lr_count = 1; /* assume it's going to be in the tree */
487 new->lr_type = type;
488 new->lr_proxy = B_FALSE;
489 new->lr_write_wanted = B_FALSE;
490 new->lr_read_wanted = B_FALSE;
491
492 mutex_enter(&rl->rl_lock);
493 if (type == RL_READER) {
494 /*
495 * First check for the usual case of no locks
496 */
497 if (avl_numnodes(&rl->rl_tree) == 0) {
498 avl_add(&rl->rl_tree, new);
499 } else if (!zfs_rangelock_enter_reader(rl, new, nonblock)) {
500 kmem_free(new, sizeof (*new));
501 new = NULL;
502 }
503 } else if (!zfs_rangelock_enter_writer(rl, new, nonblock)) {
504 kmem_free(new, sizeof (*new));
505 new = NULL;
506 }
507 mutex_exit(&rl->rl_lock);
508 return (new);
509 }
510
511 zfs_locked_range_t *
zfs_rangelock_enter(zfs_rangelock_t * rl,uint64_t off,uint64_t len,zfs_rangelock_type_t type)512 zfs_rangelock_enter(zfs_rangelock_t *rl, uint64_t off, uint64_t len,
513 zfs_rangelock_type_t type)
514 {
515 return (zfs_rangelock_enter_impl(rl, off, len, type, B_FALSE));
516 }
517
518 zfs_locked_range_t *
zfs_rangelock_tryenter(zfs_rangelock_t * rl,uint64_t off,uint64_t len,zfs_rangelock_type_t type)519 zfs_rangelock_tryenter(zfs_rangelock_t *rl, uint64_t off, uint64_t len,
520 zfs_rangelock_type_t type)
521 {
522 return (zfs_rangelock_enter_impl(rl, off, len, type, B_TRUE));
523 }
524
525 /*
526 * Safely free the zfs_locked_range_t.
527 */
528 static void
zfs_rangelock_free(zfs_locked_range_t * lr)529 zfs_rangelock_free(zfs_locked_range_t *lr)
530 {
531 if (lr->lr_write_wanted)
532 cv_destroy(&lr->lr_write_cv);
533
534 if (lr->lr_read_wanted)
535 cv_destroy(&lr->lr_read_cv);
536
537 kmem_free(lr, sizeof (zfs_locked_range_t));
538 }
539
540 /*
541 * Unlock a reader lock
542 */
543 static void
zfs_rangelock_exit_reader(zfs_rangelock_t * rl,zfs_locked_range_t * remove,list_t * free_list)544 zfs_rangelock_exit_reader(zfs_rangelock_t *rl, zfs_locked_range_t *remove,
545 list_t *free_list)
546 {
547 avl_tree_t *tree = &rl->rl_tree;
548 uint64_t len;
549
550 /*
551 * The common case is when the remove entry is in the tree
552 * (cnt == 1) meaning there's been no other reader locks overlapping
553 * with this one. Otherwise the remove entry will have been
554 * removed from the tree and replaced by proxies (one or
555 * more ranges mapping to the entire range).
556 */
557 if (remove->lr_count == 1) {
558 avl_remove(tree, remove);
559 if (remove->lr_write_wanted)
560 cv_broadcast(&remove->lr_write_cv);
561 if (remove->lr_read_wanted)
562 cv_broadcast(&remove->lr_read_cv);
563 list_insert_tail(free_list, remove);
564 } else {
565 ASSERT0(remove->lr_count);
566 ASSERT0(remove->lr_write_wanted);
567 ASSERT0(remove->lr_read_wanted);
568 /*
569 * Find start proxy representing this reader lock,
570 * then decrement ref count on all proxies
571 * that make up this range, freeing them as needed.
572 */
573 zfs_locked_range_t *lr = avl_find(tree, remove, NULL);
574 ASSERT3P(lr, !=, NULL);
575 ASSERT3U(lr->lr_count, !=, 0);
576 ASSERT3U(lr->lr_type, ==, RL_READER);
577 zfs_locked_range_t *next = NULL;
578 for (len = remove->lr_length; len != 0; lr = next) {
579 len -= lr->lr_length;
580 if (len != 0) {
581 next = AVL_NEXT(tree, lr);
582 ASSERT3P(next, !=, NULL);
583 ASSERT3U(lr->lr_offset + lr->lr_length, ==,
584 next->lr_offset);
585 ASSERT3U(next->lr_count, !=, 0);
586 ASSERT3U(next->lr_type, ==, RL_READER);
587 }
588 lr->lr_count--;
589 if (lr->lr_count == 0) {
590 avl_remove(tree, lr);
591 if (lr->lr_write_wanted)
592 cv_broadcast(&lr->lr_write_cv);
593 if (lr->lr_read_wanted)
594 cv_broadcast(&lr->lr_read_cv);
595 list_insert_tail(free_list, lr);
596 }
597 }
598 kmem_free(remove, sizeof (zfs_locked_range_t));
599 }
600 }
601
602 /*
603 * Unlock range and destroy range lock structure.
604 */
605 void
zfs_rangelock_exit(zfs_locked_range_t * lr)606 zfs_rangelock_exit(zfs_locked_range_t *lr)
607 {
608 zfs_rangelock_t *rl = lr->lr_rangelock;
609 list_t free_list;
610 zfs_locked_range_t *free_lr;
611
612 ASSERT(lr->lr_type == RL_WRITER || lr->lr_type == RL_READER);
613 ASSERT(lr->lr_count == 1 || lr->lr_count == 0);
614 ASSERT(!lr->lr_proxy);
615
616 /*
617 * The free list is used to defer the cv_destroy() and
618 * subsequent kmem_free until after the mutex is dropped.
619 */
620 list_create(&free_list, sizeof (zfs_locked_range_t),
621 offsetof(zfs_locked_range_t, lr_node));
622
623 mutex_enter(&rl->rl_lock);
624 if (lr->lr_type == RL_WRITER) {
625 /* writer locks can't be shared or split */
626 avl_remove(&rl->rl_tree, lr);
627 if (lr->lr_write_wanted)
628 cv_broadcast(&lr->lr_write_cv);
629 if (lr->lr_read_wanted)
630 cv_broadcast(&lr->lr_read_cv);
631 list_insert_tail(&free_list, lr);
632 } else {
633 /*
634 * lock may be shared, let rangelock_exit_reader()
635 * release the lock and free the zfs_locked_range_t.
636 */
637 zfs_rangelock_exit_reader(rl, lr, &free_list);
638 }
639 mutex_exit(&rl->rl_lock);
640
641 while ((free_lr = list_remove_head(&free_list)) != NULL)
642 zfs_rangelock_free(free_lr);
643
644 list_destroy(&free_list);
645 }
646
647 /*
648 * Reduce range locked as RL_WRITER from whole file to specified range.
649 * Asserts the whole file is exclusively locked and so there's only one
650 * entry in the tree.
651 */
652 void
zfs_rangelock_reduce(zfs_locked_range_t * lr,uint64_t off,uint64_t len)653 zfs_rangelock_reduce(zfs_locked_range_t *lr, uint64_t off, uint64_t len)
654 {
655 zfs_rangelock_t *rl = lr->lr_rangelock;
656
657 /* Ensure there are no other locks */
658 ASSERT3U(avl_numnodes(&rl->rl_tree), ==, 1);
659 ASSERT0(lr->lr_offset);
660 ASSERT3U(lr->lr_type, ==, RL_WRITER);
661 ASSERT(!lr->lr_proxy);
662 ASSERT3U(lr->lr_length, ==, UINT64_MAX);
663 ASSERT3U(lr->lr_count, ==, 1);
664
665 mutex_enter(&rl->rl_lock);
666 lr->lr_offset = off;
667 lr->lr_length = len;
668 mutex_exit(&rl->rl_lock);
669 if (lr->lr_write_wanted)
670 cv_broadcast(&lr->lr_write_cv);
671 if (lr->lr_read_wanted)
672 cv_broadcast(&lr->lr_read_cv);
673 }
674
675 #if defined(_KERNEL)
676 EXPORT_SYMBOL(zfs_rangelock_init);
677 EXPORT_SYMBOL(zfs_rangelock_fini);
678 EXPORT_SYMBOL(zfs_rangelock_enter);
679 EXPORT_SYMBOL(zfs_rangelock_tryenter);
680 EXPORT_SYMBOL(zfs_rangelock_exit);
681 EXPORT_SYMBOL(zfs_rangelock_reduce);
682 #endif
683