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