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 /*
2208344b29SGordon Ross * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
23148c5f43SAlan Wright * Copyright (c) 2007, 2010, Oracle and/or its affiliates. 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
63cb174861Sjoyce mcintosh static smb_oplock_break_t *smb_oplock_create_break(smb_node_t *);
64cb174861Sjoyce mcintosh static smb_oplock_break_t *smb_oplock_get_break(void);
65cb174861Sjoyce mcintosh static void smb_oplock_delete_break(smb_oplock_break_t *);
66cb174861Sjoyce mcintosh static void smb_oplock_process_levelII_break(smb_node_t *);
67cb174861Sjoyce mcintosh
68cb174861Sjoyce mcintosh static void smb_oplock_break_thread();
69cb174861Sjoyce mcintosh
70cb174861Sjoyce mcintosh /* levelII oplock break requests (smb_oplock_break_t) */
71cb174861Sjoyce mcintosh static boolean_t smb_oplock_initialized = B_FALSE;
72cb174861Sjoyce mcintosh static kmem_cache_t *smb_oplock_break_cache = NULL;
73cb174861Sjoyce mcintosh static smb_llist_t smb_oplock_breaks;
74cb174861Sjoyce mcintosh static smb_thread_t smb_oplock_thread;
75*8622ec45SGordon Ross /* shared by all zones */
768c10a865Sas200622
778c10a865Sas200622 /*
78cb174861Sjoyce mcintosh * smb_oplock_init
798c10a865Sas200622 *
80cb174861Sjoyce mcintosh * This function is not multi-thread safe. The caller must make sure only one
81cb174861Sjoyce mcintosh * thread makes the call.
828c10a865Sas200622 */
83cb174861Sjoyce mcintosh int
smb_oplock_init(void)84cb174861Sjoyce mcintosh smb_oplock_init(void)
85cb174861Sjoyce mcintosh {
86cb174861Sjoyce mcintosh int rc;
87cb174861Sjoyce mcintosh
88cb174861Sjoyce mcintosh if (smb_oplock_initialized)
89cb174861Sjoyce mcintosh return (0);
90cb174861Sjoyce mcintosh
91cb174861Sjoyce mcintosh smb_oplock_break_cache = kmem_cache_create("smb_oplock_break_cache",
92cb174861Sjoyce mcintosh sizeof (smb_oplock_break_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
93cb174861Sjoyce mcintosh
94cb174861Sjoyce mcintosh smb_llist_constructor(&smb_oplock_breaks, sizeof (smb_oplock_break_t),
95cb174861Sjoyce mcintosh offsetof(smb_oplock_break_t, ob_lnd));
96cb174861Sjoyce mcintosh
97cb174861Sjoyce mcintosh smb_thread_init(&smb_oplock_thread, "smb_thread_oplock_break",
9808344b29SGordon Ross smb_oplock_break_thread, NULL, smbsrv_notify_pri);
99cb174861Sjoyce mcintosh
100cb174861Sjoyce mcintosh rc = smb_thread_start(&smb_oplock_thread);
101cb174861Sjoyce mcintosh if (rc != 0) {
102cb174861Sjoyce mcintosh smb_thread_destroy(&smb_oplock_thread);
103cb174861Sjoyce mcintosh smb_llist_destructor(&smb_oplock_breaks);
104cb174861Sjoyce mcintosh kmem_cache_destroy(smb_oplock_break_cache);
105cb174861Sjoyce mcintosh return (rc);
106cb174861Sjoyce mcintosh }
107cb174861Sjoyce mcintosh
108cb174861Sjoyce mcintosh smb_oplock_initialized = B_TRUE;
109cb174861Sjoyce mcintosh return (0);
110cb174861Sjoyce mcintosh }
111cb174861Sjoyce mcintosh
112cb174861Sjoyce mcintosh /*
113cb174861Sjoyce mcintosh * smb_oplock_fini
114cb174861Sjoyce mcintosh * This function is not multi-thread safe. The caller must make sure only one
115cb174861Sjoyce mcintosh * thread makes the call.
116cb174861Sjoyce mcintosh */
117cb174861Sjoyce mcintosh void
smb_oplock_fini(void)118cb174861Sjoyce mcintosh smb_oplock_fini(void)
119cb174861Sjoyce mcintosh {
120cb174861Sjoyce mcintosh smb_oplock_break_t *ob;
121cb174861Sjoyce mcintosh
122cb174861Sjoyce mcintosh if (!smb_oplock_initialized)
123cb174861Sjoyce mcintosh return;
124cb174861Sjoyce mcintosh
125cb174861Sjoyce mcintosh smb_thread_stop(&smb_oplock_thread);
126cb174861Sjoyce mcintosh smb_thread_destroy(&smb_oplock_thread);
127cb174861Sjoyce mcintosh
128cb174861Sjoyce mcintosh while ((ob = smb_llist_head(&smb_oplock_breaks)) != NULL) {
129cb174861Sjoyce mcintosh SMB_OPLOCK_BREAK_VALID(ob);
130cb174861Sjoyce mcintosh smb_llist_remove(&smb_oplock_breaks, ob);
131cb174861Sjoyce mcintosh smb_oplock_delete_break(ob);
132cb174861Sjoyce mcintosh }
133cb174861Sjoyce mcintosh smb_llist_destructor(&smb_oplock_breaks);
134cb174861Sjoyce mcintosh
135cb174861Sjoyce mcintosh kmem_cache_destroy(smb_oplock_break_cache);
136cb174861Sjoyce mcintosh }
137cb174861Sjoyce mcintosh
138cb174861Sjoyce mcintosh /*
139cb174861Sjoyce mcintosh * smb_oplock_install_fem
140cb174861Sjoyce mcintosh * Install fem monitor for cross protocol oplock breaking.
141cb174861Sjoyce mcintosh */
142cb174861Sjoyce mcintosh static int
smb_oplock_install_fem(smb_node_t * node)143cb174861Sjoyce mcintosh smb_oplock_install_fem(smb_node_t *node)
144cb174861Sjoyce mcintosh {
145cb174861Sjoyce mcintosh ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
146cb174861Sjoyce mcintosh
147cb174861Sjoyce mcintosh if (node->n_oplock.ol_fem == B_FALSE) {
148cb174861Sjoyce mcintosh if (smb_fem_oplock_install(node) != 0) {
149cb174861Sjoyce mcintosh cmn_err(CE_NOTE, "No oplock granted: "
150cb174861Sjoyce mcintosh "failed to install fem monitor %s",
151cb174861Sjoyce mcintosh node->vp->v_path);
152cb174861Sjoyce mcintosh return (-1);
153cb174861Sjoyce mcintosh }
154cb174861Sjoyce mcintosh node->n_oplock.ol_fem = B_TRUE;
155cb174861Sjoyce mcintosh }
156cb174861Sjoyce mcintosh return (0);
157cb174861Sjoyce mcintosh }
158cb174861Sjoyce mcintosh
159cb174861Sjoyce mcintosh /*
160cb174861Sjoyce mcintosh * smb_oplock_uninstall_fem
161cb174861Sjoyce mcintosh * Uninstall fem monitor for cross protocol oplock breaking.
162cb174861Sjoyce mcintosh */
163cb174861Sjoyce mcintosh static void
smb_oplock_uninstall_fem(smb_node_t * node)164cb174861Sjoyce mcintosh smb_oplock_uninstall_fem(smb_node_t *node)
165cb174861Sjoyce mcintosh {
166cb174861Sjoyce mcintosh ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
167cb174861Sjoyce mcintosh
168cb174861Sjoyce mcintosh if (node->n_oplock.ol_fem) {
169*8622ec45SGordon Ross smb_fem_oplock_uninstall(node);
170cb174861Sjoyce mcintosh node->n_oplock.ol_fem = B_FALSE;
171cb174861Sjoyce mcintosh }
172cb174861Sjoyce mcintosh }
1738c10a865Sas200622
1748c10a865Sas200622 /*
1758c10a865Sas200622 * smb_oplock_acquire
1768c10a865Sas200622 *
177cb174861Sjoyce mcintosh * Attempt to acquire an oplock. Clients will request EXCLUSIVE or BATCH,
178cb174861Sjoyce mcintosh * but might only be granted LEVEL_II or NONE.
1798c10a865Sas200622 *
180cb174861Sjoyce mcintosh * If oplocks are not supported on the tree, or node, grant NONE.
181cb174861Sjoyce mcintosh * If nobody else has the file open, grant the requested level.
182cb174861Sjoyce mcintosh * If any of the following are true, grant NONE:
183cb174861Sjoyce mcintosh * - there is an exclusive oplock on the node
184cb174861Sjoyce mcintosh * - op->op_oplock_levelII is B_FALSE (LEVEL_II not supported by open cmd.
185cb174861Sjoyce mcintosh * - LEVEL_II oplocks are not supported for the session
186cb174861Sjoyce mcintosh * - a BATCH oplock is requested on a named stream
187bc7c423fSGordon Ross * - there are any range locks on the node (SMB writers)
188cb174861Sjoyce mcintosh * Otherwise, grant LEVEL_II.
1898c10a865Sas200622 *
190cb174861Sjoyce mcintosh * ol->ol_xthread is set to the current thread to lock the oplock against
191cb174861Sjoyce mcintosh * other operations until the acquire response is on the wire. When the
192cb174861Sjoyce mcintosh * acquire response is on the wire, smb_oplock_broadcast() is called to
193cb174861Sjoyce mcintosh * reset ol->ol_xthread and wake any waiting threads.
1948c10a865Sas200622 */
1952c2961f8Sjose borrego void
smb_oplock_acquire(smb_request_t * sr,smb_node_t * node,smb_ofile_t * ofile)196cb174861Sjoyce mcintosh smb_oplock_acquire(smb_request_t *sr, smb_node_t *node, smb_ofile_t *ofile)
1978c10a865Sas200622 {
1982c2961f8Sjose borrego smb_oplock_t *ol;
199cb174861Sjoyce mcintosh smb_oplock_grant_t *og;
200cb174861Sjoyce mcintosh list_t *grants;
201cb174861Sjoyce mcintosh smb_arg_open_t *op;
202cb174861Sjoyce mcintosh smb_tree_t *tree;
203cb174861Sjoyce mcintosh smb_session_t *session;
2048c10a865Sas200622
2052c2961f8Sjose borrego SMB_NODE_VALID(node);
206cb174861Sjoyce mcintosh SMB_OFILE_VALID(ofile);
2078c10a865Sas200622
208cb174861Sjoyce mcintosh ASSERT(node == SMB_OFILE_GET_NODE(ofile));
209bc7c423fSGordon Ross ASSERT(RW_LOCK_HELD(&node->n_lock));
2108c10a865Sas200622
211cb174861Sjoyce mcintosh op = &sr->sr_open;
212cb174861Sjoyce mcintosh tree = SMB_OFILE_GET_TREE(ofile);
213cb174861Sjoyce mcintosh session = SMB_OFILE_GET_SESSION(ofile);
2148c10a865Sas200622
215cb174861Sjoyce mcintosh if (!smb_tree_has_feature(tree, SMB_TREE_OPLOCKS) ||
216cb174861Sjoyce mcintosh (op->op_oplock_level == SMB_OPLOCK_NONE) ||
217cb174861Sjoyce mcintosh ((op->op_oplock_level == SMB_OPLOCK_BATCH) &&
218cb174861Sjoyce mcintosh SMB_IS_STREAM(node))) {
2192c2961f8Sjose borrego op->op_oplock_level = SMB_OPLOCK_NONE;
2202c2961f8Sjose borrego return;
2218c10a865Sas200622 }
2228c10a865Sas200622
2232c2961f8Sjose borrego ol = &node->n_oplock;
224cb174861Sjoyce mcintosh grants = &ol->ol_grants;
2258c10a865Sas200622
226cb174861Sjoyce mcintosh mutex_enter(&ol->ol_mutex);
227fc724630SAlan Wright smb_oplock_wait(node);
2282c2961f8Sjose borrego
229cb174861Sjoyce mcintosh if ((node->n_open_count > 1) ||
230cb174861Sjoyce mcintosh (node->n_opening_count > 1) ||
231cb174861Sjoyce mcintosh smb_vop_other_opens(node->vp, ofile->f_mode)) {
232bc7c423fSGordon Ross /*
233bc7c423fSGordon Ross * There are other opens.
234bc7c423fSGordon Ross */
235cb174861Sjoyce mcintosh if ((!op->op_oplock_levelII) ||
236cb174861Sjoyce mcintosh (!smb_session_levelII_oplocks(session)) ||
237cb174861Sjoyce mcintosh (smb_oplock_exclusive_grant(grants) != NULL) ||
238bc7c423fSGordon Ross (smb_lock_range_access(sr, node, 0, 0, B_FALSE))) {
239bc7c423fSGordon Ross /*
240bc7c423fSGordon Ross * LevelII (shared) oplock not allowed,
241bc7c423fSGordon Ross * so reply with "none".
242bc7c423fSGordon Ross */
2432c2961f8Sjose borrego op->op_oplock_level = SMB_OPLOCK_NONE;
244cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex);
2452c2961f8Sjose borrego return;
2462c2961f8Sjose borrego }
247cb174861Sjoyce mcintosh
248cb174861Sjoyce mcintosh op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
249cb174861Sjoyce mcintosh }
250cb174861Sjoyce mcintosh
2511fdeec65Sjoyce mcintosh og = smb_oplock_set_grant(ofile, op->op_oplock_level);
252cb174861Sjoyce mcintosh if (smb_oplock_insert_grant(node, og) != 0) {
2531fdeec65Sjoyce mcintosh smb_oplock_clear_grant(og);
254cb174861Sjoyce mcintosh op->op_oplock_level = SMB_OPLOCK_NONE;
255cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex);
2562c2961f8Sjose borrego return;
2572c2961f8Sjose borrego }
2588c10a865Sas200622
2592c2961f8Sjose borrego ol->ol_xthread = curthread;
260cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex);
2618c10a865Sas200622 }
2628c10a865Sas200622
2638c10a865Sas200622 /*
2648c10a865Sas200622 * smb_oplock_break
2658c10a865Sas200622 *
266cb174861Sjoyce mcintosh * Break granted oplocks according to the following rules:
267cb174861Sjoyce mcintosh *
268cb174861Sjoyce mcintosh * If there's an exclusive oplock granted on the node
269cb174861Sjoyce mcintosh * - if the BREAK_BATCH flags is specified and the oplock is not
270cb174861Sjoyce mcintosh * a batch oplock, no break is required.
271cb174861Sjoyce mcintosh * - if the session doesn't support LEVEL II oplocks, and 'brk' is
272cb174861Sjoyce mcintosh * BREAK_TO_LEVEL_II, do a BREAK_TO_NONE.
273cb174861Sjoyce mcintosh * - if the oplock is already breaking update the break level (if
274cb174861Sjoyce mcintosh * the requested break is to a lesser level), otherwise send an
275cb174861Sjoyce mcintosh * oplock break.
276cb174861Sjoyce mcintosh * Wait for acknowledgement of the break (unless NOWAIT flag is set)
277cb174861Sjoyce mcintosh *
278cb174861Sjoyce mcintosh * Otherwise:
279cb174861Sjoyce mcintosh * If there are level II oplocks granted on the node, and the flags
280cb174861Sjoyce mcintosh * indicate that they should be broken (BREAK_TO_NONE specified,
281cb174861Sjoyce mcintosh * BREAK_EXCLUSIVE, BREAK_BATCH not specified) queue the levelII
282cb174861Sjoyce mcintosh * break request for asynchronous processing.
2838c10a865Sas200622 *
2842c2961f8Sjose borrego * Returns:
285cb174861Sjoyce mcintosh * 0 - oplock broken (or no break required)
286cb174861Sjoyce mcintosh * EAGAIN - oplock break request sent and would block
287cb174861Sjoyce mcintosh * awaiting the reponse but NOWAIT was specified
288*8622ec45SGordon Ross *
289*8622ec45SGordon Ross * NB: sr == NULL when called by FEM framework.
2908c10a865Sas200622 */
291cb174861Sjoyce mcintosh int
smb_oplock_break(smb_request_t * sr,smb_node_t * node,uint32_t flags)292cb174861Sjoyce mcintosh smb_oplock_break(smb_request_t *sr, smb_node_t *node, uint32_t flags)
293cb174861Sjoyce mcintosh {
294cb174861Sjoyce mcintosh smb_oplock_t *ol;
295cb174861Sjoyce mcintosh smb_oplock_grant_t *og;
296cb174861Sjoyce mcintosh list_t *grants;
297cb174861Sjoyce mcintosh uint32_t timeout;
298cb174861Sjoyce mcintosh uint8_t brk;
299cb174861Sjoyce mcintosh
300cb174861Sjoyce mcintosh SMB_NODE_VALID(node);
301cb174861Sjoyce mcintosh ol = &node->n_oplock;
302cb174861Sjoyce mcintosh grants = &ol->ol_grants;
303cb174861Sjoyce mcintosh
304cb174861Sjoyce mcintosh mutex_enter(&ol->ol_mutex);
305cb174861Sjoyce mcintosh smb_oplock_wait(node);
306cb174861Sjoyce mcintosh
307cb174861Sjoyce mcintosh og = list_head(grants);
308cb174861Sjoyce mcintosh if (og == NULL) {
309cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex);
310cb174861Sjoyce mcintosh return (0);
311cb174861Sjoyce mcintosh }
312cb174861Sjoyce mcintosh
313cb174861Sjoyce mcintosh SMB_OPLOCK_GRANT_VALID(og);
314cb174861Sjoyce mcintosh
315cb174861Sjoyce mcintosh /* break levelII oplocks */
316cb174861Sjoyce mcintosh if (og->og_level == SMB_OPLOCK_LEVEL_II) {
317cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex);
318cb174861Sjoyce mcintosh
319cb174861Sjoyce mcintosh if ((flags & SMB_OPLOCK_BREAK_TO_NONE) &&
320cb174861Sjoyce mcintosh !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) &&
321cb174861Sjoyce mcintosh !(flags & SMB_OPLOCK_BREAK_BATCH)) {
322cb174861Sjoyce mcintosh smb_oplock_break_levelII(node);
323cb174861Sjoyce mcintosh }
324cb174861Sjoyce mcintosh return (0);
325cb174861Sjoyce mcintosh }
326cb174861Sjoyce mcintosh
327cb174861Sjoyce mcintosh /* break exclusive oplock */
328cb174861Sjoyce mcintosh if ((flags & SMB_OPLOCK_BREAK_BATCH) &&
329cb174861Sjoyce mcintosh (og->og_level != SMB_OPLOCK_BATCH)) {
330cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex);
331cb174861Sjoyce mcintosh return (0);
332cb174861Sjoyce mcintosh }
333cb174861Sjoyce mcintosh
334cb174861Sjoyce mcintosh if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) &&
335cb174861Sjoyce mcintosh smb_session_levelII_oplocks(og->og_session)) {
336cb174861Sjoyce mcintosh brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
337cb174861Sjoyce mcintosh } else {
338cb174861Sjoyce mcintosh brk = SMB_OPLOCK_BREAK_TO_NONE;
339cb174861Sjoyce mcintosh }
340cb174861Sjoyce mcintosh
341cb174861Sjoyce mcintosh switch (ol->ol_break) {
342cb174861Sjoyce mcintosh case SMB_OPLOCK_NO_BREAK:
343cb174861Sjoyce mcintosh ol->ol_break = brk;
344cb174861Sjoyce mcintosh smb_session_oplock_break(og->og_session,
345cb174861Sjoyce mcintosh og->og_tid, og->og_fid, brk);
346cb174861Sjoyce mcintosh break;
347cb174861Sjoyce mcintosh case SMB_OPLOCK_BREAK_TO_LEVEL_II:
348cb174861Sjoyce mcintosh if (brk == SMB_OPLOCK_BREAK_TO_NONE)
349cb174861Sjoyce mcintosh ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE;
350cb174861Sjoyce mcintosh break;
351cb174861Sjoyce mcintosh case SMB_OPLOCK_BREAK_TO_NONE:
352cb174861Sjoyce mcintosh default:
353cb174861Sjoyce mcintosh break;
354cb174861Sjoyce mcintosh }
355cb174861Sjoyce mcintosh
356cb174861Sjoyce mcintosh if (flags & SMB_OPLOCK_BREAK_NOWAIT) {
357cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex);
358cb174861Sjoyce mcintosh return (EAGAIN);
359cb174861Sjoyce mcintosh }
360cb174861Sjoyce mcintosh
361cb174861Sjoyce mcintosh if (sr && (sr->session == og->og_session) &&
362cb174861Sjoyce mcintosh (sr->smb_uid == og->og_uid)) {
363cb174861Sjoyce mcintosh timeout = smb_oplock_min_timeout;
364cb174861Sjoyce mcintosh } else {
365cb174861Sjoyce mcintosh timeout = smb_oplock_timeout;
366cb174861Sjoyce mcintosh }
367cb174861Sjoyce mcintosh
368cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex);
369cb174861Sjoyce mcintosh smb_oplock_wait_ack(node, timeout);
370cb174861Sjoyce mcintosh return (0);
371cb174861Sjoyce mcintosh }
372cb174861Sjoyce mcintosh
373cb174861Sjoyce mcintosh /*
374cb174861Sjoyce mcintosh * smb_oplock_break_levelII
375cb174861Sjoyce mcintosh *
376cb174861Sjoyce mcintosh * LevelII (shared) oplock breaks are processed asynchronously.
377cb174861Sjoyce mcintosh * Unlike exclusive oplock breaks, the thread initiating the break
378cb174861Sjoyce mcintosh * is NOT blocked while the request is processed.
379cb174861Sjoyce mcintosh *
380cb174861Sjoyce mcintosh * Create an oplock_break_request and add it to the list for async
381cb174861Sjoyce mcintosh * processing.
382cb174861Sjoyce mcintosh */
383cb174861Sjoyce mcintosh void
smb_oplock_break_levelII(smb_node_t * node)384cb174861Sjoyce mcintosh smb_oplock_break_levelII(smb_node_t *node)
385cb174861Sjoyce mcintosh {
386cb174861Sjoyce mcintosh smb_oplock_break_t *ob;
387cb174861Sjoyce mcintosh
388cb174861Sjoyce mcintosh ob = smb_oplock_create_break(node);
389cb174861Sjoyce mcintosh
390cb174861Sjoyce mcintosh smb_llist_enter(&smb_oplock_breaks, RW_WRITER);
391cb174861Sjoyce mcintosh smb_llist_insert_tail(&smb_oplock_breaks, ob);
392cb174861Sjoyce mcintosh smb_llist_exit(&smb_oplock_breaks);
393cb174861Sjoyce mcintosh
394cb174861Sjoyce mcintosh smb_thread_signal(&smb_oplock_thread);
395cb174861Sjoyce mcintosh }
396cb174861Sjoyce mcintosh
397cb174861Sjoyce mcintosh /*
398cb174861Sjoyce mcintosh * smb_oplock_break_thread
399cb174861Sjoyce mcintosh *
400cb174861Sjoyce mcintosh * The smb_oplock_thread is woken when an oplock break request is
401cb174861Sjoyce mcintosh * added to the list of pending levelII oplock break requests.
402cb174861Sjoyce mcintosh * Gets the oplock break request from the list, processes it and
403cb174861Sjoyce mcintosh * deletes it.
404cb174861Sjoyce mcintosh */
405cb174861Sjoyce mcintosh /*ARGSUSED*/
406cb174861Sjoyce mcintosh static void
smb_oplock_break_thread(smb_thread_t * thread,void * arg)407cb174861Sjoyce mcintosh smb_oplock_break_thread(smb_thread_t *thread, void *arg)
408cb174861Sjoyce mcintosh {
409cb174861Sjoyce mcintosh smb_oplock_break_t *ob;
410cb174861Sjoyce mcintosh
411cb174861Sjoyce mcintosh while (smb_thread_continue(thread)) {
412cb174861Sjoyce mcintosh while ((ob = smb_oplock_get_break()) != NULL) {
413cb174861Sjoyce mcintosh smb_oplock_process_levelII_break(ob->ob_node);
414cb174861Sjoyce mcintosh smb_oplock_delete_break(ob);
415cb174861Sjoyce mcintosh }
416cb174861Sjoyce mcintosh }
417cb174861Sjoyce mcintosh }
418cb174861Sjoyce mcintosh
419cb174861Sjoyce mcintosh /*
420cb174861Sjoyce mcintosh * smb_oplock_get_break
421cb174861Sjoyce mcintosh *
422cb174861Sjoyce mcintosh * Remove and return the next oplock break request from the list
423cb174861Sjoyce mcintosh */
424cb174861Sjoyce mcintosh static smb_oplock_break_t *
smb_oplock_get_break(void)425cb174861Sjoyce mcintosh smb_oplock_get_break(void)
426cb174861Sjoyce mcintosh {
427cb174861Sjoyce mcintosh smb_oplock_break_t *ob;
428cb174861Sjoyce mcintosh
429cb174861Sjoyce mcintosh smb_llist_enter(&smb_oplock_breaks, RW_WRITER);
430cb174861Sjoyce mcintosh if ((ob = smb_llist_head(&smb_oplock_breaks)) != NULL) {
431cb174861Sjoyce mcintosh SMB_OPLOCK_BREAK_VALID(ob);
432cb174861Sjoyce mcintosh smb_llist_remove(&smb_oplock_breaks, ob);
433cb174861Sjoyce mcintosh }
434cb174861Sjoyce mcintosh smb_llist_exit(&smb_oplock_breaks);
435cb174861Sjoyce mcintosh return (ob);
436cb174861Sjoyce mcintosh }
437cb174861Sjoyce mcintosh
438cb174861Sjoyce mcintosh /*
439cb174861Sjoyce mcintosh * smb_oplock_process_levelII_break
440cb174861Sjoyce mcintosh */
441cb174861Sjoyce mcintosh void
smb_oplock_process_levelII_break(smb_node_t * node)442cb174861Sjoyce mcintosh smb_oplock_process_levelII_break(smb_node_t *node)
443cb174861Sjoyce mcintosh {
444cb174861Sjoyce mcintosh smb_oplock_t *ol;
445cb174861Sjoyce mcintosh smb_oplock_grant_t *og;
446cb174861Sjoyce mcintosh list_t *grants;
447cb174861Sjoyce mcintosh
448cb174861Sjoyce mcintosh if (!smb_oplock_levelII)
449cb174861Sjoyce mcintosh return;
450cb174861Sjoyce mcintosh
451cb174861Sjoyce mcintosh ol = &node->n_oplock;
452cb174861Sjoyce mcintosh mutex_enter(&ol->ol_mutex);
453cb174861Sjoyce mcintosh smb_oplock_wait(node);
454cb174861Sjoyce mcintosh grants = &node->n_oplock.ol_grants;
455cb174861Sjoyce mcintosh
456cb174861Sjoyce mcintosh while ((og = list_head(grants)) != NULL) {
457cb174861Sjoyce mcintosh SMB_OPLOCK_GRANT_VALID(og);
458cb174861Sjoyce mcintosh
459cb174861Sjoyce mcintosh if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
460cb174861Sjoyce mcintosh break;
461cb174861Sjoyce mcintosh
462cb174861Sjoyce mcintosh smb_session_oplock_break(og->og_session,
463cb174861Sjoyce mcintosh og->og_tid, og->og_fid, SMB_OPLOCK_BREAK_TO_NONE);
464cb174861Sjoyce mcintosh smb_oplock_remove_grant(node, og);
4651fdeec65Sjoyce mcintosh smb_oplock_clear_grant(og);
466cb174861Sjoyce mcintosh }
467cb174861Sjoyce mcintosh
468cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex);
469cb174861Sjoyce mcintosh }
470cb174861Sjoyce mcintosh
471cb174861Sjoyce mcintosh /*
472cb174861Sjoyce mcintosh * smb_oplock_wait_ack
473cb174861Sjoyce mcintosh *
474cb174861Sjoyce mcintosh * Timed wait for an oplock break acknowledgement (or oplock release).
475cb174861Sjoyce mcintosh */
476cb174861Sjoyce mcintosh static void
smb_oplock_wait_ack(smb_node_t * node,uint32_t timeout)477cb174861Sjoyce mcintosh smb_oplock_wait_ack(smb_node_t *node, uint32_t timeout)
4788c10a865Sas200622 {
4792c2961f8Sjose borrego smb_oplock_t *ol;
4802c2961f8Sjose borrego clock_t time;
4818c10a865Sas200622
4822c2961f8Sjose borrego ol = &node->n_oplock;
483cb174861Sjoyce mcintosh mutex_enter(&ol->ol_mutex);
484cb174861Sjoyce mcintosh time = MSEC_TO_TICK(timeout) + ddi_get_lbolt();
4858c10a865Sas200622
486cb174861Sjoyce mcintosh while (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
487cb174861Sjoyce mcintosh if (cv_timedwait(&ol->ol_cv, &ol->ol_mutex, time) < 0) {
488cb174861Sjoyce mcintosh smb_oplock_timedout(node);
4892c2961f8Sjose borrego cv_broadcast(&ol->ol_cv);
4908c10a865Sas200622 break;
4918c10a865Sas200622 }
4928c10a865Sas200622 }
493cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex);
4948c10a865Sas200622 }
495cb174861Sjoyce mcintosh
496cb174861Sjoyce mcintosh /*
497cb174861Sjoyce mcintosh * smb_oplock_timedout
498cb174861Sjoyce mcintosh *
499cb174861Sjoyce mcintosh * An oplock break has not been acknowledged within timeout
500cb174861Sjoyce mcintosh * 'smb_oplock_timeout'.
501cb174861Sjoyce mcintosh * Set oplock grant to the desired break level.
502cb174861Sjoyce mcintosh */
503cb174861Sjoyce mcintosh static void
smb_oplock_timedout(smb_node_t * node)504cb174861Sjoyce mcintosh smb_oplock_timedout(smb_node_t *node)
505cb174861Sjoyce mcintosh {
506cb174861Sjoyce mcintosh smb_oplock_t *ol;
507cb174861Sjoyce mcintosh smb_oplock_grant_t *og;
508cb174861Sjoyce mcintosh list_t *grants;
509cb174861Sjoyce mcintosh
510cb174861Sjoyce mcintosh ol = &node->n_oplock;
511cb174861Sjoyce mcintosh grants = &ol->ol_grants;
512cb174861Sjoyce mcintosh
513cb174861Sjoyce mcintosh ASSERT(MUTEX_HELD(&ol->ol_mutex));
514cb174861Sjoyce mcintosh
515cb174861Sjoyce mcintosh og = smb_oplock_exclusive_grant(grants);
516cb174861Sjoyce mcintosh if (og) {
517cb174861Sjoyce mcintosh switch (ol->ol_break) {
518cb174861Sjoyce mcintosh case SMB_OPLOCK_BREAK_TO_NONE:
519cb174861Sjoyce mcintosh og->og_level = SMB_OPLOCK_NONE;
520cb174861Sjoyce mcintosh smb_oplock_remove_grant(node, og);
5211fdeec65Sjoyce mcintosh smb_oplock_clear_grant(og);
522cb174861Sjoyce mcintosh break;
523cb174861Sjoyce mcintosh case SMB_OPLOCK_BREAK_TO_LEVEL_II:
524cb174861Sjoyce mcintosh og->og_level = SMB_OPLOCK_LEVEL_II;
525cb174861Sjoyce mcintosh break;
526cb174861Sjoyce mcintosh default:
527cb174861Sjoyce mcintosh SMB_PANIC();
528cb174861Sjoyce mcintosh }
529cb174861Sjoyce mcintosh }
530cb174861Sjoyce mcintosh ol->ol_break = SMB_OPLOCK_NO_BREAK;
5318c10a865Sas200622 }
5328c10a865Sas200622
5338c10a865Sas200622 /*
5348c10a865Sas200622 * smb_oplock_release
5358c10a865Sas200622 *
536cb174861Sjoyce mcintosh * Release the oplock granted on ofile 'of'.
537cb174861Sjoyce mcintosh * Wake any threads waiting for an oplock break acknowledgement for
538cb174861Sjoyce mcintosh * this oplock.
539cb174861Sjoyce mcintosh * This is called when the ofile is being closed.
5408c10a865Sas200622 */
5412c2961f8Sjose borrego void
smb_oplock_release(smb_node_t * node,smb_ofile_t * of)5422c2961f8Sjose borrego smb_oplock_release(smb_node_t *node, smb_ofile_t *of)
5438c10a865Sas200622 {
5442c2961f8Sjose borrego smb_oplock_t *ol;
545cb174861Sjoyce mcintosh smb_oplock_grant_t *og;
5468c10a865Sas200622
5472c2961f8Sjose borrego ol = &node->n_oplock;
548cb174861Sjoyce mcintosh mutex_enter(&ol->ol_mutex);
549fc724630SAlan Wright smb_oplock_wait(node);
5502c2961f8Sjose borrego
5511fdeec65Sjoyce mcintosh og = smb_oplock_get_grant(ol, of);
552cb174861Sjoyce mcintosh if (og) {
553cb174861Sjoyce mcintosh smb_oplock_remove_grant(node, og);
5541fdeec65Sjoyce mcintosh smb_oplock_clear_grant(og);
555cb174861Sjoyce mcintosh
556cb174861Sjoyce mcintosh if (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
557cb174861Sjoyce mcintosh ol->ol_break = SMB_OPLOCK_NO_BREAK;
5582c2961f8Sjose borrego cv_broadcast(&ol->ol_cv);
5592c2961f8Sjose borrego }
5602c2961f8Sjose borrego }
561cb174861Sjoyce mcintosh
562cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex);
5638c10a865Sas200622 }
5648c10a865Sas200622
5658c10a865Sas200622 /*
566cb174861Sjoyce mcintosh * smb_oplock_ack
5678c10a865Sas200622 *
568cb174861Sjoyce mcintosh * Process oplock acknowledgement received for ofile 'of'.
569cb174861Sjoyce mcintosh * - oplock.ol_break is the break level that was requested.
570cb174861Sjoyce mcintosh * - brk is the break level being acknowledged by the client.
571cb174861Sjoyce mcintosh *
572cb174861Sjoyce mcintosh * Update the oplock grant level to the lesser of ol_break and brk.
573cb174861Sjoyce mcintosh * If the grant is now SMB_OPLOCK_NONE, remove the grant from the
574cb174861Sjoyce mcintosh * oplock's grant list and delete it.
575cb174861Sjoyce mcintosh * If the requested break level (ol_break) was NONE and the brk is
576cb174861Sjoyce mcintosh * LEVEL_II, send another oplock break (NONE). Do not wait for an
577cb174861Sjoyce mcintosh * acknowledgement.
578cb174861Sjoyce mcintosh * Wake any threads waiting for the oplock break acknowledgement.
5798c10a865Sas200622 */
580cb174861Sjoyce mcintosh void
smb_oplock_ack(smb_node_t * node,smb_ofile_t * of,uint8_t brk)581cb174861Sjoyce mcintosh smb_oplock_ack(smb_node_t *node, smb_ofile_t *of, uint8_t brk)
5828c10a865Sas200622 {
583cb174861Sjoyce mcintosh smb_oplock_t *ol;
584cb174861Sjoyce mcintosh smb_oplock_grant_t *og;
585cb174861Sjoyce mcintosh boolean_t brk_to_none = B_FALSE;
5868c10a865Sas200622
587cb174861Sjoyce mcintosh ol = &node->n_oplock;
588cb174861Sjoyce mcintosh mutex_enter(&ol->ol_mutex);
589fc724630SAlan Wright smb_oplock_wait(node);
5902c2961f8Sjose borrego
591cb174861Sjoyce mcintosh if ((ol->ol_break == SMB_OPLOCK_NO_BREAK) ||
5921fdeec65Sjoyce mcintosh ((og = smb_oplock_get_grant(ol, of)) == NULL)) {
593cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex);
594cb174861Sjoyce mcintosh return;
5958c10a865Sas200622 }
5968c10a865Sas200622
597cb174861Sjoyce mcintosh switch (brk) {
598cb174861Sjoyce mcintosh case SMB_OPLOCK_BREAK_TO_NONE:
599cb174861Sjoyce mcintosh og->og_level = SMB_OPLOCK_NONE;
6002c2961f8Sjose borrego break;
601cb174861Sjoyce mcintosh case SMB_OPLOCK_BREAK_TO_LEVEL_II:
602cb174861Sjoyce mcintosh if (ol->ol_break == SMB_OPLOCK_BREAK_TO_LEVEL_II) {
603cb174861Sjoyce mcintosh og->og_level = SMB_OPLOCK_LEVEL_II;
604cb174861Sjoyce mcintosh } else {
605cb174861Sjoyce mcintosh /* SMB_OPLOCK_BREAK_TO_NONE */
606cb174861Sjoyce mcintosh og->og_level = SMB_OPLOCK_NONE;
607cb174861Sjoyce mcintosh brk_to_none = B_TRUE;
6082c2961f8Sjose borrego }
6092c2961f8Sjose borrego break;
6102c2961f8Sjose borrego default:
6112c2961f8Sjose borrego SMB_PANIC();
6122c2961f8Sjose borrego }
613cb174861Sjoyce mcintosh
614cb174861Sjoyce mcintosh if (og->og_level == SMB_OPLOCK_NONE) {
615cb174861Sjoyce mcintosh smb_oplock_remove_grant(node, og);
6161fdeec65Sjoyce mcintosh smb_oplock_clear_grant(og);
617cb174861Sjoyce mcintosh }
618cb174861Sjoyce mcintosh
619cb174861Sjoyce mcintosh ol->ol_break = SMB_OPLOCK_NO_BREAK;
620cb174861Sjoyce mcintosh cv_broadcast(&ol->ol_cv);
621cb174861Sjoyce mcintosh
622cb174861Sjoyce mcintosh if (brk_to_none) {
623cb174861Sjoyce mcintosh smb_session_oplock_break(of->f_session,
624cb174861Sjoyce mcintosh of->f_tree->t_tid, of->f_fid,
625cb174861Sjoyce mcintosh SMB_OPLOCK_BREAK_TO_NONE);
626cb174861Sjoyce mcintosh }
627cb174861Sjoyce mcintosh
628cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex);
6298c10a865Sas200622 }
6308c10a865Sas200622
6312c2961f8Sjose borrego /*
632fc724630SAlan Wright * smb_oplock_broadcast
6332c2961f8Sjose borrego *
634cb174861Sjoyce mcintosh * ol->ol_xthread identifies the thread that was performing an oplock
635cb174861Sjoyce mcintosh * acquire. Other threads may be blocked awaiting completion of the
636cb174861Sjoyce mcintosh * acquire.
637cb174861Sjoyce mcintosh * If the calling thread is ol_ol_xthread, wake any waiting threads.
6382c2961f8Sjose borrego */
639cb174861Sjoyce mcintosh void
smb_oplock_broadcast(smb_node_t * node)640fc724630SAlan Wright smb_oplock_broadcast(smb_node_t *node)
6412c2961f8Sjose borrego {
6422c2961f8Sjose borrego smb_oplock_t *ol;
6432c2961f8Sjose borrego
6442c2961f8Sjose borrego SMB_NODE_VALID(node);
6452c2961f8Sjose borrego ol = &node->n_oplock;
6462c2961f8Sjose borrego
647cb174861Sjoyce mcintosh mutex_enter(&ol->ol_mutex);
6482c2961f8Sjose borrego if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) {
6492c2961f8Sjose borrego ol->ol_xthread = NULL;
6502c2961f8Sjose borrego cv_broadcast(&ol->ol_cv);
6512c2961f8Sjose borrego }
652cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex);
6538c10a865Sas200622 }
6548c10a865Sas200622
6552c2961f8Sjose borrego /*
6562c2961f8Sjose borrego * smb_oplock_wait
6572c2961f8Sjose borrego *
658cb174861Sjoyce mcintosh * Wait for the completion of an oplock acquire.
659cb174861Sjoyce mcintosh * If ol_xthread is not NULL and doesn't contain the pointer to the
660cb174861Sjoyce mcintosh * context of the calling thread, the caller will sleep until the
661cb174861Sjoyce mcintosh * ol_xthread is reset to NULL (via smb_oplock_broadcast()).
6622c2961f8Sjose borrego */
6632c2961f8Sjose borrego static void
smb_oplock_wait(smb_node_t * node)664fc724630SAlan Wright smb_oplock_wait(smb_node_t *node)
6652c2961f8Sjose borrego {
666cb174861Sjoyce mcintosh smb_oplock_t *ol;
667cb174861Sjoyce mcintosh
668cb174861Sjoyce mcintosh ol = &node->n_oplock;
669cb174861Sjoyce mcintosh ASSERT(MUTEX_HELD(&ol->ol_mutex));
6702c2961f8Sjose borrego
6712c2961f8Sjose borrego if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) {
6722c2961f8Sjose borrego while (ol->ol_xthread != NULL)
673cb174861Sjoyce mcintosh cv_wait(&ol->ol_cv, &ol->ol_mutex);
6742c2961f8Sjose borrego }
6758c10a865Sas200622 }
676cb174861Sjoyce mcintosh
677cb174861Sjoyce mcintosh /*
6781fdeec65Sjoyce mcintosh * smb_oplock_set_grant
679cb174861Sjoyce mcintosh */
680cb174861Sjoyce mcintosh static smb_oplock_grant_t *
smb_oplock_set_grant(smb_ofile_t * of,uint8_t level)6811fdeec65Sjoyce mcintosh smb_oplock_set_grant(smb_ofile_t *of, uint8_t level)
682cb174861Sjoyce mcintosh {
683cb174861Sjoyce mcintosh smb_oplock_grant_t *og;
684cb174861Sjoyce mcintosh
6851fdeec65Sjoyce mcintosh og = &of->f_oplock_grant;
6861fdeec65Sjoyce mcintosh
687cb174861Sjoyce mcintosh og->og_magic = SMB_OPLOCK_GRANT_MAGIC;
688cb174861Sjoyce mcintosh og->og_level = level;
689cb174861Sjoyce mcintosh og->og_ofile = of;
690cb174861Sjoyce mcintosh og->og_fid = of->f_fid;
691cb174861Sjoyce mcintosh og->og_tid = of->f_tree->t_tid;
692cb174861Sjoyce mcintosh og->og_uid = of->f_user->u_uid;
693cb174861Sjoyce mcintosh og->og_session = of->f_session;
694cb174861Sjoyce mcintosh return (og);
695cb174861Sjoyce mcintosh }
696cb174861Sjoyce mcintosh
697cb174861Sjoyce mcintosh /*
6981fdeec65Sjoyce mcintosh * smb_oplock_clear_grant
699cb174861Sjoyce mcintosh */
700cb174861Sjoyce mcintosh void
smb_oplock_clear_grant(smb_oplock_grant_t * og)7011fdeec65Sjoyce mcintosh smb_oplock_clear_grant(smb_oplock_grant_t *og)
702cb174861Sjoyce mcintosh {
7031fdeec65Sjoyce mcintosh bzero(og, sizeof (smb_oplock_grant_t));
704cb174861Sjoyce mcintosh }
705cb174861Sjoyce mcintosh
706cb174861Sjoyce mcintosh /*
707cb174861Sjoyce mcintosh * smb_oplock_insert_grant
708cb174861Sjoyce mcintosh *
709cb174861Sjoyce mcintosh * If there are no grants in the oplock's list install the fem
710cb174861Sjoyce mcintosh * monitor.
711cb174861Sjoyce mcintosh * Insert the grant into the list and increment the grant count.
712cb174861Sjoyce mcintosh */
713cb174861Sjoyce mcintosh static int
smb_oplock_insert_grant(smb_node_t * node,smb_oplock_grant_t * og)714cb174861Sjoyce mcintosh smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og)
715cb174861Sjoyce mcintosh {
716cb174861Sjoyce mcintosh smb_oplock_t *ol = &node->n_oplock;
717cb174861Sjoyce mcintosh
718cb174861Sjoyce mcintosh ASSERT(MUTEX_HELD(&ol->ol_mutex));
719cb174861Sjoyce mcintosh
720cb174861Sjoyce mcintosh if (ol->ol_count == 0) {
721cb174861Sjoyce mcintosh if (smb_oplock_install_fem(node) != 0)
722cb174861Sjoyce mcintosh return (-1);
723cb174861Sjoyce mcintosh }
724cb174861Sjoyce mcintosh
725cb174861Sjoyce mcintosh list_insert_tail(&ol->ol_grants, og);
726cb174861Sjoyce mcintosh ++ol->ol_count;
727cb174861Sjoyce mcintosh return (0);
728cb174861Sjoyce mcintosh }
729cb174861Sjoyce mcintosh
730cb174861Sjoyce mcintosh /*
731cb174861Sjoyce mcintosh * smb_oplock_remove_grant
732cb174861Sjoyce mcintosh *
733cb174861Sjoyce mcintosh * Remove the oplock grant from the list, decrement the grant count
734cb174861Sjoyce mcintosh * and, if there are no other grants in the list, uninstall the fem
735cb174861Sjoyce mcintosh * monitor.
736cb174861Sjoyce mcintosh */
737cb174861Sjoyce mcintosh static void
smb_oplock_remove_grant(smb_node_t * node,smb_oplock_grant_t * og)738cb174861Sjoyce mcintosh smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og)
739cb174861Sjoyce mcintosh {
740cb174861Sjoyce mcintosh smb_oplock_t *ol = &node->n_oplock;
741cb174861Sjoyce mcintosh
742cb174861Sjoyce mcintosh ASSERT(MUTEX_HELD(&ol->ol_mutex));
743cb174861Sjoyce mcintosh ASSERT(ol->ol_count > 0);
744cb174861Sjoyce mcintosh
745cb174861Sjoyce mcintosh list_remove(&ol->ol_grants, og);
746cb174861Sjoyce mcintosh if (--ol->ol_count == 0)
747cb174861Sjoyce mcintosh smb_oplock_uninstall_fem(node);
748cb174861Sjoyce mcintosh }
749cb174861Sjoyce mcintosh
750cb174861Sjoyce mcintosh /*
751cb174861Sjoyce mcintosh * smb_oplock_exclusive_grant
752cb174861Sjoyce mcintosh *
753cb174861Sjoyce mcintosh * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists,
754cb174861Sjoyce mcintosh * return it. Otherwise return NULL.
755cb174861Sjoyce mcintosh */
756cb174861Sjoyce mcintosh static smb_oplock_grant_t *
smb_oplock_exclusive_grant(list_t * grants)757cb174861Sjoyce mcintosh smb_oplock_exclusive_grant(list_t *grants)
758cb174861Sjoyce mcintosh {
759cb174861Sjoyce mcintosh smb_oplock_grant_t *og;
760cb174861Sjoyce mcintosh
761cb174861Sjoyce mcintosh og = list_head(grants);
762cb174861Sjoyce mcintosh if (og) {
763cb174861Sjoyce mcintosh SMB_OPLOCK_GRANT_VALID(og);
764cb174861Sjoyce mcintosh if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
765cb174861Sjoyce mcintosh return (og);
766cb174861Sjoyce mcintosh }
767cb174861Sjoyce mcintosh return (NULL);
768cb174861Sjoyce mcintosh }
769cb174861Sjoyce mcintosh
770cb174861Sjoyce mcintosh /*
7711fdeec65Sjoyce mcintosh * smb_oplock_get_grant
772cb174861Sjoyce mcintosh *
773cb174861Sjoyce mcintosh * Find oplock grant corresponding to the specified ofile.
774cb174861Sjoyce mcintosh */
775cb174861Sjoyce mcintosh static smb_oplock_grant_t *
smb_oplock_get_grant(smb_oplock_t * ol,smb_ofile_t * ofile)7761fdeec65Sjoyce mcintosh smb_oplock_get_grant(smb_oplock_t *ol, smb_ofile_t *ofile)
777cb174861Sjoyce mcintosh {
7781fdeec65Sjoyce mcintosh ASSERT(MUTEX_HELD(&ol->ol_mutex));
779cb174861Sjoyce mcintosh
7801fdeec65Sjoyce mcintosh if (SMB_OFILE_OPLOCK_GRANTED(ofile))
7811fdeec65Sjoyce mcintosh return (&ofile->f_oplock_grant);
7821fdeec65Sjoyce mcintosh else
7831fdeec65Sjoyce mcintosh return (NULL);
784cb174861Sjoyce mcintosh }
785cb174861Sjoyce mcintosh
786cb174861Sjoyce mcintosh /*
787cb174861Sjoyce mcintosh * smb_oplock_create_break
788cb174861Sjoyce mcintosh */
789cb174861Sjoyce mcintosh static smb_oplock_break_t *
smb_oplock_create_break(smb_node_t * node)790cb174861Sjoyce mcintosh smb_oplock_create_break(smb_node_t *node)
791cb174861Sjoyce mcintosh {
792cb174861Sjoyce mcintosh smb_oplock_break_t *ob;
793cb174861Sjoyce mcintosh
794cb174861Sjoyce mcintosh ob = kmem_cache_alloc(smb_oplock_break_cache, KM_SLEEP);
795cb174861Sjoyce mcintosh
796cb174861Sjoyce mcintosh smb_node_ref(node);
797cb174861Sjoyce mcintosh ob->ob_magic = SMB_OPLOCK_BREAK_MAGIC;
798cb174861Sjoyce mcintosh ob->ob_node = node;
799cb174861Sjoyce mcintosh
800cb174861Sjoyce mcintosh return (ob);
801cb174861Sjoyce mcintosh }
802cb174861Sjoyce mcintosh
803cb174861Sjoyce mcintosh /*
804cb174861Sjoyce mcintosh * smb_oplock_delete_break
805cb174861Sjoyce mcintosh */
806cb174861Sjoyce mcintosh static void
smb_oplock_delete_break(smb_oplock_break_t * ob)807cb174861Sjoyce mcintosh smb_oplock_delete_break(smb_oplock_break_t *ob)
808cb174861Sjoyce mcintosh {
809cb174861Sjoyce mcintosh smb_node_release(ob->ob_node);
810cb174861Sjoyce mcintosh kmem_cache_free(smb_oplock_break_cache, ob);
811cb174861Sjoyce mcintosh }
812