usr/src/uts/common/fs/zfs/rrwlock.c
author ck153898
Mon, 29 Oct 2007 22:45:33 -0700
changeset 5378 111aa1baa84a
parent 5326 6752aa2bd5bc
child 9981 b4907297e740
permissions -rw-r--r--
PSARC 2007/555 zfs fs-only quotas and reservations 6431277 want filesystem-only quotas 6483677 need immediate reservation
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
5326
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
     1
/*
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
     2
 * CDDL HEADER START
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
     3
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
     4
 * The contents of this file are subject to the terms of the
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
     5
 * Common Development and Distribution License (the "License").
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
     6
 * You may not use this file except in compliance with the License.
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
     7
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
     8
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
     9
 * or http://www.opensolaris.org/os/licensing.
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    10
 * See the License for the specific language governing permissions
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    11
 * and limitations under the License.
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    12
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    13
 * When distributing Covered Code, include this CDDL HEADER in each
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    14
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    15
 * If applicable, add the following below this CDDL HEADER, with the
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    16
 * fields enclosed by brackets "[]" replaced with your own identifying
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    17
 * information: Portions Copyright [yyyy] [name of copyright owner]
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    18
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    19
 * CDDL HEADER END
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    20
 */
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    21
/*
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    22
 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    23
 * Use is subject to license terms.
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    24
 */
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    25
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    26
#pragma ident	"%Z%%M%	%I%	%E% SMI"
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    27
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    28
#include <sys/refcount.h>
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    29
#include <sys/rrwlock.h>
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    30
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    31
/*
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    32
 * This file contains the implementation of a re-entrant read
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    33
 * reader/writer lock (aka "rrwlock").
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    34
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    35
 * This is a normal reader/writer lock with the additional feature
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    36
 * of allowing threads who have already obtained a read lock to
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    37
 * re-enter another read lock (re-entrant read) - even if there are
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    38
 * waiting writers.
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    39
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    40
 * Callers who have not obtained a read lock give waiting writers priority.
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    41
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    42
 * The rrwlock_t lock does not allow re-entrant writers, nor does it
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    43
 * allow a re-entrant mix of reads and writes (that is, it does not
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    44
 * allow a caller who has already obtained a read lock to be able to
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    45
 * then grab a write lock without first dropping all read locks, and
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    46
 * vice versa).
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    47
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    48
 * The rrwlock_t uses tsd (thread specific data) to keep a list of
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    49
 * nodes (rrw_node_t), where each node keeps track of which specific
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    50
 * lock (rrw_node_t::rn_rrl) the thread has grabbed.  Since re-entering
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    51
 * should be rare, a thread that grabs multiple reads on the same rrwlock_t
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    52
 * will store multiple rrw_node_ts of the same 'rrn_rrl'. Nodes on the
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    53
 * tsd list can represent a different rrwlock_t.  This allows a thread
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    54
 * to enter multiple and unique rrwlock_ts for read locks at the same time.
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    55
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    56
 * Since using tsd exposes some overhead, the rrwlock_t only needs to
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    57
 * keep tsd data when writers are waiting.  If no writers are waiting, then
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    58
 * a reader just bumps the anonymous read count (rr_anon_rcount) - no tsd
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    59
 * is needed.  Once a writer attempts to grab the lock, readers then
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    60
 * keep tsd data and bump the linked readers count (rr_linked_rcount).
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    61
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    62
 * If there are waiting writers and there are anonymous readers, then a
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    63
 * reader doesn't know if it is a re-entrant lock. But since it may be one,
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    64
 * we allow the read to proceed (otherwise it could deadlock).  Since once
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    65
 * waiting writers are active, readers no longer bump the anonymous count,
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    66
 * the anonymous readers will eventually flush themselves out.  At this point,
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    67
 * readers will be able to tell if they are a re-entrant lock (have a
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    68
 * rrw_node_t entry for the lock) or not. If they are a re-entrant lock, then
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    69
 * we must let the proceed.  If they are not, then the reader blocks for the
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    70
 * waiting writers.  Hence, we do not starve writers.
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    71
 */
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    72
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    73
/* global key for TSD */
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    74
uint_t rrw_tsd_key;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    75
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    76
typedef struct rrw_node {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    77
	struct rrw_node	*rn_next;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    78
	rrwlock_t	*rn_rrl;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    79
} rrw_node_t;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    80
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    81
static rrw_node_t *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    82
rrn_find(rrwlock_t *rrl)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    83
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    84
	rrw_node_t *rn;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    85
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    86
	if (refcount_count(&rrl->rr_linked_rcount) == 0)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    87
		return (NULL);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    88
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    89
	for (rn = tsd_get(rrw_tsd_key); rn != NULL; rn = rn->rn_next) {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    90
		if (rn->rn_rrl == rrl)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    91
			return (rn);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    92
	}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    93
	return (NULL);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    94
}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    95
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    96
/*
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    97
 * Add a node to the head of the singly linked list.
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    98
 */
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    99
static void
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   100
rrn_add(rrwlock_t *rrl)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   101
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   102
	rrw_node_t *rn;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   103
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   104
	rn = kmem_alloc(sizeof (*rn), KM_SLEEP);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   105
	rn->rn_rrl = rrl;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   106
	rn->rn_next = tsd_get(rrw_tsd_key);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   107
	VERIFY(tsd_set(rrw_tsd_key, rn) == 0);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   108
}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   109
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   110
/*
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   111
 * If a node is found for 'rrl', then remove the node from this
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   112
 * thread's list and return TRUE; otherwise return FALSE.
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   113
 */
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   114
static boolean_t
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   115
rrn_find_and_remove(rrwlock_t *rrl)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   116
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   117
	rrw_node_t *rn;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   118
	rrw_node_t *prev = NULL;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   119
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   120
	if (refcount_count(&rrl->rr_linked_rcount) == 0)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   121
		return (NULL);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   122
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   123
	for (rn = tsd_get(rrw_tsd_key); rn != NULL; rn = rn->rn_next) {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   124
		if (rn->rn_rrl == rrl) {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   125
			if (prev)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   126
				prev->rn_next = rn->rn_next;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   127
			else
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   128
				VERIFY(tsd_set(rrw_tsd_key, rn->rn_next) == 0);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   129
			kmem_free(rn, sizeof (*rn));
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   130
			return (B_TRUE);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   131
		}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   132
		prev = rn;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   133
	}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   134
	return (B_FALSE);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   135
}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   136
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   137
void
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   138
rrw_init(rrwlock_t *rrl)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   139
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   140
	mutex_init(&rrl->rr_lock, NULL, MUTEX_DEFAULT, NULL);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   141
	cv_init(&rrl->rr_cv, NULL, CV_DEFAULT, NULL);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   142
	rrl->rr_writer = NULL;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   143
	refcount_create(&rrl->rr_anon_rcount);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   144
	refcount_create(&rrl->rr_linked_rcount);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   145
	rrl->rr_writer_wanted = B_FALSE;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   146
}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   147
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   148
void
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   149
rrw_destroy(rrwlock_t *rrl)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   150
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   151
	mutex_destroy(&rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   152
	cv_destroy(&rrl->rr_cv);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   153
	ASSERT(rrl->rr_writer == NULL);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   154
	refcount_destroy(&rrl->rr_anon_rcount);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   155
	refcount_destroy(&rrl->rr_linked_rcount);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   156
}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   157
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   158
static void
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   159
rrw_enter_read(rrwlock_t *rrl, void *tag)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   160
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   161
	mutex_enter(&rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   162
	ASSERT(rrl->rr_writer != curthread);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   163
	ASSERT(refcount_count(&rrl->rr_anon_rcount) >= 0);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   164
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   165
	while (rrl->rr_writer || (rrl->rr_writer_wanted &&
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   166
	    refcount_is_zero(&rrl->rr_anon_rcount) &&
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   167
	    rrn_find(rrl) == NULL))
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   168
		cv_wait(&rrl->rr_cv, &rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   169
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   170
	if (rrl->rr_writer_wanted) {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   171
		/* may or may not be a re-entrant enter */
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   172
		rrn_add(rrl);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   173
		(void) refcount_add(&rrl->rr_linked_rcount, tag);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   174
	} else {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   175
		(void) refcount_add(&rrl->rr_anon_rcount, tag);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   176
	}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   177
	ASSERT(rrl->rr_writer == NULL);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   178
	mutex_exit(&rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   179
}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   180
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   181
static void
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   182
rrw_enter_write(rrwlock_t *rrl)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   183
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   184
	mutex_enter(&rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   185
	ASSERT(rrl->rr_writer != curthread);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   186
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   187
	while (refcount_count(&rrl->rr_anon_rcount) > 0 ||
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   188
	    refcount_count(&rrl->rr_linked_rcount) > 0 ||
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   189
	    rrl->rr_writer != NULL) {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   190
		rrl->rr_writer_wanted = B_TRUE;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   191
		cv_wait(&rrl->rr_cv, &rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   192
	}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   193
	rrl->rr_writer_wanted = B_FALSE;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   194
	rrl->rr_writer = curthread;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   195
	mutex_exit(&rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   196
}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   197
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   198
void
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   199
rrw_enter(rrwlock_t *rrl, krw_t rw, void *tag)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   200
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   201
	if (rw == RW_READER)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   202
		rrw_enter_read(rrl, tag);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   203
	else
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   204
		rrw_enter_write(rrl);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   205
}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   206
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   207
void
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   208
rrw_exit(rrwlock_t *rrl, void *tag)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   209
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   210
	mutex_enter(&rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   211
	ASSERT(!refcount_is_zero(&rrl->rr_anon_rcount) ||
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   212
	    !refcount_is_zero(&rrl->rr_linked_rcount) ||
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   213
	    rrl->rr_writer != NULL);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   214
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   215
	if (rrl->rr_writer == NULL) {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   216
		if (rrn_find_and_remove(rrl)) {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   217
			if (refcount_remove(&rrl->rr_linked_rcount, tag) == 0)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   218
				cv_broadcast(&rrl->rr_cv);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   219
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   220
		} else {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   221
			if (refcount_remove(&rrl->rr_anon_rcount, tag) == 0)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   222
				cv_broadcast(&rrl->rr_cv);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   223
		}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   224
	} else {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   225
		ASSERT(rrl->rr_writer == curthread);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   226
		ASSERT(refcount_is_zero(&rrl->rr_anon_rcount) &&
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   227
		    refcount_is_zero(&rrl->rr_linked_rcount));
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   228
		rrl->rr_writer = NULL;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   229
		cv_broadcast(&rrl->rr_cv);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   230
	}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   231
	mutex_exit(&rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   232
}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   233
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   234
boolean_t
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   235
rrw_held(rrwlock_t *rrl, krw_t rw)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   236
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   237
	boolean_t held;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   238
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   239
	mutex_enter(&rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   240
	if (rw == RW_WRITER) {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   241
		held = (rrl->rr_writer == curthread);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   242
	} else {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   243
		held = (!refcount_is_zero(&rrl->rr_anon_rcount) ||
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   244
		    !refcount_is_zero(&rrl->rr_linked_rcount));
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   245
	}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   246
	mutex_exit(&rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   247
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   248
	return (held);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   249
}