usr/src/uts/common/fs/zfs/rrwlock.c
author Chris Kirby <Chris.Kirby@oracle.com>
Thu, 10 Jun 2010 15:46:47 -0600
changeset 12605 6790e683d5a5
parent 9981 b4907297e740
child 13743 95aba6e49b9f
permissions -rw-r--r--
6959846 DMU traverse prefetch size should be a global tunable
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
/*
9981
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
    22
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
5326
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
#include <sys/refcount.h>
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    27
#include <sys/rrwlock.h>
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    28
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    29
/*
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    30
 * 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
    31
 * reader/writer lock (aka "rrwlock").
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    32
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    33
 * 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
    34
 * 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
    35
 * 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
    36
 * waiting writers.
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    37
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    38
 * 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
    39
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    40
 * 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
    41
 * 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
    42
 * 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
    43
 * 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
    44
 * vice versa).
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    45
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    46
 * 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
    47
 * 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
    48
 * 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
    49
 * 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
    50
 * 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
    51
 * 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
    52
 * 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
    53
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    54
 * 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
    55
 * 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
    56
 * 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
    57
 * 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
    58
 * 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
    59
 *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    60
 * 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
    61
 * 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
    62
 * 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
    63
 * 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
    64
 * 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
    65
 * 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
    66
 * 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
    67
 * 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
    68
 * waiting writers.  Hence, we do not starve writers.
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    69
 */
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    70
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    71
/* global key for TSD */
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    72
uint_t rrw_tsd_key;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    73
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    74
typedef struct rrw_node {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    75
	struct rrw_node	*rn_next;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    76
	rrwlock_t	*rn_rrl;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    77
} rrw_node_t;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    78
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    79
static rrw_node_t *
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    80
rrn_find(rrwlock_t *rrl)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    81
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    82
	rrw_node_t *rn;
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
	if (refcount_count(&rrl->rr_linked_rcount) == 0)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    85
		return (NULL);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    86
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    87
	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
    88
		if (rn->rn_rrl == rrl)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    89
			return (rn);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    90
	}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    91
	return (NULL);
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
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
 * 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
    96
 */
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    97
static void
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    98
rrn_add(rrwlock_t *rrl)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
    99
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   100
	rrw_node_t *rn;
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
	rn = kmem_alloc(sizeof (*rn), KM_SLEEP);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   103
	rn->rn_rrl = rrl;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   104
	rn->rn_next = tsd_get(rrw_tsd_key);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   105
	VERIFY(tsd_set(rrw_tsd_key, rn) == 0);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   106
}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   107
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
 * 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
   110
 * thread's list and return TRUE; otherwise return FALSE.
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   111
 */
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   112
static boolean_t
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   113
rrn_find_and_remove(rrwlock_t *rrl)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   114
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   115
	rrw_node_t *rn;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   116
	rrw_node_t *prev = NULL;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   117
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   118
	if (refcount_count(&rrl->rr_linked_rcount) == 0)
9981
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   119
		return (B_FALSE);
5326
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   120
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   121
	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
   122
		if (rn->rn_rrl == rrl) {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   123
			if (prev)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   124
				prev->rn_next = rn->rn_next;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   125
			else
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   126
				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
   127
			kmem_free(rn, sizeof (*rn));
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   128
			return (B_TRUE);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   129
		}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   130
		prev = rn;
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
	return (B_FALSE);
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
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   135
void
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   136
rrw_init(rrwlock_t *rrl)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   137
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   138
	mutex_init(&rrl->rr_lock, NULL, MUTEX_DEFAULT, NULL);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   139
	cv_init(&rrl->rr_cv, NULL, CV_DEFAULT, NULL);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   140
	rrl->rr_writer = NULL;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   141
	refcount_create(&rrl->rr_anon_rcount);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   142
	refcount_create(&rrl->rr_linked_rcount);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   143
	rrl->rr_writer_wanted = B_FALSE;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   144
}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   145
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   146
void
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   147
rrw_destroy(rrwlock_t *rrl)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   148
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   149
	mutex_destroy(&rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   150
	cv_destroy(&rrl->rr_cv);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   151
	ASSERT(rrl->rr_writer == NULL);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   152
	refcount_destroy(&rrl->rr_anon_rcount);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   153
	refcount_destroy(&rrl->rr_linked_rcount);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   154
}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   155
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   156
static void
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   157
rrw_enter_read(rrwlock_t *rrl, void *tag)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   158
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   159
	mutex_enter(&rrl->rr_lock);
