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
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* 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));
}
/*
* 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 */
caller_context_t *ct) /* caller context */
{
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, ct)) {
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, ct));
}
/*
* 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, NULL);
if (error != 0)
return (error);
*svp = MANDLOCK(vp, va.va_mode);
return (0);
}
|