xref: /titanic_51/usr/src/uts/common/fs/smbsrv/smb_oplock.c (revision a90cf9f29973990687fa61de9f1f6ea22e924e40)
18c10a865Sas200622 /*
28c10a865Sas200622  * CDDL HEADER START
38c10a865Sas200622  *
48c10a865Sas200622  * The contents of this file are subject to the terms of the
58c10a865Sas200622  * Common Development and Distribution License (the "License").
68c10a865Sas200622  * You may not use this file except in compliance with the License.
78c10a865Sas200622  *
88c10a865Sas200622  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98c10a865Sas200622  * or http://www.opensolaris.org/os/licensing.
108c10a865Sas200622  * See the License for the specific language governing permissions
118c10a865Sas200622  * and limitations under the License.
128c10a865Sas200622  *
138c10a865Sas200622  * When distributing Covered Code, include this CDDL HEADER in each
148c10a865Sas200622  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158c10a865Sas200622  * If applicable, add the following below this CDDL HEADER, with the
168c10a865Sas200622  * fields enclosed by brackets "[]" replaced with your own identifying
178c10a865Sas200622  * information: Portions Copyright [yyyy] [name of copyright owner]
188c10a865Sas200622  *
198c10a865Sas200622  * CDDL HEADER END
208c10a865Sas200622  */
218c10a865Sas200622 /*
22148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23*a90cf9f2SGordon Ross  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
248c10a865Sas200622  */
25cb174861Sjoyce mcintosh 
268c10a865Sas200622 /*
27cb174861Sjoyce mcintosh  * smb_oplock_wait / smb_oplock_broadcast
28cb174861Sjoyce mcintosh  * When an oplock is being acquired, we must ensure that the acquisition
29cb174861Sjoyce mcintosh  * response is submitted to the network stack before any other operation
30cb174861Sjoyce mcintosh  * is permitted on the oplock.
31cb174861Sjoyce mcintosh  * In smb_oplock_acquire, oplock.ol_xthread is set to point to the worker
32cb174861Sjoyce mcintosh  * thread processing the command that is granting the oplock.
33cb174861Sjoyce mcintosh  * Other threads accessing the oplock will be suspended in smb_oplock_wait().
34cb174861Sjoyce mcintosh  * They will be awakened when the worker thread referenced in 'ol_xthread'
35cb174861Sjoyce mcintosh  * calls smb_oplock_broadcast().
368b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  *
37cb174861Sjoyce mcintosh  * The purpose of this mechanism is to prevent another thread from
38cb174861Sjoyce mcintosh  * triggering an oplock break before the response conveying the grant
39cb174861Sjoyce mcintosh  * has been sent.
408c10a865Sas200622  */
418c10a865Sas200622 
42bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
43cb174861Sjoyce mcintosh #include <sys/nbmlock.h>
448c10a865Sas200622 
45cb174861Sjoyce mcintosh #define	SMB_OPLOCK_IS_EXCLUSIVE(level)		\
46cb174861Sjoyce mcintosh 	(((level) == SMB_OPLOCK_EXCLUSIVE) ||	\
47cb174861Sjoyce mcintosh 	((level) == SMB_OPLOCK_BATCH))
48cb174861Sjoyce mcintosh 
49cb174861Sjoyce mcintosh static int smb_oplock_install_fem(smb_node_t *);
50cb174861Sjoyce mcintosh static void smb_oplock_uninstall_fem(smb_node_t *);
51cb174861Sjoyce mcintosh 
52fc724630SAlan Wright static void smb_oplock_wait(smb_node_t *);
53cb174861Sjoyce mcintosh static void smb_oplock_wait_ack(smb_node_t *, uint32_t);
54cb174861Sjoyce mcintosh static void smb_oplock_timedout(smb_node_t *);
55cb174861Sjoyce mcintosh 
561fdeec65Sjoyce mcintosh static smb_oplock_grant_t *smb_oplock_set_grant(smb_ofile_t *, uint8_t);
571fdeec65Sjoyce mcintosh void smb_oplock_clear_grant(smb_oplock_grant_t *);
58cb174861Sjoyce mcintosh static int smb_oplock_insert_grant(smb_node_t *, smb_oplock_grant_t *);
59cb174861Sjoyce mcintosh static void smb_oplock_remove_grant(smb_node_t *, smb_oplock_grant_t *);
60cb174861Sjoyce mcintosh static smb_oplock_grant_t *smb_oplock_exclusive_grant(list_t *);
611fdeec65Sjoyce mcintosh static smb_oplock_grant_t *smb_oplock_get_grant(smb_oplock_t *, smb_ofile_t *);
62cb174861Sjoyce mcintosh 
63*a90cf9f2SGordon Ross static void smb_oplock_sched_async_break(smb_oplock_grant_t *, uint8_t);
64*a90cf9f2SGordon Ross static void smb_oplock_exec_async_break(void *);
65*a90cf9f2SGordon Ross static void smb_oplock_break_levelII_locked(smb_node_t *);
66cb174861Sjoyce mcintosh 
67cb174861Sjoyce mcintosh /*
68cb174861Sjoyce mcintosh  * smb_oplock_install_fem
69cb174861Sjoyce mcintosh  * Install fem monitor for cross protocol oplock breaking.
70cb174861Sjoyce mcintosh  */
71cb174861Sjoyce mcintosh static int
72cb174861Sjoyce mcintosh smb_oplock_install_fem(smb_node_t *node)
73cb174861Sjoyce mcintosh {
74cb174861Sjoyce mcintosh 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
75cb174861Sjoyce mcintosh 
76cb174861Sjoyce mcintosh 	if (node->n_oplock.ol_fem == B_FALSE) {
77cb174861Sjoyce mcintosh 		if (smb_fem_oplock_install(node) != 0) {
78cb174861Sjoyce mcintosh 			cmn_err(CE_NOTE, "No oplock granted: "
79cb174861Sjoyce mcintosh 			    "failed to install fem monitor %s",
80cb174861Sjoyce mcintosh 			    node->vp->v_path);
81cb174861Sjoyce mcintosh 			return (-1);
82cb174861Sjoyce mcintosh 		}
83cb174861Sjoyce mcintosh 		node->n_oplock.ol_fem = B_TRUE;
84cb174861Sjoyce mcintosh 	}
85cb174861Sjoyce mcintosh 	return (0);
86cb174861Sjoyce mcintosh }
87cb174861Sjoyce mcintosh 
88cb174861Sjoyce mcintosh /*
89cb174861Sjoyce mcintosh  * smb_oplock_uninstall_fem
90cb174861Sjoyce mcintosh  * Uninstall fem monitor for cross protocol oplock breaking.
91cb174861Sjoyce mcintosh  */
92cb174861Sjoyce mcintosh static void
93cb174861Sjoyce mcintosh smb_oplock_uninstall_fem(smb_node_t *node)
94cb174861Sjoyce mcintosh {
95cb174861Sjoyce mcintosh 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
96cb174861Sjoyce mcintosh 
97cb174861Sjoyce mcintosh 	if (node->n_oplock.ol_fem) {
988622ec45SGordon Ross 		smb_fem_oplock_uninstall(node);
99cb174861Sjoyce mcintosh 		node->n_oplock.ol_fem = B_FALSE;
100cb174861Sjoyce mcintosh 	}
101cb174861Sjoyce mcintosh }
1028c10a865Sas200622 
1038c10a865Sas200622 /*
104*a90cf9f2SGordon Ross  * This provides a way to fully disable oplocks, i.e. for testing.
105*a90cf9f2SGordon Ross  * You _really_ do _not_ want to turn this off, because if you do,
106*a90cf9f2SGordon Ross  * the clients send you very small read requests, and a _lot_ more
107*a90cf9f2SGordon Ross  * of them.  The skc_oplock_enable parameter can be used to enable
108*a90cf9f2SGordon Ross  * or disable exclusive oplocks.  Disabling that can be helpful
109*a90cf9f2SGordon Ross  * when there are clients not responding to oplock breaks.
110*a90cf9f2SGordon Ross  */
111*a90cf9f2SGordon Ross int smb_oplocks_enabled = 1;
112*a90cf9f2SGordon Ross 
113*a90cf9f2SGordon Ross /*
1148c10a865Sas200622  * smb_oplock_acquire
1158c10a865Sas200622  *
116cb174861Sjoyce mcintosh  * Attempt to acquire an oplock. Clients will request EXCLUSIVE or BATCH,
117cb174861Sjoyce mcintosh  * but might only be granted LEVEL_II or NONE.
1188c10a865Sas200622  *
119cb174861Sjoyce mcintosh  * If oplocks are not supported on the tree, or node, grant NONE.
120cb174861Sjoyce mcintosh  * If nobody else has the file open, grant the requested level.
121cb174861Sjoyce mcintosh  * If any of the following are true, grant NONE:
122cb174861Sjoyce mcintosh  * - there is an exclusive oplock on the node
123cb174861Sjoyce mcintosh  * - op->op_oplock_levelII is B_FALSE (LEVEL_II not supported by open cmd.
124cb174861Sjoyce mcintosh  * - LEVEL_II oplocks are not supported for the session
125cb174861Sjoyce mcintosh  * - a BATCH oplock is requested on a named stream
126bc7c423fSGordon Ross  * - there are any range locks on the node (SMB writers)
127cb174861Sjoyce mcintosh  * Otherwise, grant LEVEL_II.
1288c10a865Sas200622  *
129cb174861Sjoyce mcintosh  * ol->ol_xthread is set to the current thread to lock the oplock against
130cb174861Sjoyce mcintosh  * other operations until the acquire response is on the wire. When the
131cb174861Sjoyce mcintosh  * acquire response is on the wire, smb_oplock_broadcast() is called to
132cb174861Sjoyce mcintosh  * reset ol->ol_xthread and wake any waiting threads.
1338c10a865Sas200622  */
1342c2961f8Sjose borrego void
135cb174861Sjoyce mcintosh smb_oplock_acquire(smb_request_t *sr, smb_node_t *node, smb_ofile_t *ofile)
1368c10a865Sas200622 {
1372c2961f8Sjose borrego 	smb_oplock_t		*ol;
138cb174861Sjoyce mcintosh 	smb_oplock_grant_t	*og;
139cb174861Sjoyce mcintosh 	list_t			*grants;
140cb174861Sjoyce mcintosh 	smb_arg_open_t		*op;
141cb174861Sjoyce mcintosh 	smb_tree_t		*tree;
142cb174861Sjoyce mcintosh 	smb_session_t		*session;
1438c10a865Sas200622 
1442c2961f8Sjose borrego 	SMB_NODE_VALID(node);
145cb174861Sjoyce mcintosh 	SMB_OFILE_VALID(ofile);
1468c10a865Sas200622 
147cb174861Sjoyce mcintosh 	ASSERT(node == SMB_OFILE_GET_NODE(ofile));
148bc7c423fSGordon Ross 	ASSERT(RW_LOCK_HELD(&node->n_lock));
1498c10a865Sas200622 
150cb174861Sjoyce mcintosh 	op = &sr->sr_open;
151cb174861Sjoyce mcintosh 	tree = SMB_OFILE_GET_TREE(ofile);
152cb174861Sjoyce mcintosh 	session = SMB_OFILE_GET_SESSION(ofile);
1538c10a865Sas200622 
154*a90cf9f2SGordon Ross 	if (smb_oplocks_enabled == 0 ||
155cb174861Sjoyce mcintosh 	    (op->op_oplock_level == SMB_OPLOCK_NONE) ||
156cb174861Sjoyce mcintosh 	    ((op->op_oplock_level == SMB_OPLOCK_BATCH) &&
157cb174861Sjoyce mcintosh 	    SMB_IS_STREAM(node))) {
1582c2961f8Sjose borrego 		op->op_oplock_level = SMB_OPLOCK_NONE;
1592c2961f8Sjose borrego 		return;
1608c10a865Sas200622 	}
1618c10a865Sas200622 
1622c2961f8Sjose borrego 	ol = &node->n_oplock;
163cb174861Sjoyce mcintosh 	grants = &ol->ol_grants;
1648c10a865Sas200622 
165cb174861Sjoyce mcintosh 	mutex_enter(&ol->ol_mutex);
166fc724630SAlan Wright 	smb_oplock_wait(node);
1672c2961f8Sjose borrego 
168*a90cf9f2SGordon Ross 	/*
169*a90cf9f2SGordon Ross 	 * Even if there are no other opens, we might want to
170*a90cf9f2SGordon Ross 	 * grant only a Level II (shared) oplock so we avoid
171*a90cf9f2SGordon Ross 	 * ever granting exclusive oplocks.
172*a90cf9f2SGordon Ross 	 *
173*a90cf9f2SGordon Ross 	 * Borrowing the SMB_TREE_OPLOCKS flag to enable/disable
174*a90cf9f2SGordon Ross 	 * exclusive oplocks (for now).  See skc_oplock_enable,
175*a90cf9f2SGordon Ross 	 * which can now be taken as "exclusive oplock enable".
176*a90cf9f2SGordon Ross 	 * Should rename this parameter, and/or implement a new
177*a90cf9f2SGordon Ross 	 * multi-valued parameter for oplock enables.
178*a90cf9f2SGordon Ross 	 */
179cb174861Sjoyce mcintosh 	if ((node->n_open_count > 1) ||
180cb174861Sjoyce mcintosh 	    (node->n_opening_count > 1) ||
181*a90cf9f2SGordon Ross 	    !smb_tree_has_feature(tree, SMB_TREE_OPLOCKS) ||
182cb174861Sjoyce mcintosh 	    smb_vop_other_opens(node->vp, ofile->f_mode)) {
183bc7c423fSGordon Ross 		/*
184bc7c423fSGordon Ross 		 * There are other opens.
185bc7c423fSGordon Ross 		 */
186cb174861Sjoyce mcintosh 		if ((!op->op_oplock_levelII) ||
187cb174861Sjoyce mcintosh 		    (!smb_session_levelII_oplocks(session)) ||
188cb174861Sjoyce mcintosh 		    (smb_oplock_exclusive_grant(grants) != NULL) ||
189bc7c423fSGordon Ross 		    (smb_lock_range_access(sr, node, 0, 0, B_FALSE))) {
190bc7c423fSGordon Ross 			/*
191bc7c423fSGordon Ross 			 * LevelII (shared) oplock not allowed,
192bc7c423fSGordon Ross 			 * so reply with "none".
193bc7c423fSGordon Ross 			 */
1942c2961f8Sjose borrego 			op->op_oplock_level = SMB_OPLOCK_NONE;
195cb174861Sjoyce mcintosh 			mutex_exit(&ol->ol_mutex);
1962c2961f8Sjose borrego 			return;
1972c2961f8Sjose borrego 		}
198cb174861Sjoyce mcintosh 
199cb174861Sjoyce mcintosh 		op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
200cb174861Sjoyce mcintosh 	}
201cb174861Sjoyce mcintosh 
2021fdeec65Sjoyce mcintosh 	og = smb_oplock_set_grant(ofile, op->op_oplock_level);
203cb174861Sjoyce mcintosh 	if (smb_oplock_insert_grant(node, og) != 0) {
2041fdeec65Sjoyce mcintosh 		smb_oplock_clear_grant(og);
205cb174861Sjoyce mcintosh 		op->op_oplock_level = SMB_OPLOCK_NONE;
206cb174861Sjoyce mcintosh 		mutex_exit(&ol->ol_mutex);
2072c2961f8Sjose borrego 		return;
2082c2961f8Sjose borrego 	}
2098c10a865Sas200622 
2102c2961f8Sjose borrego 	ol->ol_xthread = curthread;
211cb174861Sjoyce mcintosh 	mutex_exit(&ol->ol_mutex);
2128c10a865Sas200622 }
2138c10a865Sas200622 
2148c10a865Sas200622 /*
2158c10a865Sas200622  * smb_oplock_break
2168c10a865Sas200622  *
217cb174861Sjoyce mcintosh  * Break granted oplocks according to the following rules:
218cb174861Sjoyce mcintosh  *
219cb174861Sjoyce mcintosh  * If there's an exclusive oplock granted on the node
220cb174861Sjoyce mcintosh  *  - if the BREAK_BATCH flags is specified and the oplock is not
221cb174861Sjoyce mcintosh  *    a batch oplock, no break is required.
222cb174861Sjoyce mcintosh  *  - if the session doesn't support LEVEL II oplocks, and 'brk' is
223cb174861Sjoyce mcintosh  *    BREAK_TO_LEVEL_II, do a BREAK_TO_NONE.
224cb174861Sjoyce mcintosh  *  - if the oplock is already breaking update the break level (if
225cb174861Sjoyce mcintosh  *    the requested break is to a lesser level), otherwise send an
226cb174861Sjoyce mcintosh  *    oplock break.
227cb174861Sjoyce mcintosh  *    Wait for acknowledgement of the break (unless NOWAIT flag is set)
228cb174861Sjoyce mcintosh  *
229cb174861Sjoyce mcintosh  * Otherwise:
230cb174861Sjoyce mcintosh  * If there are level II oplocks granted on the node, and the flags
231cb174861Sjoyce mcintosh  * indicate that they should be broken (BREAK_TO_NONE specified,
232cb174861Sjoyce mcintosh  * BREAK_EXCLUSIVE, BREAK_BATCH not specified) queue the levelII
233cb174861Sjoyce mcintosh  * break request for asynchronous processing.
2348c10a865Sas200622  *
2352c2961f8Sjose borrego  * Returns:
236cb174861Sjoyce mcintosh  *       0 - oplock broken (or no break required)
237cb174861Sjoyce mcintosh  *  EAGAIN - oplock break request sent and would block
238cb174861Sjoyce mcintosh  *           awaiting the reponse but NOWAIT was specified
2398622ec45SGordon Ross  *
2408622ec45SGordon Ross  * NB: sr == NULL when called by FEM framework.
2418c10a865Sas200622  */
242cb174861Sjoyce mcintosh int
243cb174861Sjoyce mcintosh smb_oplock_break(smb_request_t *sr, smb_node_t *node, uint32_t flags)
244cb174861Sjoyce mcintosh {
245cb174861Sjoyce mcintosh 	smb_oplock_t		*ol;
246cb174861Sjoyce mcintosh 	smb_oplock_grant_t	*og;
247cb174861Sjoyce mcintosh 	list_t			*grants;
248cb174861Sjoyce mcintosh 	uint32_t		timeout;
249cb174861Sjoyce mcintosh 	uint8_t			brk;
250cb174861Sjoyce mcintosh 
251cb174861Sjoyce mcintosh 	SMB_NODE_VALID(node);
252cb174861Sjoyce mcintosh 	ol = &node->n_oplock;
253cb174861Sjoyce mcintosh 	grants = &ol->ol_grants;
254cb174861Sjoyce mcintosh 
255cb174861Sjoyce mcintosh 	mutex_enter(&ol->ol_mutex);
256cb174861Sjoyce mcintosh 	smb_oplock_wait(node);
257cb174861Sjoyce mcintosh 
258cb174861Sjoyce mcintosh 	og = list_head(grants);
259cb174861Sjoyce mcintosh 	if (og == NULL) {
260cb174861Sjoyce mcintosh 		mutex_exit(&ol->ol_mutex);
261cb174861Sjoyce mcintosh 		return (0);
262cb174861Sjoyce mcintosh 	}
263cb174861Sjoyce mcintosh 
264cb174861Sjoyce mcintosh 	SMB_OPLOCK_GRANT_VALID(og);
265cb174861Sjoyce mcintosh 
266cb174861Sjoyce mcintosh 	/* break levelII oplocks */
267cb174861Sjoyce mcintosh 	if (og->og_level == SMB_OPLOCK_LEVEL_II) {
268cb174861Sjoyce mcintosh 		mutex_exit(&ol->ol_mutex);
269cb174861Sjoyce mcintosh 
270cb174861Sjoyce mcintosh 		if ((flags & SMB_OPLOCK_BREAK_TO_NONE) &&
271cb174861Sjoyce mcintosh 		    !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) &&
272cb174861Sjoyce mcintosh 		    !(flags & SMB_OPLOCK_BREAK_BATCH))  {
273cb174861Sjoyce mcintosh 			smb_oplock_break_levelII(node);
274cb174861Sjoyce mcintosh 		}
275cb174861Sjoyce mcintosh 		return (0);
276cb174861Sjoyce mcintosh 	}
277cb174861Sjoyce mcintosh 
278cb174861Sjoyce mcintosh 	/* break exclusive oplock */
279cb174861Sjoyce mcintosh 	if ((flags & SMB_OPLOCK_BREAK_BATCH) &&
280cb174861Sjoyce mcintosh 	    (og->og_level != SMB_OPLOCK_BATCH)) {
281cb174861Sjoyce mcintosh 		mutex_exit(&ol->ol_mutex);
282cb174861Sjoyce mcintosh 		return (0);
283cb174861Sjoyce mcintosh 	}
284cb174861Sjoyce mcintosh 
285cb174861Sjoyce mcintosh 	if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) &&
286cb174861Sjoyce mcintosh 	    smb_session_levelII_oplocks(og->og_session)) {
287cb174861Sjoyce mcintosh 		brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
288cb174861Sjoyce mcintosh 	} else {
289cb174861Sjoyce mcintosh 		brk = SMB_OPLOCK_BREAK_TO_NONE;
290cb174861Sjoyce mcintosh 	}
291cb174861Sjoyce mcintosh 
292cb174861Sjoyce mcintosh 	switch (ol->ol_break) {
293cb174861Sjoyce mcintosh 	case SMB_OPLOCK_NO_BREAK:
294cb174861Sjoyce mcintosh 		ol->ol_break = brk;
295*a90cf9f2SGordon Ross 		smb_oplock_sched_async_break(og, brk);
296cb174861Sjoyce mcintosh 		break;
297cb174861Sjoyce mcintosh 	case SMB_OPLOCK_BREAK_TO_LEVEL_II:
298cb174861Sjoyce mcintosh 		if (brk == SMB_OPLOCK_BREAK_TO_NONE)
299cb174861Sjoyce mcintosh 			ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE;
300cb174861Sjoyce mcintosh 		break;
301cb174861Sjoyce mcintosh 	case SMB_OPLOCK_BREAK_TO_NONE:
302cb174861Sjoyce mcintosh 	default:
303cb174861Sjoyce mcintosh 		break;
304cb174861Sjoyce mcintosh 	}
305cb174861Sjoyce mcintosh 
306cb174861Sjoyce mcintosh 	if (flags & SMB_OPLOCK_BREAK_NOWAIT) {
307cb174861Sjoyce mcintosh 		mutex_exit(&ol->ol_mutex);
308cb174861Sjoyce mcintosh 		return (EAGAIN);
309cb174861Sjoyce mcintosh 	}
310cb174861Sjoyce mcintosh 
311cb174861Sjoyce mcintosh 	if (sr && (sr->session == og->og_session) &&
312cb174861Sjoyce mcintosh 	    (sr->smb_uid == og->og_uid)) {
313cb174861Sjoyce mcintosh 		timeout = smb_oplock_min_timeout;
314cb174861Sjoyce mcintosh 	} else {
315cb174861Sjoyce mcintosh 		timeout = smb_oplock_timeout;
316cb174861Sjoyce mcintosh 	}
317cb174861Sjoyce mcintosh 
318cb174861Sjoyce mcintosh 	mutex_exit(&ol->ol_mutex);
319cb174861Sjoyce mcintosh 	smb_oplock_wait_ack(node, timeout);
320cb174861Sjoyce mcintosh 	return (0);
321cb174861Sjoyce mcintosh }
322cb174861Sjoyce mcintosh 
323cb174861Sjoyce mcintosh /*
324cb174861Sjoyce mcintosh  * smb_oplock_break_levelII
325cb174861Sjoyce mcintosh  *
326*a90cf9f2SGordon Ross  * This is called after a file is modified in some way.  If there are
327*a90cf9f2SGordon Ross  * LevelII (shared) oplocks, break those to none.  If there is an
328*a90cf9f2SGordon Ross  * exclusive oplock, there can be no LevelII oplocks, so do nothing.
329*a90cf9f2SGordon Ross  *
330cb174861Sjoyce mcintosh  * LevelII (shared) oplock breaks are processed asynchronously.
331cb174861Sjoyce mcintosh  * Unlike exclusive oplock breaks, the thread initiating the break
332cb174861Sjoyce mcintosh  * is NOT blocked while the request is processed.
333cb174861Sjoyce mcintosh  *
334*a90cf9f2SGordon Ross  * There may be a thread with exclusive rights to oplock state for
335*a90cf9f2SGordon Ross  * this node (via ol_xthread in smb_oplock_wait) and if so, we must
336*a90cf9f2SGordon Ross  * avoid breaking oplocks until that's out of the way.  However, we
337*a90cf9f2SGordon Ross  * really don't want to block here, so when ol_xthread is set, we'll
338*a90cf9f2SGordon Ross  * just mark that a "break level II to none" is pending, and let the
339*a90cf9f2SGordon Ross  * exclusive thread do this work when it's done being exclusive.
340cb174861Sjoyce mcintosh  */
341cb174861Sjoyce mcintosh void
342cb174861Sjoyce mcintosh smb_oplock_break_levelII(smb_node_t *node)
343cb174861Sjoyce mcintosh {
344*a90cf9f2SGordon Ross 	smb_oplock_t		*ol;
345cb174861Sjoyce mcintosh 
346*a90cf9f2SGordon Ross 	ol = &node->n_oplock;
347*a90cf9f2SGordon Ross 	mutex_enter(&ol->ol_mutex);
348cb174861Sjoyce mcintosh 
349*a90cf9f2SGordon Ross 	/* Instead of: smb_oplock_wait() ... */
350*a90cf9f2SGordon Ross 	if (ol->ol_xthread != NULL) {
351*a90cf9f2SGordon Ross 		/* Defer the call to smb_oplock_broadcast(). */
352*a90cf9f2SGordon Ross 		ol->ol_brk_pending = SMB_OPLOCK_BREAK_TO_NONE;
353*a90cf9f2SGordon Ross 	} else {
354*a90cf9f2SGordon Ross 		/* Equivalent of smb_oplock_wait() done. */
355*a90cf9f2SGordon Ross 		smb_oplock_break_levelII_locked(node);
356*a90cf9f2SGordon Ross 	}
357cb174861Sjoyce mcintosh 
358*a90cf9f2SGordon Ross 	mutex_exit(&ol->ol_mutex);
359cb174861Sjoyce mcintosh }
360cb174861Sjoyce mcintosh 
361cb174861Sjoyce mcintosh /*
362*a90cf9f2SGordon Ross  * smb_oplock_break_levelII_locked
363*a90cf9f2SGordon Ross  * Internal helper for smb_oplock_break_levelII()
364cb174861Sjoyce mcintosh  *
365*a90cf9f2SGordon Ross  * Called with the oplock mutex already held, and _after_
366*a90cf9f2SGordon Ross  * (the equivalent of) an smb_oplock_wait().
367cb174861Sjoyce mcintosh  */
368cb174861Sjoyce mcintosh static void
369*a90cf9f2SGordon Ross smb_oplock_break_levelII_locked(smb_node_t *node)
370cb174861Sjoyce mcintosh {
371cb174861Sjoyce mcintosh 	smb_oplock_t		*ol;
372cb174861Sjoyce mcintosh 	smb_oplock_grant_t	*og;
373cb174861Sjoyce mcintosh 	list_t			*grants;
374cb174861Sjoyce mcintosh 
375cb174861Sjoyce mcintosh 	ol = &node->n_oplock;
376*a90cf9f2SGordon Ross 	grants = &ol->ol_grants;
377*a90cf9f2SGordon Ross 
378*a90cf9f2SGordon Ross 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
379*a90cf9f2SGordon Ross 	ASSERT(ol->ol_xthread == NULL);
380cb174861Sjoyce mcintosh 
381cb174861Sjoyce mcintosh 	while ((og = list_head(grants)) != NULL) {
382cb174861Sjoyce mcintosh 		SMB_OPLOCK_GRANT_VALID(og);
383cb174861Sjoyce mcintosh 
384*a90cf9f2SGordon Ross 		/*
385*a90cf9f2SGordon Ross 		 * If there's an exclusive oplock, there are
386*a90cf9f2SGordon Ross 		 * no LevelII oplocks, so do nothing.
387*a90cf9f2SGordon Ross 		 */
388cb174861Sjoyce mcintosh 		if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
389cb174861Sjoyce mcintosh 			break;
390cb174861Sjoyce mcintosh 
391*a90cf9f2SGordon Ross 		smb_oplock_sched_async_break(og, SMB_OPLOCK_BREAK_TO_NONE);
392cb174861Sjoyce mcintosh 		smb_oplock_remove_grant(node, og);
3931fdeec65Sjoyce mcintosh 		smb_oplock_clear_grant(og);
394cb174861Sjoyce mcintosh 	}
395*a90cf9f2SGordon Ross }
396cb174861Sjoyce mcintosh 
397*a90cf9f2SGordon Ross /*
398*a90cf9f2SGordon Ross  * Schedule a call to smb_session_oplock_break
399*a90cf9f2SGordon Ross  * using an smb_request on the owning session.
400*a90cf9f2SGordon Ross  */
401*a90cf9f2SGordon Ross static void
402*a90cf9f2SGordon Ross smb_oplock_sched_async_break(smb_oplock_grant_t *og, uint8_t brk)
403*a90cf9f2SGordon Ross {
404*a90cf9f2SGordon Ross 	smb_request_t		*sr;
405*a90cf9f2SGordon Ross 	smb_ofile_t		*ofile;
406*a90cf9f2SGordon Ross 
407*a90cf9f2SGordon Ross 	/*
408*a90cf9f2SGordon Ross 	 * Make sure we can get a hold on the ofile.  If we can't,
409*a90cf9f2SGordon Ross 	 * the file is closing, and there's no point scheduling an
410*a90cf9f2SGordon Ross 	 * oplock break on it.  (Also hold the tree and user.)
411*a90cf9f2SGordon Ross 	 * These holds account for the pointers we copy into the
412*a90cf9f2SGordon Ross 	 * smb_request fields: fid_ofile, tid_tree, uid_user.
413*a90cf9f2SGordon Ross 	 * These holds are released via smb_request_free after
414*a90cf9f2SGordon Ross 	 * the oplock break has been sent.
415*a90cf9f2SGordon Ross 	 */
416*a90cf9f2SGordon Ross 	ofile = og->og_ofile;
417*a90cf9f2SGordon Ross 	if (!smb_ofile_hold(ofile))
418*a90cf9f2SGordon Ross 		return;
419*a90cf9f2SGordon Ross 	smb_tree_hold_internal(ofile->f_tree);
420*a90cf9f2SGordon Ross 	smb_user_hold_internal(ofile->f_user);
421*a90cf9f2SGordon Ross 
422*a90cf9f2SGordon Ross 	sr = smb_request_alloc(og->og_session, 0);
423*a90cf9f2SGordon Ross 	sr->sr_state = SMB_REQ_STATE_SUBMITTED;
424*a90cf9f2SGordon Ross 	sr->user_cr = zone_kcred();
425*a90cf9f2SGordon Ross 	sr->fid_ofile = ofile;
426*a90cf9f2SGordon Ross 	sr->tid_tree = ofile->f_tree;
427*a90cf9f2SGordon Ross 	sr->uid_user = ofile->f_user;
428*a90cf9f2SGordon Ross 
429*a90cf9f2SGordon Ross 	sr->arg.olbrk = *og; /* struct copy */
430*a90cf9f2SGordon Ross 	sr->arg.olbrk.og_breaking = brk;
431*a90cf9f2SGordon Ross 
432*a90cf9f2SGordon Ross 	(void) taskq_dispatch(
433*a90cf9f2SGordon Ross 	    sr->sr_server->sv_worker_pool,
434*a90cf9f2SGordon Ross 	    smb_oplock_exec_async_break, sr, TQ_SLEEP);
435*a90cf9f2SGordon Ross }
436*a90cf9f2SGordon Ross 
437*a90cf9f2SGordon Ross /*
438*a90cf9f2SGordon Ross  * smb_oplock_exec_async_break
439*a90cf9f2SGordon Ross  *
440*a90cf9f2SGordon Ross  * Called via the taskq to handle an asynchronous oplock break.
441*a90cf9f2SGordon Ross  * We have a hold on the ofile, which keeps the FID here valid.
442*a90cf9f2SGordon Ross  */
443*a90cf9f2SGordon Ross static void
444*a90cf9f2SGordon Ross smb_oplock_exec_async_break(void *arg)
445*a90cf9f2SGordon Ross {
446*a90cf9f2SGordon Ross 	smb_request_t *sr = arg;
447*a90cf9f2SGordon Ross 	smb_oplock_grant_t *og = &sr->arg.olbrk;
448*a90cf9f2SGordon Ross 
449*a90cf9f2SGordon Ross 	SMB_REQ_VALID(sr);
450*a90cf9f2SGordon Ross 	SMB_OPLOCK_GRANT_VALID(og);
451*a90cf9f2SGordon Ross 
452*a90cf9f2SGordon Ross 	mutex_enter(&sr->sr_mutex);
453*a90cf9f2SGordon Ross 	sr->sr_worker = curthread;
454*a90cf9f2SGordon Ross 	sr->sr_time_active = gethrtime();
455*a90cf9f2SGordon Ross 
456*a90cf9f2SGordon Ross 	switch (sr->sr_state) {
457*a90cf9f2SGordon Ross 	case SMB_REQ_STATE_SUBMITTED:
458*a90cf9f2SGordon Ross 		sr->sr_state = SMB_REQ_STATE_ACTIVE;
459*a90cf9f2SGordon Ross 		mutex_exit(&sr->sr_mutex);
460*a90cf9f2SGordon Ross 
461*a90cf9f2SGordon Ross 		/*
462*a90cf9f2SGordon Ross 		 * This is where we actually do the deferred work
463*a90cf9f2SGordon Ross 		 * requested by smb_oplock_sched_async_break().
464*a90cf9f2SGordon Ross 		 */
465*a90cf9f2SGordon Ross 		smb_session_oplock_break(sr, og->og_breaking);
466*a90cf9f2SGordon Ross 
467*a90cf9f2SGordon Ross 		mutex_enter(&sr->sr_mutex);
468*a90cf9f2SGordon Ross 		/* FALLTHROUGH */
469*a90cf9f2SGordon Ross 
470*a90cf9f2SGordon Ross 	default: /* typically cancelled */
471*a90cf9f2SGordon Ross 		sr->sr_state = SMB_REQ_STATE_COMPLETED;
472*a90cf9f2SGordon Ross 		mutex_exit(&sr->sr_mutex);
473*a90cf9f2SGordon Ross 	}
474*a90cf9f2SGordon Ross 
475*a90cf9f2SGordon Ross 	smb_request_free(sr);
476cb174861Sjoyce mcintosh }
477cb174861Sjoyce mcintosh 
478cb174861Sjoyce mcintosh /*
479cb174861Sjoyce mcintosh  * smb_oplock_wait_ack
480cb174861Sjoyce mcintosh  *
481cb174861Sjoyce mcintosh  * Timed wait for an oplock break acknowledgement (or oplock release).
482cb174861Sjoyce mcintosh  */
483cb174861Sjoyce mcintosh static void
484cb174861Sjoyce mcintosh smb_oplock_wait_ack(smb_node_t *node, uint32_t timeout)
4858c10a865Sas200622 {
4862c2961f8Sjose borrego 	smb_oplock_t	*ol;
4872c2961f8Sjose borrego 	clock_t		time;
4888c10a865Sas200622 
4892c2961f8Sjose borrego 	ol = &node->n_oplock;
490cb174861Sjoyce mcintosh 	mutex_enter(&ol->ol_mutex);
491cb174861Sjoyce mcintosh 	time = MSEC_TO_TICK(timeout) + ddi_get_lbolt();
4928c10a865Sas200622 
493cb174861Sjoyce mcintosh 	while (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
494cb174861Sjoyce mcintosh 		if (cv_timedwait(&ol->ol_cv, &ol->ol_mutex, time) < 0) {
495cb174861Sjoyce mcintosh 			smb_oplock_timedout(node);
4962c2961f8Sjose borrego 			cv_broadcast(&ol->ol_cv);
4978c10a865Sas200622 			break;
4988c10a865Sas200622 		}
4998c10a865Sas200622 	}
500cb174861Sjoyce mcintosh 	mutex_exit(&ol->ol_mutex);
5018c10a865Sas200622 }
502cb174861Sjoyce mcintosh 
503cb174861Sjoyce mcintosh /*
504cb174861Sjoyce mcintosh  * smb_oplock_timedout
505cb174861Sjoyce mcintosh  *
506cb174861Sjoyce mcintosh  * An oplock break has not been acknowledged within timeout
507cb174861Sjoyce mcintosh  * 'smb_oplock_timeout'.
508cb174861Sjoyce mcintosh  * Set oplock grant to the desired break level.
509cb174861Sjoyce mcintosh  */
510cb174861Sjoyce mcintosh static void
511cb174861Sjoyce mcintosh smb_oplock_timedout(smb_node_t *node)
512cb174861Sjoyce mcintosh {
513cb174861Sjoyce mcintosh 	smb_oplock_t		*ol;
514cb174861Sjoyce mcintosh 	smb_oplock_grant_t	*og;
515cb174861Sjoyce mcintosh 	list_t			*grants;
516cb174861Sjoyce mcintosh 
517cb174861Sjoyce mcintosh 	ol = &node->n_oplock;
518cb174861Sjoyce mcintosh 	grants = &ol->ol_grants;
519cb174861Sjoyce mcintosh 
520cb174861Sjoyce mcintosh 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
521cb174861Sjoyce mcintosh 
522cb174861Sjoyce mcintosh 	og = smb_oplock_exclusive_grant(grants);
523cb174861Sjoyce mcintosh 	if (og) {
524cb174861Sjoyce mcintosh 		switch (ol->ol_break) {
525cb174861Sjoyce mcintosh 		case SMB_OPLOCK_BREAK_TO_NONE:
526cb174861Sjoyce mcintosh 			og->og_level = SMB_OPLOCK_NONE;
527cb174861Sjoyce mcintosh 			smb_oplock_remove_grant(node, og);
5281fdeec65Sjoyce mcintosh 			smb_oplock_clear_grant(og);
529cb174861Sjoyce mcintosh 			break;
530cb174861Sjoyce mcintosh 		case SMB_OPLOCK_BREAK_TO_LEVEL_II:
531cb174861Sjoyce mcintosh 			og->og_level = SMB_OPLOCK_LEVEL_II;
532cb174861Sjoyce mcintosh 			break;
533cb174861Sjoyce mcintosh 		default:
534cb174861Sjoyce mcintosh 			SMB_PANIC();
535cb174861Sjoyce mcintosh 		}
536cb174861Sjoyce mcintosh 	}
537cb174861Sjoyce mcintosh 	ol->ol_break = SMB_OPLOCK_NO_BREAK;
5388c10a865Sas200622 }
5398c10a865Sas200622 
5408c10a865Sas200622 /*
5418c10a865Sas200622  * smb_oplock_release
5428c10a865Sas200622  *
543cb174861Sjoyce mcintosh  * Release the oplock granted on ofile 'of'.
544cb174861Sjoyce mcintosh  * Wake any threads waiting for an oplock break acknowledgement for
545cb174861Sjoyce mcintosh  * this oplock.
546cb174861Sjoyce mcintosh  * This is called when the ofile is being closed.
5478c10a865Sas200622  */
5482c2961f8Sjose borrego void
5492c2961f8Sjose borrego smb_oplock_release(smb_node_t *node, smb_ofile_t *of)
5508c10a865Sas200622 {
5512c2961f8Sjose borrego 	smb_oplock_t		*ol;
552cb174861Sjoyce mcintosh 	smb_oplock_grant_t	*og;
5538c10a865Sas200622 
5542c2961f8Sjose borrego 	ol = &node->n_oplock;
555cb174861Sjoyce mcintosh 	mutex_enter(&ol->ol_mutex);
556fc724630SAlan Wright 	smb_oplock_wait(node);
5572c2961f8Sjose borrego 
5581fdeec65Sjoyce mcintosh 	og = smb_oplock_get_grant(ol, of);
559cb174861Sjoyce mcintosh 	if (og) {
560cb174861Sjoyce mcintosh 		smb_oplock_remove_grant(node, og);
5611fdeec65Sjoyce mcintosh 		smb_oplock_clear_grant(og);
562cb174861Sjoyce mcintosh 
563cb174861Sjoyce mcintosh 		if (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
564cb174861Sjoyce mcintosh 			ol->ol_break = SMB_OPLOCK_NO_BREAK;
5652c2961f8Sjose borrego 			cv_broadcast(&ol->ol_cv);
5662c2961f8Sjose borrego 		}
5672c2961f8Sjose borrego 	}
568cb174861Sjoyce mcintosh 
569cb174861Sjoyce mcintosh 	mutex_exit(&ol->ol_mutex);
5708c10a865Sas200622 }
5718c10a865Sas200622 
5728c10a865Sas200622 /*
573cb174861Sjoyce mcintosh  * smb_oplock_ack
5748c10a865Sas200622  *
575cb174861Sjoyce mcintosh  * Process oplock acknowledgement received for ofile 'of'.
576cb174861Sjoyce mcintosh  * - oplock.ol_break is the break level that was requested.
577cb174861Sjoyce mcintosh  * - brk is the break level being acknowledged by the client.
578cb174861Sjoyce mcintosh  *
579cb174861Sjoyce mcintosh  * Update the oplock grant level to the lesser of ol_break and brk.
580cb174861Sjoyce mcintosh  * If the grant is now SMB_OPLOCK_NONE, remove the grant from the
581cb174861Sjoyce mcintosh  * oplock's grant list and delete it.
582cb174861Sjoyce mcintosh  * If the requested break level (ol_break) was NONE and the brk is
583cb174861Sjoyce mcintosh  * LEVEL_II, send another oplock break (NONE). Do not wait for an
584cb174861Sjoyce mcintosh  * acknowledgement.
585cb174861Sjoyce mcintosh  * Wake any threads waiting for the oplock break acknowledgement.
5868c10a865Sas200622  */
587cb174861Sjoyce mcintosh void
588cb174861Sjoyce mcintosh smb_oplock_ack(smb_node_t *node, smb_ofile_t *of, uint8_t brk)
5898c10a865Sas200622 {
590cb174861Sjoyce mcintosh 	smb_oplock_t		*ol;
591cb174861Sjoyce mcintosh 	smb_oplock_grant_t	*og;
5928c10a865Sas200622 
593cb174861Sjoyce mcintosh 	ol = &node->n_oplock;
594cb174861Sjoyce mcintosh 	mutex_enter(&ol->ol_mutex);
595fc724630SAlan Wright 	smb_oplock_wait(node);
5962c2961f8Sjose borrego 
597cb174861Sjoyce mcintosh 	if ((ol->ol_break == SMB_OPLOCK_NO_BREAK) ||
5981fdeec65Sjoyce mcintosh 	    ((og = smb_oplock_get_grant(ol, of)) == NULL)) {
599cb174861Sjoyce mcintosh 		mutex_exit(&ol->ol_mutex);
600cb174861Sjoyce mcintosh 		return;
6018c10a865Sas200622 	}
6028c10a865Sas200622 
603cb174861Sjoyce mcintosh 	switch (brk) {
604cb174861Sjoyce mcintosh 	case SMB_OPLOCK_BREAK_TO_NONE:
605cb174861Sjoyce mcintosh 		og->og_level = SMB_OPLOCK_NONE;
6062c2961f8Sjose borrego 		break;
607cb174861Sjoyce mcintosh 	case SMB_OPLOCK_BREAK_TO_LEVEL_II:
608cb174861Sjoyce mcintosh 		if (ol->ol_break == SMB_OPLOCK_BREAK_TO_LEVEL_II) {
609cb174861Sjoyce mcintosh 			og->og_level = SMB_OPLOCK_LEVEL_II;
610cb174861Sjoyce mcintosh 		} else {
611cb174861Sjoyce mcintosh 			/* SMB_OPLOCK_BREAK_TO_NONE */
612cb174861Sjoyce mcintosh 			og->og_level = SMB_OPLOCK_NONE;
613*a90cf9f2SGordon Ross 			smb_oplock_sched_async_break(og,
614*a90cf9f2SGordon Ross 			    SMB_OPLOCK_BREAK_TO_NONE);
6152c2961f8Sjose borrego 		}
6162c2961f8Sjose borrego 		break;
6172c2961f8Sjose borrego 	default:
6182c2961f8Sjose borrego 		SMB_PANIC();
6192c2961f8Sjose borrego 	}
620cb174861Sjoyce mcintosh 
621cb174861Sjoyce mcintosh 	if (og->og_level == SMB_OPLOCK_NONE) {
622cb174861Sjoyce mcintosh 		smb_oplock_remove_grant(node, og);
6231fdeec65Sjoyce mcintosh 		smb_oplock_clear_grant(og);
624cb174861Sjoyce mcintosh 	}
625cb174861Sjoyce mcintosh 
626cb174861Sjoyce mcintosh 	ol->ol_break = SMB_OPLOCK_NO_BREAK;
627cb174861Sjoyce mcintosh 	cv_broadcast(&ol->ol_cv);
628cb174861Sjoyce mcintosh 
629cb174861Sjoyce mcintosh 	mutex_exit(&ol->ol_mutex);
6308c10a865Sas200622 }
6318c10a865Sas200622 
6322c2961f8Sjose borrego /*
633fc724630SAlan Wright  * smb_oplock_broadcast
6342c2961f8Sjose borrego  *
635*a90cf9f2SGordon Ross  * Called when an open with oplock request completes.
636*a90cf9f2SGordon Ross  *
637cb174861Sjoyce mcintosh  * ol->ol_xthread identifies the thread that was performing an oplock
638cb174861Sjoyce mcintosh  * acquire. Other threads may be blocked awaiting completion of the
639cb174861Sjoyce mcintosh  * acquire.
640*a90cf9f2SGordon Ross  * If the calling thread is ol_xthread, wake any waiting threads.
6412c2961f8Sjose borrego  */
642cb174861Sjoyce mcintosh void
643fc724630SAlan Wright smb_oplock_broadcast(smb_node_t *node)
6442c2961f8Sjose borrego {
6452c2961f8Sjose borrego 	smb_oplock_t	*ol;
6462c2961f8Sjose borrego 
6472c2961f8Sjose borrego 	SMB_NODE_VALID(node);
6482c2961f8Sjose borrego 	ol = &node->n_oplock;
6492c2961f8Sjose borrego 
650cb174861Sjoyce mcintosh 	mutex_enter(&ol->ol_mutex);
6512c2961f8Sjose borrego 	if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) {
6522c2961f8Sjose borrego 		ol->ol_xthread = NULL;
653*a90cf9f2SGordon Ross 		if (ol->ol_brk_pending) {
654*a90cf9f2SGordon Ross 			ol->ol_brk_pending = 0;
655*a90cf9f2SGordon Ross 			smb_oplock_break_levelII_locked(node);
656*a90cf9f2SGordon Ross 		}
6572c2961f8Sjose borrego 		cv_broadcast(&ol->ol_cv);
6582c2961f8Sjose borrego 	}
659cb174861Sjoyce mcintosh 	mutex_exit(&ol->ol_mutex);
6608c10a865Sas200622 }
6618c10a865Sas200622 
6622c2961f8Sjose borrego /*
6632c2961f8Sjose borrego  * smb_oplock_wait
6642c2961f8Sjose borrego  *
665cb174861Sjoyce mcintosh  * Wait for the completion of an oplock acquire.
666cb174861Sjoyce mcintosh  * If ol_xthread is not NULL and doesn't contain the pointer to the
667cb174861Sjoyce mcintosh  * context of the calling thread, the caller will sleep until the
668cb174861Sjoyce mcintosh  * ol_xthread is reset to NULL (via smb_oplock_broadcast()).
6692c2961f8Sjose borrego  */
6702c2961f8Sjose borrego static void
671fc724630SAlan Wright smb_oplock_wait(smb_node_t *node)
6722c2961f8Sjose borrego {
673cb174861Sjoyce mcintosh 	smb_oplock_t	*ol;
674cb174861Sjoyce mcintosh 
675cb174861Sjoyce mcintosh 	ol = &node->n_oplock;
676cb174861Sjoyce mcintosh 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
6772c2961f8Sjose borrego 
6782c2961f8Sjose borrego 	if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) {
6792c2961f8Sjose borrego 		while (ol->ol_xthread != NULL)
680cb174861Sjoyce mcintosh 			cv_wait(&ol->ol_cv, &ol->ol_mutex);
6812c2961f8Sjose borrego 	}
6828c10a865Sas200622 }
683cb174861Sjoyce mcintosh 
684cb174861Sjoyce mcintosh /*
6851fdeec65Sjoyce mcintosh  * smb_oplock_set_grant
686cb174861Sjoyce mcintosh  */
687cb174861Sjoyce mcintosh static smb_oplock_grant_t *
6881fdeec65Sjoyce mcintosh smb_oplock_set_grant(smb_ofile_t *of, uint8_t level)
689cb174861Sjoyce mcintosh {
690cb174861Sjoyce mcintosh 	smb_oplock_grant_t	*og;
691cb174861Sjoyce mcintosh 
6921fdeec65Sjoyce mcintosh 	og = &of->f_oplock_grant;
6931fdeec65Sjoyce mcintosh 
694cb174861Sjoyce mcintosh 	og->og_magic = SMB_OPLOCK_GRANT_MAGIC;
695*a90cf9f2SGordon Ross 	og->og_breaking = 0;
696cb174861Sjoyce mcintosh 	og->og_level = level;
697cb174861Sjoyce mcintosh 	og->og_ofile = of;
698cb174861Sjoyce mcintosh 	og->og_fid = of->f_fid;
699cb174861Sjoyce mcintosh 	og->og_tid = of->f_tree->t_tid;
700cb174861Sjoyce mcintosh 	og->og_uid = of->f_user->u_uid;
701cb174861Sjoyce mcintosh 	og->og_session = of->f_session;
702cb174861Sjoyce mcintosh 	return (og);
703cb174861Sjoyce mcintosh }
704cb174861Sjoyce mcintosh 
705cb174861Sjoyce mcintosh /*
7061fdeec65Sjoyce mcintosh  * smb_oplock_clear_grant
707cb174861Sjoyce mcintosh  */
708cb174861Sjoyce mcintosh void
7091fdeec65Sjoyce mcintosh smb_oplock_clear_grant(smb_oplock_grant_t *og)
710cb174861Sjoyce mcintosh {
7111fdeec65Sjoyce mcintosh 	bzero(og, sizeof (smb_oplock_grant_t));
712cb174861Sjoyce mcintosh }
713cb174861Sjoyce mcintosh 
714cb174861Sjoyce mcintosh /*
715cb174861Sjoyce mcintosh  * smb_oplock_insert_grant
716cb174861Sjoyce mcintosh  *
717cb174861Sjoyce mcintosh  * If there are no grants in the oplock's list install the fem
718cb174861Sjoyce mcintosh  * monitor.
719cb174861Sjoyce mcintosh  * Insert the grant into the list and increment the grant count.
720cb174861Sjoyce mcintosh  */
721cb174861Sjoyce mcintosh static int
722cb174861Sjoyce mcintosh smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og)
723cb174861Sjoyce mcintosh {
724cb174861Sjoyce mcintosh 	smb_oplock_t *ol = &node->n_oplock;
725cb174861Sjoyce mcintosh 
726cb174861Sjoyce mcintosh 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
727cb174861Sjoyce mcintosh 
728cb174861Sjoyce mcintosh 	if (ol->ol_count == 0) {
729cb174861Sjoyce mcintosh 		if (smb_oplock_install_fem(node) != 0)
730cb174861Sjoyce mcintosh 			return (-1);
731cb174861Sjoyce mcintosh 	}
732cb174861Sjoyce mcintosh 
733cb174861Sjoyce mcintosh 	list_insert_tail(&ol->ol_grants, og);
734cb174861Sjoyce mcintosh 	++ol->ol_count;
735cb174861Sjoyce mcintosh 	return (0);
736cb174861Sjoyce mcintosh }
737cb174861Sjoyce mcintosh 
738cb174861Sjoyce mcintosh /*
739cb174861Sjoyce mcintosh  * smb_oplock_remove_grant
740cb174861Sjoyce mcintosh  *
741cb174861Sjoyce mcintosh  * Remove the oplock grant from the list, decrement the grant count
742cb174861Sjoyce mcintosh  * and, if there are no other grants in the list, uninstall the fem
743cb174861Sjoyce mcintosh  * monitor.
744cb174861Sjoyce mcintosh  */
745cb174861Sjoyce mcintosh static void
746cb174861Sjoyce mcintosh smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og)
747cb174861Sjoyce mcintosh {
748cb174861Sjoyce mcintosh 	smb_oplock_t *ol = &node->n_oplock;
749cb174861Sjoyce mcintosh 
750cb174861Sjoyce mcintosh 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
751cb174861Sjoyce mcintosh 	ASSERT(ol->ol_count > 0);
752cb174861Sjoyce mcintosh 
753cb174861Sjoyce mcintosh 	list_remove(&ol->ol_grants, og);
754cb174861Sjoyce mcintosh 	if (--ol->ol_count == 0)
755cb174861Sjoyce mcintosh 		smb_oplock_uninstall_fem(node);
756cb174861Sjoyce mcintosh }
757cb174861Sjoyce mcintosh 
758cb174861Sjoyce mcintosh /*
759cb174861Sjoyce mcintosh  * smb_oplock_exclusive_grant
760cb174861Sjoyce mcintosh  *
761cb174861Sjoyce mcintosh  * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists,
762cb174861Sjoyce mcintosh  * return it. Otherwise return NULL.
763cb174861Sjoyce mcintosh  */
764cb174861Sjoyce mcintosh static smb_oplock_grant_t *
765cb174861Sjoyce mcintosh smb_oplock_exclusive_grant(list_t *grants)
766cb174861Sjoyce mcintosh {
767cb174861Sjoyce mcintosh 	smb_oplock_grant_t	*og;
768cb174861Sjoyce mcintosh 
769cb174861Sjoyce mcintosh 	og = list_head(grants);
770cb174861Sjoyce mcintosh 	if (og) {
771cb174861Sjoyce mcintosh 		SMB_OPLOCK_GRANT_VALID(og);
772cb174861Sjoyce mcintosh 		if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
773cb174861Sjoyce mcintosh 			return (og);
774cb174861Sjoyce mcintosh 	}
775cb174861Sjoyce mcintosh 	return (NULL);
776cb174861Sjoyce mcintosh }
777cb174861Sjoyce mcintosh 
778cb174861Sjoyce mcintosh /*
7791fdeec65Sjoyce mcintosh  * smb_oplock_get_grant
780cb174861Sjoyce mcintosh  *
781cb174861Sjoyce mcintosh  * Find oplock grant corresponding to the specified ofile.
782cb174861Sjoyce mcintosh  */
783cb174861Sjoyce mcintosh static smb_oplock_grant_t *
7841fdeec65Sjoyce mcintosh smb_oplock_get_grant(smb_oplock_t *ol, smb_ofile_t *ofile)
785cb174861Sjoyce mcintosh {
7861fdeec65Sjoyce mcintosh 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
787cb174861Sjoyce mcintosh 
7881fdeec65Sjoyce mcintosh 	if (SMB_OFILE_OPLOCK_GRANTED(ofile))
7891fdeec65Sjoyce mcintosh 		return (&ofile->f_oplock_grant);
7901fdeec65Sjoyce mcintosh 	else
7911fdeec65Sjoyce mcintosh 		return (NULL);
792cb174861Sjoyce mcintosh }
793