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