7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * This file contains the code to implement file range locking in
28 * ZFS, although there isn't much specific to ZFS (all that comes to mind
29 * support for growing the blocksize).
30 *
31 * Interface
32 * ---------
33 * Defined in zfs_rlock.h but essentially:
34 * rl = zfs_range_lock(zp, off, len, lock_type);
35 * zfs_range_unlock(rl);
36 * zfs_range_reduce(rl, off, len);
37 *
38 * AVL tree
39 * --------
40 * An AVL tree is used to maintain the state of the existing ranges
41 * that are locked for exclusive (writer) or shared (reader) use.
42 * The starting range offset is used for searching and sorting the tree.
43 *
44 * Common case
45 * -----------
46 * The (hopefully) usual case is of no overlaps or contention for
464 uint64_t len;
465
466 /*
467 * The common case is when the remove entry is in the tree
468 * (cnt == 1) meaning there's been no other reader locks overlapping
469 * with this one. Otherwise the remove entry will have been
470 * removed from the tree and replaced by proxies (one or
471 * more ranges mapping to the entire range).
472 */
473 if (remove->r_cnt == 1) {
474 avl_remove(tree, remove);
475 if (remove->r_write_wanted) {
476 cv_broadcast(&remove->r_wr_cv);
477 cv_destroy(&remove->r_wr_cv);
478 }
479 if (remove->r_read_wanted) {
480 cv_broadcast(&remove->r_rd_cv);
481 cv_destroy(&remove->r_rd_cv);
482 }
483 } else {
484 ASSERT3U(remove->r_cnt, ==, 0);
485 ASSERT3U(remove->r_write_wanted, ==, 0);
486 ASSERT3U(remove->r_read_wanted, ==, 0);
487 /*
488 * Find start proxy representing this reader lock,
489 * then decrement ref count on all proxies
490 * that make up this range, freeing them as needed.
491 */
492 rl = avl_find(tree, remove, NULL);
493 ASSERT(rl);
494 ASSERT(rl->r_cnt);
495 ASSERT(rl->r_type == RL_READER);
496 for (len = remove->r_len; len != 0; rl = next) {
497 len -= rl->r_len;
498 if (len) {
499 next = AVL_NEXT(tree, rl);
500 ASSERT(next);
501 ASSERT(rl->r_off + rl->r_len == next->r_off);
502 ASSERT(next->r_cnt);
503 ASSERT(next->r_type == RL_READER);
504 }
505 rl->r_cnt--;
506 if (rl->r_cnt == 0) {
|
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Copyright (c) 2012 by Delphix. All rights reserved.
28 */
29
30
31
32 /*
33 * This file contains the code to implement file range locking in
34 * ZFS, although there isn't much specific to ZFS (all that comes to mind
35 * support for growing the blocksize).
36 *
37 * Interface
38 * ---------
39 * Defined in zfs_rlock.h but essentially:
40 * rl = zfs_range_lock(zp, off, len, lock_type);
41 * zfs_range_unlock(rl);
42 * zfs_range_reduce(rl, off, len);
43 *
44 * AVL tree
45 * --------
46 * An AVL tree is used to maintain the state of the existing ranges
47 * that are locked for exclusive (writer) or shared (reader) use.
48 * The starting range offset is used for searching and sorting the tree.
49 *
50 * Common case
51 * -----------
52 * The (hopefully) usual case is of no overlaps or contention for
470 uint64_t len;
471
472 /*
473 * The common case is when the remove entry is in the tree
474 * (cnt == 1) meaning there's been no other reader locks overlapping
475 * with this one. Otherwise the remove entry will have been
476 * removed from the tree and replaced by proxies (one or
477 * more ranges mapping to the entire range).
478 */
479 if (remove->r_cnt == 1) {
480 avl_remove(tree, remove);
481 if (remove->r_write_wanted) {
482 cv_broadcast(&remove->r_wr_cv);
483 cv_destroy(&remove->r_wr_cv);
484 }
485 if (remove->r_read_wanted) {
486 cv_broadcast(&remove->r_rd_cv);
487 cv_destroy(&remove->r_rd_cv);
488 }
489 } else {
490 ASSERT0(remove->r_cnt);
491 ASSERT0(remove->r_write_wanted);
492 ASSERT0(remove->r_read_wanted);
493 /*
494 * Find start proxy representing this reader lock,
495 * then decrement ref count on all proxies
496 * that make up this range, freeing them as needed.
497 */
498 rl = avl_find(tree, remove, NULL);
499 ASSERT(rl);
500 ASSERT(rl->r_cnt);
501 ASSERT(rl->r_type == RL_READER);
502 for (len = remove->r_len; len != 0; rl = next) {
503 len -= rl->r_len;
504 if (len) {
505 next = AVL_NEXT(tree, rl);
506 ASSERT(next);
507 ASSERT(rl->r_off + rl->r_len == next->r_off);
508 ASSERT(next->r_cnt);
509 ASSERT(next->r_type == RL_READER);
510 }
511 rl->r_cnt--;
512 if (rl->r_cnt == 0) {
|