1b819ceaGordon Ross/*
2b819ceaGordon Ross * CDDL HEADER START
3b819ceaGordon Ross *
4b819ceaGordon Ross * The contents of this file are subject to the terms of the
5b819ceaGordon Ross * Common Development and Distribution License (the "License").
6b819ceaGordon Ross * You may not use this file except in compliance with the License.
7b819ceaGordon Ross *
8b819ceaGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9b819ceaGordon Ross * or http://www.opensolaris.org/os/licensing.
10b819ceaGordon Ross * See the License for the specific language governing permissions
11b819ceaGordon Ross * and limitations under the License.
12b819ceaGordon Ross *
13b819ceaGordon Ross * When distributing Covered Code, include this CDDL HEADER in each
14b819ceaGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15b819ceaGordon Ross * If applicable, add the following below this CDDL HEADER, with the
16b819ceaGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying
17b819ceaGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner]
18b819ceaGordon Ross *
19b819ceaGordon Ross * CDDL HEADER END
20b819ceaGordon Ross */
21b819ceaGordon Ross/*
22b819ceaGordon Ross * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23b819ceaGordon Ross * Use is subject to license terms.
24b819ceaGordon Ross *
25b819ceaGordon Ross * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
26b819ceaGordon Ross */
27b819ceaGordon Ross
28b819ceaGordon Ross/*
29b819ceaGordon Ross * Utility routines and top-level conflict detection code for NBMAND
30b819ceaGordon Ross * locks.
31b819ceaGordon Ross */
32b819ceaGordon Ross
33b819ceaGordon Ross#include <sys/types.h>
34b819ceaGordon Ross#include <sys/cmn_err.h>
35b819ceaGordon Ross#include <sys/debug.h>
36b819ceaGordon Ross#include <sys/fcntl.h>
37b819ceaGordon Ross#include <sys/rwlock.h>
38b819ceaGordon Ross#include <sys/vnode.h>
39b819ceaGordon Ross#include <sys/vfs.h>
40b819ceaGordon Ross#include <sys/nbmlock.h>
41b819ceaGordon Ross
42b819ceaGordon Ross/*
43b819ceaGordon Ross * Enter the critical region for synchronizing I/O requests with lock/share
44b819ceaGordon Ross * requests.  "mode" specifies whether the caller intends to update
45b819ceaGordon Ross * lock/share state (as opposed to just query it).
46b819ceaGordon Ross */
47b819ceaGordon Ross
48b819ceaGordon Rossvoid
49b819ceaGordon Rossnbl_start_crit(vnode_t *vp, krw_t mode)
50b819ceaGordon Ross{
51b819ceaGordon Ross	rw_enter(&vp->v_nbllock, mode);
52b819ceaGordon Ross}
53b819ceaGordon Ross
54b819ceaGordon Ross/*
55b819ceaGordon Ross * Leave the critical region.
56b819ceaGordon Ross */
57b819ceaGordon Ross
58b819ceaGordon Rossvoid
59b819ceaGordon Rossnbl_end_crit(vnode_t *vp)
60b819ceaGordon Ross{
61b819ceaGordon Ross	rw_exit(&vp->v_nbllock);
62b819ceaGordon Ross}
63b819ceaGordon Ross
64b819ceaGordon Ross/*
65b819ceaGordon Ross * Return non-zero if some thread is in the critical region.
66b819ceaGordon Ross * Note that this is appropriate for use in ASSERT()s only.
67b819ceaGordon Ross */
68b819ceaGordon Ross
69b819ceaGordon Rossint
70b819ceaGordon Rossnbl_in_crit(vnode_t *vp)
71b819ceaGordon Ross{
72b819ceaGordon Ross	return (RW_LOCK_HELD(&vp->v_nbllock));
73b819ceaGordon Ross}
74b819ceaGordon Ross
75b819ceaGordon Ross/*
76b819ceaGordon Ross * Returns non-zero if we need to look further for an NBMAND lock or
77b819ceaGordon Ross * share conflict.
78b819ceaGordon Ross */
79b819ceaGordon Ross/* ARGSUSED */
80b819ceaGordon Rossint
81b819ceaGordon Rossnbl_need_check(vnode_t *vp)
82b819ceaGordon Ross{
83b819ceaGordon Ross	/*
84b819ceaGordon Ross	 * Currently we only check if NBMAND locks/shares are allowed on
85b819ceaGordon Ross	 * the filesystem.  An option for the future would be to have a
86b819ceaGordon Ross	 * flag on the vnode, though the locking for that can get tricky.
87b819ceaGordon Ross	 */
88b819ceaGordon Ross	/* (vp->v_vfsp) && (vp->v_vfsp->vfs_flag & VFS_NBMAND)) */
89b819ceaGordon Ross	return (0);
90b819ceaGordon Ross}
91b819ceaGordon Ross
92b819ceaGordon Ross/*
93b819ceaGordon Ross * Top-level conflict detection routine.  The arguments describe the
94b819ceaGordon Ross * operation that is being attempted.  If the operation conflicts with an
95b819ceaGordon Ross * existing lock or share reservation, a non-zero value is returned.  If
96b819ceaGordon Ross * the operation is allowed, zero is returned.  Note that there is an
97b819ceaGordon Ross * implicit argument, which is the process ID of the requester.
98b819ceaGordon Ross *
99b819ceaGordon Ross * svmand indicates that the file has System V mandatory locking enabled,
100b819ceaGordon Ross * so we should look at all record locks, not just NBMAND record locks.
101b819ceaGordon Ross * (This is to avoid a deadlock between a process making an I/O request and
102b819ceaGordon Ross * a process trying to release a lock.  Instead of letting the first
103b819ceaGordon Ross * process block in the filesystem code, we flag a conflict here.)
104b819ceaGordon Ross */
105b819ceaGordon Ross
106b819ceaGordon Rossint
107b819ceaGordon Rossnbl_conflict(vnode_t *vp,
108b819ceaGordon Ross		nbl_op_t op,		/* attempted operation */
109b819ceaGordon Ross		u_offset_t offset,	/* ignore if not I/O */
110b819ceaGordon Ross		ssize_t length,		/* ignore if not I/O */
111b819ceaGordon Ross		int svmand,		/* System V mandatory locking */
112b819ceaGordon Ross		caller_context_t *ct)	/* caller context */
113b819ceaGordon Ross{
114b819ceaGordon Ross	ASSERT(nbl_in_crit(vp));
115b819ceaGordon Ross	ASSERT(op == NBL_READ || op == NBL_WRITE || op == NBL_RENAME ||
116b819ceaGordon Ross	    op == NBL_REMOVE || op == NBL_READWRITE);
117b819ceaGordon Ross
118b819ceaGordon Ross	if (nbl_share_conflict(vp, op, ct)) {
119b819ceaGordon Ross		return (1);
120b819ceaGordon Ross	}
121b819ceaGordon Ross
122b819ceaGordon Ross	/*
123b819ceaGordon Ross	 * If this is not an I/O request, there's no need to check against
124b819ceaGordon Ross	 * the locks on the file.
125b819ceaGordon Ross	 */
126b819ceaGordon Ross	if (op == NBL_REMOVE || op == NBL_RENAME)
127b819ceaGordon Ross		return (0);
128b819ceaGordon Ross
129b819ceaGordon Ross	return (nbl_lock_conflict(vp, op, offset, length, svmand, ct));
130b819ceaGordon Ross}
131b819ceaGordon Ross
132b819ceaGordon Ross/*
133b819ceaGordon Ross * Determine if the given file has mode bits for System V mandatory locks.
134b819ceaGordon Ross * If there was an error, the errno value is returned.  Otherwise, zero is
135b819ceaGordon Ross * returned and *svp is set appropriately (non-zero for mandatory locks,
136b819ceaGordon Ross * zero for no mandatory locks).
137b819ceaGordon Ross */
138b819ceaGordon Ross
139b819ceaGordon Rossint
140b819ceaGordon Rossnbl_svmand(vnode_t *vp, cred_t *cr, int *svp)
141b819ceaGordon Ross{
142b819ceaGordon Ross	struct vattr va;
143b819ceaGordon Ross	int error;
144b819ceaGordon Ross
145b819ceaGordon Ross	va.va_mask = AT_MODE;
146b819ceaGordon Ross	error = VOP_GETATTR(vp, &va, 0, cr, NULL);
147b819ceaGordon Ross	if (error != 0)
148b819ceaGordon Ross		return (error);
149b819ceaGordon Ross
150b819ceaGordon Ross	*svp = MANDLOCK(vp, va.va_mode);
151b819ceaGordon Ross	return (0);
152b819ceaGordon Ross}
153b819ceaGordon Ross
154b819ceaGordon Ross/*
155b819ceaGordon Ross * The kernel handles this for us when we actually try I/O.
156b819ceaGordon Ross */
157b819ceaGordon Ross/* ARGSUSED */
158b819ceaGordon Rossint
159b819ceaGordon Rossnbl_share_conflict(vnode_t *vp, nbl_op_t op, caller_context_t *ct)
160b819ceaGordon Ross{
161b819ceaGordon Ross	return (0);
162b819ceaGordon Ross}
163b819ceaGordon Ross
164b819ceaGordon Ross/*
165b819ceaGordon Ross * The kernel handles this for us when we actually try I/O.
166b819ceaGordon Ross */
167b819ceaGordon Ross/* ARGSUSED */
168b819ceaGordon Rossint
169b819ceaGordon Rossnbl_lock_conflict(vnode_t *vp, nbl_op_t op, u_offset_t offset,
170b819ceaGordon Ross		ssize_t length, int svmand, caller_context_t *ct)
171b819ceaGordon Ross{
172b819ceaGordon Ross	return (0);
173b819ceaGordon Ross}