9981
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   160
#if !defined(DEBUG) && defined(_KERNEL)
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   161
	if (!rrl->rr_writer && !rrl->rr_writer_wanted) {
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   162
		rrl->rr_anon_rcount.rc_count++;
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   163
		mutex_exit(&rrl->rr_lock);
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   164
		return;
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   165
	}
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   166
	DTRACE_PROBE(zfs__rrwfastpath__rdmiss);
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   167
#endif
5326
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   168
	ASSERT(rrl->rr_writer != curthread);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   169
	ASSERT(refcount_count(&rrl->rr_anon_rcount) >= 0);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   170
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   171
	while (rrl->rr_writer || (rrl->rr_writer_wanted &&
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   172
	    refcount_is_zero(&rrl->rr_anon_rcount) &&
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   173
	    rrn_find(rrl) == NULL))
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   174
		cv_wait(&rrl->rr_cv, &rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   175
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   176
	if (rrl->rr_writer_wanted) {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   177
		/* may or may not be a re-entrant enter */
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   178
		rrn_add(rrl);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   179
		(void) refcount_add(&rrl->rr_linked_rcount, tag);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   180
	} else {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   181
		(void) refcount_add(&rrl->rr_anon_rcount, tag);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   182
	}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   183
	ASSERT(rrl->rr_writer == NULL);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   184
	mutex_exit(&rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   185
}
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
static void
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   188
rrw_enter_write(rrwlock_t *rrl)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   189
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   190
	mutex_enter(&rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   191
	ASSERT(rrl->rr_writer != curthread);
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
	while (refcount_count(&rrl->rr_anon_rcount) > 0 ||
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   194
	    refcount_count(&rrl->rr_linked_rcount) > 0 ||
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   195
	    rrl->rr_writer != NULL) {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   196
		rrl->rr_writer_wanted = B_TRUE;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   197
		cv_wait(&rrl->rr_cv, &rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   198
	}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   199
	rrl->rr_writer_wanted = B_FALSE;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   200
	rrl->rr_writer = curthread;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   201
	mutex_exit(&rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   202
}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   203
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   204
void
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   205
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
   206
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   207
	if (rw == RW_READER)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   208
		rrw_enter_read(rrl, tag);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   209
	else
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   210
		rrw_enter_write(rrl);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   211
}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   212
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   213
void
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   214
rrw_exit(rrwlock_t *rrl, void *tag)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   215
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   216
	mutex_enter(&rrl->rr_lock);
9981
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   217
#if !defined(DEBUG) && defined(_KERNEL)
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   218
	if (!rrl->rr_writer && rrl->rr_linked_rcount.rc_count == 0) {
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   219
		rrl->rr_anon_rcount.rc_count--;
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   220
		if (rrl->rr_anon_rcount.rc_count == 0)
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   221
			cv_broadcast(&rrl->rr_cv);
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   222
		mutex_exit(&rrl->rr_lock);
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   223
		return;
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   224
	}
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   225
	DTRACE_PROBE(zfs__rrwfastpath__exitmiss);
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   226
#endif
5326
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   227
	ASSERT(!refcount_is_zero(&rrl->rr_anon_rcount) ||
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   228
	    !refcount_is_zero(&rrl->rr_linked_rcount) ||
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   229
	    rrl->rr_writer != NULL);
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
	if (rrl->rr_writer == NULL) {
9981
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   232
		int64_t count;
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   233
		if (rrn_find_and_remove(rrl))
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   234
			count = refcount_remove(&rrl->rr_linked_rcount, tag);
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   235
		else
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   236
			count = refcount_remove(&rrl->rr_anon_rcount, tag);
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   237
		if (count == 0)
b4907297e740 6775100 stat() performance on files on zfs should be improved
Tim Haley <Tim.Haley@Sun.COM>
parents: 5326
diff changeset
   238
			cv_broadcast(&rrl->rr_cv);
5326
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   239
	} else {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   240
		ASSERT(rrl->rr_writer == curthread);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   241
		ASSERT(refcount_is_zero(&rrl->rr_anon_rcount) &&
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   242
		    refcount_is_zero(&rrl->rr_linked_rcount));
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   243
		rrl->rr_writer = NULL;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   244
		cv_broadcast(&rrl->rr_cv);
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
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   249
boolean_t
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   250
rrw_held(rrwlock_t *rrl, krw_t rw)
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   251
{
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   252
	boolean_t held;
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   253
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   254
	mutex_enter(&rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   255
	if (rw == RW_WRITER) {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   256
		held = (rrl->rr_writer == curthread);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   257
	} else {
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   258
		held = (!refcount_is_zero(&rrl->rr_anon_rcount) ||
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   259
		    !refcount_is_zero(&rrl->rr_linked_rcount));
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   260
	}
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   261
	mutex_exit(&rrl->rr_lock);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   262
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   263
	return (held);
6752aa2bd5bc 6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
diff changeset
   264
}