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