summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs/nbmlock.c
blob: bb9dd887229e0a5675c1ea5d1bee96b3def716c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2001 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

/*
 * Utility routines and top-level conflict detection code for NBMAND
 * locks.
 */

#include <sys/nbmlock.h>
#include <sys/rwlock.h>
#include <sys/vnode.h>
#include <sys/cmn_err.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/vfs.h>

/*
 * Enter the critical region for synchronizing I/O requests with lock/share
 * requests.  "mode" specifies whether the caller intends to update
 * lock/share state (as opposed to just query it).
 */

void
nbl_start_crit(vnode_t *vp, krw_t mode)
{
	rw_enter(&vp->v_nbllock, mode);
}

/*
 * Leave the critical region.
 */

void
nbl_end_crit(vnode_t *vp)
{
	rw_exit(&vp->v_nbllock);
}

/*
 * Return non-zero if some thread is in the critical region.
 * Note that this is appropriate for use in ASSERT()s only.
 */

int
nbl_in_crit(vnode_t *vp)
{
	return (RW_LOCK_HELD(&vp->v_nbllock));
}

/*
 * Return the nbl_op_t that corresponds to the given lock type (read or
 * write).
 */

nbl_op_t
nbl_lock_to_op(int lock_type)
{
	int level;

	switch (lock_type) {
	case F_WRLCK:
		return (NBL_READWRITE);
	case F_RDLCK:
		return (NBL_READ);
	default:
#ifdef DEBUG
		level = CE_PANIC;
#else
		level = CE_WARN;
#endif
		cmn_err(level, "unexpected lock type: %d\n", lock_type);
		return (NBL_WRITE);	/* pick something restrictive */
	}
	/*NOTREACHED*/
}

/*
 * Returns non-zero if we need to look further for an NBMAND lock or
 * share conflict.
 */
int
nbl_need_check(vnode_t *vp)
{
	/*
	 * Currently we only check if NBMAND locks/shares are allowed on
	 * the filesystem.  An option for the future would be to have a
	 * flag on the vnode, though the locking for that can get tricky.
	 */
	return ((vp->v_vfsp) && (vp->v_vfsp->vfs_flag & VFS_NBMAND));
}

/*
 * Top-level conflict detection routine.  The arguments describe the
 * operation that is being attempted.  If the operation conflicts with an
 * existing lock or share reservation, a non-zero value is returned.  If
 * the operation is allowed, zero is returned.  Note that there is an
 * implicit argument, which is the process ID of the requester.
 *
 * svmand indicates that the file has System V mandatory locking enabled,
 * so we should look at all record locks, not just NBMAND record locks.
 * (This is to avoid a deadlock between a process making an I/O request and
 * a process trying to release a lock.  Instead of letting the first
 * process block in the filesystem code, we flag a conflict here.)
 */

int
nbl_conflict(vnode_t *vp,
		nbl_op_t op,		/* attempted operation */
		u_offset_t offset,	/* ignore if not I/O */
		ssize_t length,		/* ignore if not I/O */
		int svmand)		/* System V mandatory locking */
{
	ASSERT(nbl_in_crit(vp));
	ASSERT(op == NBL_READ || op == NBL_WRITE || op == NBL_RENAME ||
	    op == NBL_REMOVE || op == NBL_READWRITE);

	if (nbl_share_conflict(vp, op)) {
		return (1);
	}

	/*
	 * If this is not an I/O request, there's no need to check against
	 * the locks on the file.
	 */
	if (op == NBL_REMOVE || op == NBL_RENAME)
		return (0);

	return (nbl_lock_conflict(vp, op, offset, length, svmand));
}

/*
 * Determine if the given file has mode bits for System V mandatory locks.
 * If there was an error, the errno value is returned.  Otherwise, zero is
 * returned and *svp is set appropriately (non-zero for mandatory locks,
 * zero for no mandatory locks).
 */

int
nbl_svmand(vnode_t *vp, cred_t *cr, int *svp)
{
	struct vattr va;
	int error;

	va.va_mask = AT_MODE;
	error = VOP_GETATTR(vp, &va, 0, cr);
	if (error != 0)
		return (error);

	*svp = MANDLOCK(vp, va.va_mode);
	return (0);
}