xref: /titanic_41/usr/src/uts/common/fs/smbsrv/smb_oplock.c (revision 09bbc1382f9244fdbb4dfab9126fa50826c93228)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * smb_oplock_wait / smb_oplock_broadcast
28  * When an oplock is being acquired, we must ensure that the acquisition
29  * response is submitted to the network stack before any other operation
30  * is permitted on the oplock.
31  * In smb_oplock_acquire, oplock.ol_xthread is set to point to the worker
32  * thread processing the command that is granting the oplock.
33  * Other threads accessing the oplock will be suspended in smb_oplock_wait().
34  * They will be awakened when the worker thread referenced in 'ol_xthread'
35  * calls smb_oplock_broadcast().
36  *
37  * The purpose of this mechanism is to prevent another thread from
38  * triggering an oplock break before the response conveying the grant
39  * has been sent.
40  */
41 
42 #include <smbsrv/smb_kproto.h>
43 #include <sys/nbmlock.h>
44 #include <inet/tcp.h>
45 
46 #define	SMB_OPLOCK_IS_EXCLUSIVE(level)		\
47 	(((level) == SMB_OPLOCK_EXCLUSIVE) ||	\
48 	((level) == SMB_OPLOCK_BATCH))
49 
50 static int smb_oplock_install_fem(smb_node_t *);
51 static void smb_oplock_uninstall_fem(smb_node_t *);
52 
53 static void smb_oplock_wait(smb_node_t *);
54 static void smb_oplock_wait_ack(smb_node_t *, uint32_t);
55 static void smb_oplock_timedout(smb_node_t *);
56 
57 static smb_oplock_grant_t *smb_oplock_set_grant(smb_ofile_t *, uint8_t);
58 void smb_oplock_clear_grant(smb_oplock_grant_t *);
59 static int smb_oplock_insert_grant(smb_node_t *, smb_oplock_grant_t *);
60 static void smb_oplock_remove_grant(smb_node_t *, smb_oplock_grant_t *);
61 static smb_oplock_grant_t *smb_oplock_exclusive_grant(list_t *);
62 static smb_oplock_grant_t *smb_oplock_get_grant(smb_oplock_t *, smb_ofile_t *);
63 
64 static smb_oplock_break_t *smb_oplock_create_break(smb_node_t *);
65 static smb_oplock_break_t *smb_oplock_get_break(void);
66 static void smb_oplock_delete_break(smb_oplock_break_t *);
67 static void smb_oplock_process_levelII_break(smb_node_t *);
68 
69 static void smb_oplock_break_thread();
70 
71 /* levelII oplock break requests (smb_oplock_break_t) */
72 static boolean_t	smb_oplock_initialized = B_FALSE;
73 static kmem_cache_t	*smb_oplock_break_cache = NULL;
74 static smb_llist_t	smb_oplock_breaks;
75 static smb_thread_t	smb_oplock_thread;
76 /* shared by all zones */
77 
78 /*
79  * smb_oplock_init
80  *
81  * This function is not multi-thread safe. The caller must make sure only one
82  * thread makes the call.
83  */
84 int
85 smb_oplock_init(void)
86 {
87 	int rc;
88 
89 	if (smb_oplock_initialized)
90 		return (0);
91 
92 	smb_oplock_break_cache = kmem_cache_create("smb_oplock_break_cache",
93 	    sizeof (smb_oplock_break_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
94 
95 	smb_llist_constructor(&smb_oplock_breaks, sizeof (smb_oplock_break_t),
96 	    offsetof(smb_oplock_break_t, ob_lnd));
97 
98 	smb_thread_init(&smb_oplock_thread, "smb_thread_oplock_break",
99 	    smb_oplock_break_thread, NULL, smbsrv_notify_pri);
100 
101 	rc = smb_thread_start(&smb_oplock_thread);
102 	if (rc != 0) {
103 		smb_thread_destroy(&smb_oplock_thread);
104 		smb_llist_destructor(&smb_oplock_breaks);
105 		kmem_cache_destroy(smb_oplock_break_cache);
106 		return (rc);
107 	}
108 
109 	smb_oplock_initialized = B_TRUE;
110 	return (0);
111 }
112 
113 /*
114  * smb_oplock_fini
115  * This function is not multi-thread safe. The caller must make sure only one
116  * thread makes the call.
117  */
118 void
119 smb_oplock_fini(void)
120 {
121 	smb_oplock_break_t	*ob;
122 
123 	if (!smb_oplock_initialized)
124 		return;
125 
126 	smb_thread_stop(&smb_oplock_thread);
127 	smb_thread_destroy(&smb_oplock_thread);
128 
129 	while ((ob = smb_llist_head(&smb_oplock_breaks)) != NULL) {
130 		SMB_OPLOCK_BREAK_VALID(ob);
131 		smb_llist_remove(&smb_oplock_breaks, ob);
132 		smb_oplock_delete_break(ob);
133 	}
134 	smb_llist_destructor(&smb_oplock_breaks);
135 
136 	kmem_cache_destroy(smb_oplock_break_cache);
137 }
138 
139 /*
140  * smb_oplock_install_fem
141  * Install fem monitor for cross protocol oplock breaking.
142  */
143 static int
144 smb_oplock_install_fem(smb_node_t *node)
145 {
146 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
147 
148 	if (node->n_oplock.ol_fem == B_FALSE) {
149 		if (smb_fem_oplock_install(node) != 0) {
150 			cmn_err(CE_NOTE, "No oplock granted: "
151 			    "failed to install fem monitor %s",
152 			    node->vp->v_path);
153 			return (-1);
154 		}
155 		node->n_oplock.ol_fem = B_TRUE;
156 	}
157 	return (0);
158 }
159 
160 /*
161  * smb_oplock_uninstall_fem
162  * Uninstall fem monitor for cross protocol oplock breaking.
163  */
164 static void
165 smb_oplock_uninstall_fem(smb_node_t *node)
166 {
167 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
168 
169 	if (node->n_oplock.ol_fem) {
170 		smb_fem_oplock_uninstall(node);
171 		node->n_oplock.ol_fem = B_FALSE;
172 	}
173 }
174 
175 /*
176  * smb_oplock_acquire
177  *
178  * Attempt to acquire an oplock. Clients will request EXCLUSIVE or BATCH,
179  * but might only be granted LEVEL_II or NONE.
180  *
181  * If oplocks are not supported on the tree, or node, grant NONE.
182  * If nobody else has the file open, grant the requested level.
183  * If any of the following are true, grant NONE:
184  * - there is an exclusive oplock on the node
185  * - op->op_oplock_levelII is B_FALSE (LEVEL_II not supported by open cmd.
186  * - LEVEL_II oplocks are not supported for the session
187  * - a BATCH oplock is requested on a named stream
188  * - there are any range locks on the node (SMB writers)
189  * Otherwise, grant LEVEL_II.
190  *
191  * ol->ol_xthread is set to the current thread to lock the oplock against
192  * other operations until the acquire response is on the wire. When the
193  * acquire response is on the wire, smb_oplock_broadcast() is called to
194  * reset ol->ol_xthread and wake any waiting threads.
195  */
196 void
197 smb_oplock_acquire(smb_request_t *sr, smb_node_t *node, smb_ofile_t *ofile)
198 {
199 	smb_oplock_t		*ol;
200 	smb_oplock_grant_t	*og;
201 	list_t			*grants;
202 	smb_arg_open_t		*op;
203 	smb_tree_t		*tree;
204 	smb_session_t		*session;
205 
206 	SMB_NODE_VALID(node);
207 	SMB_OFILE_VALID(ofile);
208 
209 	ASSERT(node == SMB_OFILE_GET_NODE(ofile));
210 	ASSERT(RW_LOCK_HELD(&node->n_lock));
211 
212 	op = &sr->sr_open;
213 	tree = SMB_OFILE_GET_TREE(ofile);
214 	session = SMB_OFILE_GET_SESSION(ofile);
215 
216 	if (!smb_tree_has_feature(tree, SMB_TREE_OPLOCKS) ||
217 	    (op->op_oplock_level == SMB_OPLOCK_NONE) ||
218 	    ((op->op_oplock_level == SMB_OPLOCK_BATCH) &&
219 	    SMB_IS_STREAM(node))) {
220 		op->op_oplock_level = SMB_OPLOCK_NONE;
221 		return;
222 	}
223 
224 	ol = &node->n_oplock;
225 	grants = &ol->ol_grants;
226 
227 	mutex_enter(&ol->ol_mutex);
228 	smb_oplock_wait(node);
229 
230 	if ((node->n_open_count > 1) ||
231 	    (node->n_opening_count > 1) ||
232 	    smb_vop_other_opens(node->vp, ofile->f_mode)) {
233 		/*
234 		 * There are other opens.
235 		 */
236 		if ((!op->op_oplock_levelII) ||
237 		    (!smb_session_levelII_oplocks(session)) ||
238 		    (smb_oplock_exclusive_grant(grants) != NULL) ||
239 		    (smb_lock_range_access(sr, node, 0, 0, B_FALSE))) {
240 			/*
241 			 * LevelII (shared) oplock not allowed,
242 			 * so reply with "none".
243 			 */
244 			op->op_oplock_level = SMB_OPLOCK_NONE;
245 			mutex_exit(&ol->ol_mutex);
246 			return;
247 		}
248 
249 		op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
250 	}
251 
252 	og = smb_oplock_set_grant(ofile, op->op_oplock_level);
253 	if (smb_oplock_insert_grant(node, og) != 0) {
254 		smb_oplock_clear_grant(og);
255 		op->op_oplock_level = SMB_OPLOCK_NONE;
256 		mutex_exit(&ol->ol_mutex);
257 		return;
258 	}
259 
260 	ol->ol_xthread = curthread;
261 	mutex_exit(&ol->ol_mutex);
262 }
263 
264 /*
265  * smb_oplock_break
266  *
267  * Break granted oplocks according to the following rules:
268  *
269  * If there's an exclusive oplock granted on the node
270  *  - if the BREAK_BATCH flags is specified and the oplock is not
271  *    a batch oplock, no break is required.
272  *  - if the session doesn't support LEVEL II oplocks, and 'brk' is
273  *    BREAK_TO_LEVEL_II, do a BREAK_TO_NONE.
274  *  - if the oplock is already breaking update the break level (if
275  *    the requested break is to a lesser level), otherwise send an
276  *    oplock break.
277  *    Wait for acknowledgement of the break (unless NOWAIT flag is set)
278  *
279  * Otherwise:
280  * If there are level II oplocks granted on the node, and the flags
281  * indicate that they should be broken (BREAK_TO_NONE specified,
282  * BREAK_EXCLUSIVE, BREAK_BATCH not specified) queue the levelII
283  * break request for asynchronous processing.
284  *
285  * Returns:
286  *       0 - oplock broken (or no break required)
287  *  EAGAIN - oplock break request sent and would block
288  *           awaiting the reponse but NOWAIT was specified
289  *
290  * NB: sr == NULL when called by FEM framework.
291  */
292 int
293 smb_oplock_break(smb_request_t *sr, smb_node_t *node, uint32_t flags)
294 {
295 	smb_oplock_t		*ol;
296 	smb_oplock_grant_t	*og;
297 	list_t			*grants;
298 	uint32_t		timeout;
299 	uint8_t			brk;
300 
301 	SMB_NODE_VALID(node);
302 	ol = &node->n_oplock;
303 	grants = &ol->ol_grants;
304 
305 	mutex_enter(&ol->ol_mutex);
306 	smb_oplock_wait(node);
307 
308 	og = list_head(grants);
309 	if (og == NULL) {
310 		mutex_exit(&ol->ol_mutex);
311 		return (0);
312 	}
313 
314 	SMB_OPLOCK_GRANT_VALID(og);
315 
316 	/* break levelII oplocks */
317 	if (og->og_level == SMB_OPLOCK_LEVEL_II) {
318 		mutex_exit(&ol->ol_mutex);
319 
320 		if ((flags & SMB_OPLOCK_BREAK_TO_NONE) &&
321 		    !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) &&
322 		    !(flags & SMB_OPLOCK_BREAK_BATCH))  {
323 			smb_oplock_break_levelII(node);
324 		}
325 		return (0);
326 	}
327 
328 	/* break exclusive oplock */
329 	if ((flags & SMB_OPLOCK_BREAK_BATCH) &&
330 	    (og->og_level != SMB_OPLOCK_BATCH)) {
331 		mutex_exit(&ol->ol_mutex);
332 		return (0);
333 	}
334 
335 	if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) &&
336 	    smb_session_levelII_oplocks(og->og_session)) {
337 		brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
338 	} else {
339 		brk = SMB_OPLOCK_BREAK_TO_NONE;
340 	}
341 
342 	switch (ol->ol_break) {
343 	case SMB_OPLOCK_NO_BREAK:
344 		ol->ol_break = brk;
345 		smb_session_oplock_break(og->og_session,
346 		    og->og_tid, og->og_fid, brk);
347 		break;
348 	case SMB_OPLOCK_BREAK_TO_LEVEL_II:
349 		if (brk == SMB_OPLOCK_BREAK_TO_NONE)
350 			ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE;
351 		break;
352 	case SMB_OPLOCK_BREAK_TO_NONE:
353 	default:
354 		break;
355 	}
356 
357 	if (flags & SMB_OPLOCK_BREAK_NOWAIT) {
358 		mutex_exit(&ol->ol_mutex);
359 		return (EAGAIN);
360 	}
361 
362 	if (sr && (sr->session == og->og_session) &&
363 	    (sr->smb_uid == og->og_uid)) {
364 		timeout = smb_oplock_min_timeout;
365 	} else {
366 		timeout = smb_oplock_timeout;
367 	}
368 
369 	mutex_exit(&ol->ol_mutex);
370 	smb_oplock_wait_ack(node, timeout);
371 	return (0);
372 }
373 
374 /*
375  * smb_oplock_break_levelII
376  *
377  * LevelII (shared) oplock breaks are processed asynchronously.
378  * Unlike exclusive oplock breaks, the thread initiating the break
379  * is NOT blocked while the request is processed.
380  *
381  * Create an oplock_break_request and add it to the list for async
382  * processing.
383  */
384 void
385 smb_oplock_break_levelII(smb_node_t *node)
386 {
387 	smb_oplock_break_t	*ob;
388 
389 	ob = smb_oplock_create_break(node);
390 
391 	smb_llist_enter(&smb_oplock_breaks, RW_WRITER);
392 	smb_llist_insert_tail(&smb_oplock_breaks, ob);
393 	smb_llist_exit(&smb_oplock_breaks);
394 
395 	smb_thread_signal(&smb_oplock_thread);
396 }
397 
398 /*
399  * smb_oplock_break_thread
400  *
401  * The smb_oplock_thread is woken when an oplock break request is
402  * added to the list of pending levelII oplock break requests.
403  * Gets the oplock break request from the list, processes it and
404  * deletes it.
405  */
406 /*ARGSUSED*/
407 static void
408 smb_oplock_break_thread(smb_thread_t *thread, void *arg)
409 {
410 	smb_oplock_break_t	*ob;
411 
412 	while (smb_thread_continue(thread)) {
413 		while ((ob = smb_oplock_get_break()) != NULL) {
414 			smb_oplock_process_levelII_break(ob->ob_node);
415 			smb_oplock_delete_break(ob);
416 		}
417 	}
418 }
419 
420 /*
421  * smb_oplock_get_break
422  *
423  * Remove and return the next oplock break request from the list
424  */
425 static smb_oplock_break_t *
426 smb_oplock_get_break(void)
427 {
428 	smb_oplock_break_t	*ob;
429 
430 	smb_llist_enter(&smb_oplock_breaks, RW_WRITER);
431 	if ((ob = smb_llist_head(&smb_oplock_breaks)) != NULL) {
432 		SMB_OPLOCK_BREAK_VALID(ob);
433 		smb_llist_remove(&smb_oplock_breaks, ob);
434 	}
435 	smb_llist_exit(&smb_oplock_breaks);
436 	return (ob);
437 }
438 
439 /*
440  * smb_oplock_process_levelII_break
441  */
442 void
443 smb_oplock_process_levelII_break(smb_node_t *node)
444 {
445 	smb_oplock_t		*ol;
446 	smb_oplock_grant_t	*og;
447 	list_t			*grants;
448 
449 	if (!smb_oplock_levelII)
450 		return;
451 
452 	ol = &node->n_oplock;
453 	mutex_enter(&ol->ol_mutex);
454 	smb_oplock_wait(node);
455 	grants = &node->n_oplock.ol_grants;
456 
457 	while ((og = list_head(grants)) != NULL) {
458 		SMB_OPLOCK_GRANT_VALID(og);
459 
460 		if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
461 			break;
462 
463 		smb_session_oplock_break(og->og_session,
464 		    og->og_tid, og->og_fid, SMB_OPLOCK_BREAK_TO_NONE);
465 		smb_oplock_remove_grant(node, og);
466 		smb_oplock_clear_grant(og);
467 	}
468 
469 	mutex_exit(&ol->ol_mutex);
470 }
471 
472 /*
473  * smb_oplock_wait_ack
474  *
475  * Timed wait for an oplock break acknowledgement (or oplock release).
476  */
477 static void
478 smb_oplock_wait_ack(smb_node_t *node, uint32_t timeout)
479 {
480 	smb_oplock_t	*ol;
481 	clock_t		time;
482 
483 	ol = &node->n_oplock;
484 	mutex_enter(&ol->ol_mutex);
485 	time = MSEC_TO_TICK(timeout) + ddi_get_lbolt();
486 
487 	while (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
488 		if (cv_timedwait(&ol->ol_cv, &ol->ol_mutex, time) < 0) {
489 			smb_oplock_timedout(node);
490 			cv_broadcast(&ol->ol_cv);
491 			break;
492 		}
493 	}
494 	mutex_exit(&ol->ol_mutex);
495 }
496 
497 /*
498  * smb_oplock_timedout
499  *
500  * An oplock break has not been acknowledged within timeout
501  * 'smb_oplock_timeout'.
502  * Set oplock grant to the desired break level.
503  */
504 static void
505 smb_oplock_timedout(smb_node_t *node)
506 {
507 	smb_oplock_t		*ol;
508 	smb_oplock_grant_t	*og;
509 	list_t			*grants;
510 
511 	ol = &node->n_oplock;
512 	grants = &ol->ol_grants;
513 
514 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
515 
516 	og = smb_oplock_exclusive_grant(grants);
517 	if (og) {
518 		switch (ol->ol_break) {
519 		case SMB_OPLOCK_BREAK_TO_NONE:
520 			og->og_level = SMB_OPLOCK_NONE;
521 			smb_oplock_remove_grant(node, og);
522 			smb_oplock_clear_grant(og);
523 			break;
524 		case SMB_OPLOCK_BREAK_TO_LEVEL_II:
525 			og->og_level = SMB_OPLOCK_LEVEL_II;
526 			break;
527 		default:
528 			SMB_PANIC();
529 		}
530 	}
531 	ol->ol_break = SMB_OPLOCK_NO_BREAK;
532 }
533 
534 /*
535  * smb_oplock_release
536  *
537  * Release the oplock granted on ofile 'of'.
538  * Wake any threads waiting for an oplock break acknowledgement for
539  * this oplock.
540  * This is called when the ofile is being closed.
541  */
542 void
543 smb_oplock_release(smb_node_t *node, smb_ofile_t *of)
544 {
545 	smb_oplock_t		*ol;
546 	smb_oplock_grant_t	*og;
547 
548 	ol = &node->n_oplock;
549 	mutex_enter(&ol->ol_mutex);
550 	smb_oplock_wait(node);
551 
552 	og = smb_oplock_get_grant(ol, of);
553 	if (og) {
554 		smb_oplock_remove_grant(node, og);
555 		smb_oplock_clear_grant(og);
556 
557 		if (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
558 			ol->ol_break = SMB_OPLOCK_NO_BREAK;
559 			cv_broadcast(&ol->ol_cv);
560 		}
561 	}
562 
563 	mutex_exit(&ol->ol_mutex);
564 }
565 
566 /*
567  * smb_oplock_ack
568  *
569  * Process oplock acknowledgement received for ofile 'of'.
570  * - oplock.ol_break is the break level that was requested.
571  * - brk is the break level being acknowledged by the client.
572  *
573  * Update the oplock grant level to the lesser of ol_break and brk.
574  * If the grant is now SMB_OPLOCK_NONE, remove the grant from the
575  * oplock's grant list and delete it.
576  * If the requested break level (ol_break) was NONE and the brk is
577  * LEVEL_II, send another oplock break (NONE). Do not wait for an
578  * acknowledgement.
579  * Wake any threads waiting for the oplock break acknowledgement.
580  */
581 void
582 smb_oplock_ack(smb_node_t *node, smb_ofile_t *of, uint8_t brk)
583 {
584 	smb_oplock_t		*ol;
585 	smb_oplock_grant_t	*og;
586 	boolean_t		brk_to_none = B_FALSE;
587 
588 	ol = &node->n_oplock;
589 	mutex_enter(&ol->ol_mutex);
590 	smb_oplock_wait(node);
591 
592 	if ((ol->ol_break == SMB_OPLOCK_NO_BREAK) ||
593 	    ((og = smb_oplock_get_grant(ol, of)) == NULL)) {
594 		mutex_exit(&ol->ol_mutex);
595 		return;
596 	}
597 
598 	switch (brk) {
599 	case SMB_OPLOCK_BREAK_TO_NONE:
600 		og->og_level = SMB_OPLOCK_NONE;
601 		break;
602 	case SMB_OPLOCK_BREAK_TO_LEVEL_II:
603 		if (ol->ol_break == SMB_OPLOCK_BREAK_TO_LEVEL_II) {
604 			og->og_level = SMB_OPLOCK_LEVEL_II;
605 		} else {
606 			/* SMB_OPLOCK_BREAK_TO_NONE */
607 			og->og_level = SMB_OPLOCK_NONE;
608 			brk_to_none = B_TRUE;
609 		}
610 		break;
611 	default:
612 		SMB_PANIC();
613 	}
614 
615 	if (og->og_level == SMB_OPLOCK_NONE) {
616 		smb_oplock_remove_grant(node, og);
617 		smb_oplock_clear_grant(og);
618 	}
619 
620 	ol->ol_break = SMB_OPLOCK_NO_BREAK;
621 	cv_broadcast(&ol->ol_cv);
622 
623 	if (brk_to_none) {
624 		smb_session_oplock_break(of->f_session,
625 		    of->f_tree->t_tid, of->f_fid,
626 		    SMB_OPLOCK_BREAK_TO_NONE);
627 	}
628 
629 	mutex_exit(&ol->ol_mutex);
630 }
631 
632 /*
633  * smb_oplock_broadcast
634  *
635  * ol->ol_xthread identifies the thread that was performing an oplock
636  * acquire. Other threads may be blocked awaiting completion of the
637  * acquire.
638  * If the calling thread is ol_ol_xthread, wake any waiting threads.
639  */
640 void
641 smb_oplock_broadcast(smb_node_t *node)
642 {
643 	smb_oplock_t	*ol;
644 
645 	SMB_NODE_VALID(node);
646 	ol = &node->n_oplock;
647 
648 	mutex_enter(&ol->ol_mutex);
649 	if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) {
650 		ol->ol_xthread = NULL;
651 		cv_broadcast(&ol->ol_cv);
652 	}
653 	mutex_exit(&ol->ol_mutex);
654 }
655 
656 /*
657  * smb_oplock_wait
658  *
659  * Wait for the completion of an oplock acquire.
660  * If ol_xthread is not NULL and doesn't contain the pointer to the
661  * context of the calling thread, the caller will sleep until the
662  * ol_xthread is reset to NULL (via smb_oplock_broadcast()).
663  */
664 static void
665 smb_oplock_wait(smb_node_t *node)
666 {
667 	smb_oplock_t	*ol;
668 
669 	ol = &node->n_oplock;
670 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
671 
672 	if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) {
673 		while (ol->ol_xthread != NULL)
674 			cv_wait(&ol->ol_cv, &ol->ol_mutex);
675 	}
676 }
677 
678 /*
679  * smb_oplock_set_grant
680  */
681 static smb_oplock_grant_t *
682 smb_oplock_set_grant(smb_ofile_t *of, uint8_t level)
683 {
684 	smb_oplock_grant_t	*og;
685 
686 	og = &of->f_oplock_grant;
687 
688 	og->og_magic = SMB_OPLOCK_GRANT_MAGIC;
689 	og->og_level = level;
690 	og->og_ofile = of;
691 	og->og_fid = of->f_fid;
692 	og->og_tid = of->f_tree->t_tid;
693 	og->og_uid = of->f_user->u_uid;
694 	og->og_session = of->f_session;
695 	return (og);
696 }
697 
698 /*
699  * smb_oplock_clear_grant
700  */
701 void
702 smb_oplock_clear_grant(smb_oplock_grant_t *og)
703 {
704 	bzero(og, sizeof (smb_oplock_grant_t));
705 }
706 
707 /*
708  * smb_oplock_insert_grant
709  *
710  * If there are no grants in the oplock's list install the fem
711  * monitor.
712  * Insert the grant into the list and increment the grant count.
713  */
714 static int
715 smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og)
716 {
717 	smb_oplock_t *ol = &node->n_oplock;
718 
719 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
720 
721 	if (ol->ol_count == 0) {
722 		if (smb_oplock_install_fem(node) != 0)
723 			return (-1);
724 	}
725 
726 	list_insert_tail(&ol->ol_grants, og);
727 	++ol->ol_count;
728 	return (0);
729 }
730 
731 /*
732  * smb_oplock_remove_grant
733  *
734  * Remove the oplock grant from the list, decrement the grant count
735  * and, if there are no other grants in the list, uninstall the fem
736  * monitor.
737  */
738 static void
739 smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og)
740 {
741 	smb_oplock_t *ol = &node->n_oplock;
742 
743 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
744 	ASSERT(ol->ol_count > 0);
745 
746 	list_remove(&ol->ol_grants, og);
747 	if (--ol->ol_count == 0)
748 		smb_oplock_uninstall_fem(node);
749 }
750 
751 /*
752  * smb_oplock_exclusive_grant
753  *
754  * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists,
755  * return it. Otherwise return NULL.
756  */
757 static smb_oplock_grant_t *
758 smb_oplock_exclusive_grant(list_t *grants)
759 {
760 	smb_oplock_grant_t	*og;
761 
762 	og = list_head(grants);
763 	if (og) {
764 		SMB_OPLOCK_GRANT_VALID(og);
765 		if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
766 			return (og);
767 	}
768 	return (NULL);
769 }
770 
771 /*
772  * smb_oplock_get_grant
773  *
774  * Find oplock grant corresponding to the specified ofile.
775  */
776 static smb_oplock_grant_t *
777 smb_oplock_get_grant(smb_oplock_t *ol, smb_ofile_t *ofile)
778 {
779 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
780 
781 	if (SMB_OFILE_OPLOCK_GRANTED(ofile))
782 		return (&ofile->f_oplock_grant);
783 	else
784 		return (NULL);
785 }
786 
787 /*
788  * smb_oplock_create_break
789  */
790 static smb_oplock_break_t *
791 smb_oplock_create_break(smb_node_t *node)
792 {
793 	smb_oplock_break_t	*ob;
794 
795 	ob = kmem_cache_alloc(smb_oplock_break_cache, KM_SLEEP);
796 
797 	smb_node_ref(node);
798 	ob->ob_magic = SMB_OPLOCK_BREAK_MAGIC;
799 	ob->ob_node = node;
800 
801 	return (ob);
802 }
803 
804 /*
805  * smb_oplock_delete_break
806  */
807 static void
808 smb_oplock_delete_break(smb_oplock_break_t *ob)
809 {
810 	smb_node_release(ob->ob_node);
811 	kmem_cache_free(smb_oplock_break_cache, ob);
812 }
813