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