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