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
smb_oplock_install_fem(smb_node_t * node)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
smb_oplock_uninstall_fem(smb_node_t * node)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
smb_oplock_acquire(smb_request_t * sr,smb_node_t * node,smb_ofile_t * ofile)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
smb_oplock_break(smb_request_t * sr,smb_node_t * node,uint32_t flags)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
smb_oplock_break_levelII(smb_node_t * node)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
smb_oplock_break_levelII_locked(smb_node_t * node)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
smb_oplock_sched_async_break(smb_oplock_grant_t * og,uint8_t brk)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
smb_oplock_exec_async_break(void * arg)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
smb_oplock_wait_ack(smb_node_t * node,uint32_t timeout)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
smb_oplock_timedout(smb_node_t * node)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
smb_oplock_release(smb_node_t * node,smb_ofile_t * of)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
smb_oplock_ack(smb_node_t * node,smb_ofile_t * of,uint8_t brk)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
smb_oplock_broadcast(smb_node_t * node)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
smb_oplock_wait(smb_node_t * node)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 *
smb_oplock_set_grant(smb_ofile_t * of,uint8_t level)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
smb_oplock_clear_grant(smb_oplock_grant_t * og)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
smb_oplock_insert_grant(smb_node_t * node,smb_oplock_grant_t * og)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
smb_oplock_remove_grant(smb_node_t * node,smb_oplock_grant_t * og)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 *
smb_oplock_exclusive_grant(list_t * grants)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 *
smb_oplock_get_grant(smb_oplock_t * ol,smb_ofile_t * ofile)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