xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_oplock.c (revision 80bd8a585c4ef2f19c09c9c4379635e411c91fe6)
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  * Copyright 2014 Nexenta Systems, Inc.  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 void smb_oplock_sched_async_break(smb_oplock_grant_t *, uint8_t);
64 static void smb_oplock_exec_async_break(void *);
65 static void smb_oplock_break_levelII_locked(smb_node_t *);
66 
67 /*
68  * smb_oplock_install_fem
69  * Install fem monitor for cross protocol oplock breaking.
70  */
71 static int
72 smb_oplock_install_fem(smb_node_t *node)
73 {
74 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
75 
76 	if (node->n_oplock.ol_fem == B_FALSE) {
77 		if (smb_fem_oplock_install(node) != 0) {
78 			cmn_err(CE_NOTE, "No oplock granted: "
79 			    "failed to install fem monitor %s",
80 			    node->vp->v_path);
81 			return (-1);
82 		}
83 		node->n_oplock.ol_fem = B_TRUE;
84 	}
85 	return (0);
86 }
87 
88 /*
89  * smb_oplock_uninstall_fem
90  * Uninstall fem monitor for cross protocol oplock breaking.
91  */
92 static void
93 smb_oplock_uninstall_fem(smb_node_t *node)
94 {
95 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
96 
97 	if (node->n_oplock.ol_fem) {
98 		smb_fem_oplock_uninstall(node);
99 		node->n_oplock.ol_fem = B_FALSE;
100 	}
101 }
102 
103 /*
104  * This provides a way to fully disable oplocks, i.e. for testing.
105  * You _really_ do _not_ want to turn this off, because if you do,
106  * the clients send you very small read requests, and a _lot_ more
107  * of them.  The skc_oplock_enable parameter can be used to enable
108  * or disable exclusive oplocks.  Disabling that can be helpful
109  * when there are clients not responding to oplock breaks.
110  */
111 int smb_oplocks_enabled = 1;
112 
113 /*
114  * smb_oplock_acquire
115  *
116  * Attempt to acquire an oplock. Clients will request EXCLUSIVE or BATCH,
117  * but might only be granted LEVEL_II or NONE.
118  *
119  * If oplocks are not supported on the tree, or node, grant NONE.
120  * If nobody else has the file open, grant the requested level.
121  * If any of the following are true, grant NONE:
122  * - there is an exclusive oplock on the node
123  * - op->op_oplock_levelII is B_FALSE (LEVEL_II not supported by open cmd.
124  * - LEVEL_II oplocks are not supported for the session
125  * - a BATCH oplock is requested on a named stream
126  * - there are any range locks on the node (SMB writers)
127  * Otherwise, grant LEVEL_II.
128  *
129  * ol->ol_xthread is set to the current thread to lock the oplock against
130  * other operations until the acquire response is on the wire. When the
131  * acquire response is on the wire, smb_oplock_broadcast() is called to
132  * reset ol->ol_xthread and wake any waiting threads.
133  */
134 void
135 smb_oplock_acquire(smb_request_t *sr, smb_node_t *node, smb_ofile_t *ofile)
136 {
137 	smb_oplock_t		*ol;
138 	smb_oplock_grant_t	*og;
139 	list_t			*grants;
140 	smb_arg_open_t		*op;
141 	smb_tree_t		*tree;
142 	smb_session_t		*session;
143 
144 	SMB_NODE_VALID(node);
145 	SMB_OFILE_VALID(ofile);
146 
147 	ASSERT(node == SMB_OFILE_GET_NODE(ofile));
148 	ASSERT(RW_LOCK_HELD(&node->n_lock));
149 
150 	op = &sr->sr_open;
151 	tree = SMB_OFILE_GET_TREE(ofile);
152 	session = SMB_OFILE_GET_SESSION(ofile);
153 
154 	if (smb_oplocks_enabled == 0 ||
155 	    (op->op_oplock_level == SMB_OPLOCK_NONE) ||
156 	    ((op->op_oplock_level == SMB_OPLOCK_BATCH) &&
157 	    SMB_IS_STREAM(node))) {
158 		op->op_oplock_level = SMB_OPLOCK_NONE;
159 		return;
160 	}
161 
162 	ol = &node->n_oplock;
163 	grants = &ol->ol_grants;
164 
165 	mutex_enter(&ol->ol_mutex);
166 	smb_oplock_wait(node);
167 
168 	/*
169 	 * Even if there are no other opens, we might want to
170 	 * grant only a Level II (shared) oplock so we avoid
171 	 * ever granting exclusive oplocks.
172 	 *
173 	 * Borrowing the SMB_TREE_OPLOCKS flag to enable/disable
174 	 * exclusive oplocks (for now).  See skc_oplock_enable,
175 	 * which can now be taken as "exclusive oplock enable".
176 	 * Should rename this parameter, and/or implement a new
177 	 * multi-valued parameter for oplock enables.
178 	 */
179 	if ((node->n_open_count > 1) ||
180 	    (node->n_opening_count > 1) ||
181 	    !smb_tree_has_feature(tree, SMB_TREE_OPLOCKS) ||
182 	    smb_vop_other_opens(node->vp, ofile->f_mode)) {
183 		/*
184 		 * There are other opens.
185 		 */
186 		if ((!op->op_oplock_levelII) ||
187 		    (!smb_session_levelII_oplocks(session)) ||
188 		    (smb_oplock_exclusive_grant(grants) != NULL) ||
189 		    (smb_lock_range_access(sr, node, 0, ~0, B_FALSE))) {
190 			/*
191 			 * LevelII (shared) oplock not allowed,
192 			 * so reply with "none".
193 			 */
194 			op->op_oplock_level = SMB_OPLOCK_NONE;
195 			mutex_exit(&ol->ol_mutex);
196 			return;
197 		}
198 
199 		op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
200 	}
201 
202 	og = smb_oplock_set_grant(ofile, op->op_oplock_level);
203 	if (smb_oplock_insert_grant(node, og) != 0) {
204 		smb_oplock_clear_grant(og);
205 		op->op_oplock_level = SMB_OPLOCK_NONE;
206 		mutex_exit(&ol->ol_mutex);
207 		return;
208 	}
209 
210 	ol->ol_xthread = curthread;
211 	mutex_exit(&ol->ol_mutex);
212 }
213 
214 /*
215  * smb_oplock_break
216  *
217  * Break granted oplocks according to the following rules:
218  *
219  * If there's an exclusive oplock granted on the node
220  *  - if the BREAK_BATCH flags is specified and the oplock is not
221  *    a batch oplock, no break is required.
222  *  - if the session doesn't support LEVEL II oplocks, and 'brk' is
223  *    BREAK_TO_LEVEL_II, do a BREAK_TO_NONE.
224  *  - if the oplock is already breaking update the break level (if
225  *    the requested break is to a lesser level), otherwise send an
226  *    oplock break.
227  *    Wait for acknowledgement of the break (unless NOWAIT flag is set)
228  *
229  * Otherwise:
230  * If there are level II oplocks granted on the node, and the flags
231  * indicate that they should be broken (BREAK_TO_NONE specified,
232  * BREAK_EXCLUSIVE, BREAK_BATCH not specified) queue the levelII
233  * break request for asynchronous processing.
234  *
235  * Returns:
236  *       0 - oplock broken (or no break required)
237  *  EAGAIN - oplock break request sent and would block
238  *           awaiting the reponse but NOWAIT was specified
239  *
240  * NB: sr == NULL when called by FEM framework.
241  */
242 int
243 smb_oplock_break(smb_request_t *sr, smb_node_t *node, uint32_t flags)
244 {
245 	smb_oplock_t		*ol;
246 	smb_oplock_grant_t	*og;
247 	smb_ofile_t		*ofile;
248 	list_t			*grants;
249 	uint32_t		timeout;
250 	uint8_t			brk;
251 
252 	SMB_NODE_VALID(node);
253 	ol = &node->n_oplock;
254 	grants = &ol->ol_grants;
255 
256 	mutex_enter(&ol->ol_mutex);
257 	smb_oplock_wait(node);
258 
259 	og = list_head(grants);
260 	if (og == NULL) {
261 		mutex_exit(&ol->ol_mutex);
262 		return (0);
263 	}
264 
265 	SMB_OPLOCK_GRANT_VALID(og);
266 	ofile = og->og_ofile;	/* containing struct */
267 
268 	/* break levelII oplocks */
269 	if (og->og_level == SMB_OPLOCK_LEVEL_II) {
270 		mutex_exit(&ol->ol_mutex);
271 
272 		if ((flags & SMB_OPLOCK_BREAK_TO_NONE) &&
273 		    !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) &&
274 		    !(flags & SMB_OPLOCK_BREAK_BATCH))  {
275 			smb_oplock_break_levelII(node);
276 		}
277 		return (0);
278 	}
279 
280 	/* break exclusive oplock */
281 	if ((flags & SMB_OPLOCK_BREAK_BATCH) &&
282 	    (og->og_level != SMB_OPLOCK_BATCH)) {
283 		mutex_exit(&ol->ol_mutex);
284 		return (0);
285 	}
286 
287 	if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) &&
288 	    smb_session_levelII_oplocks(ofile->f_session)) {
289 		brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
290 	} else {
291 		brk = SMB_OPLOCK_BREAK_TO_NONE;
292 	}
293 
294 	switch (ol->ol_break) {
295 	case SMB_OPLOCK_NO_BREAK:
296 		ol->ol_break = brk;
297 		smb_oplock_sched_async_break(og, brk);
298 		break;
299 	case SMB_OPLOCK_BREAK_TO_LEVEL_II:
300 		if (brk == SMB_OPLOCK_BREAK_TO_NONE)
301 			ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE;
302 		break;
303 	case SMB_OPLOCK_BREAK_TO_NONE:
304 	default:
305 		break;
306 	}
307 
308 	if (flags & SMB_OPLOCK_BREAK_NOWAIT) {
309 		mutex_exit(&ol->ol_mutex);
310 		return (EAGAIN);
311 	}
312 
313 	if (sr && (sr->uid_user == ofile->f_user)) {
314 		timeout = smb_oplock_min_timeout;
315 	} else {
316 		timeout = smb_oplock_timeout;
317 	}
318 
319 	mutex_exit(&ol->ol_mutex);
320 	smb_oplock_wait_ack(node, timeout);
321 	return (0);
322 }
323 
324 /*
325  * smb_oplock_break_levelII
326  *
327  * This is called after a file is modified in some way.  If there are
328  * LevelII (shared) oplocks, break those to none.  If there is an
329  * exclusive oplock, there can be no LevelII oplocks, so do nothing.
330  *
331  * LevelII (shared) oplock breaks are processed asynchronously.
332  * Unlike exclusive oplock breaks, the thread initiating the break
333  * is NOT blocked while the request is processed.
334  *
335  * There may be a thread with exclusive rights to oplock state for
336  * this node (via ol_xthread in smb_oplock_wait) and if so, we must
337  * avoid breaking oplocks until that's out of the way.  However, we
338  * really don't want to block here, so when ol_xthread is set, we'll
339  * just mark that a "break level II to none" is pending, and let the
340  * exclusive thread do this work when it's done being exclusive.
341  */
342 void
343 smb_oplock_break_levelII(smb_node_t *node)
344 {
345 	smb_oplock_t		*ol;
346 
347 	ol = &node->n_oplock;
348 	mutex_enter(&ol->ol_mutex);
349 
350 	/* Instead of: smb_oplock_wait() ... */
351 	if (ol->ol_xthread != NULL) {
352 		/* Defer the call to smb_oplock_broadcast(). */
353 		ol->ol_brk_pending = SMB_OPLOCK_BREAK_TO_NONE;
354 	} else {
355 		/* Equivalent of smb_oplock_wait() done. */
356 		smb_oplock_break_levelII_locked(node);
357 	}
358 
359 	mutex_exit(&ol->ol_mutex);
360 }
361 
362 /*
363  * smb_oplock_break_levelII_locked
364  * Internal helper for smb_oplock_break_levelII()
365  *
366  * Called with the oplock mutex already held, and _after_
367  * (the equivalent of) an smb_oplock_wait().
368  */
369 static void
370 smb_oplock_break_levelII_locked(smb_node_t *node)
371 {
372 	smb_oplock_t		*ol;
373 	smb_oplock_grant_t	*og;
374 	list_t			*grants;
375 
376 	ol = &node->n_oplock;
377 	grants = &ol->ol_grants;
378 
379 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
380 	ASSERT(ol->ol_xthread == NULL);
381 
382 	while ((og = list_head(grants)) != NULL) {
383 		SMB_OPLOCK_GRANT_VALID(og);
384 
385 		/*
386 		 * If there's an exclusive oplock, there are
387 		 * no LevelII oplocks, so do nothing.
388 		 */
389 		if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
390 			break;
391 
392 		smb_oplock_sched_async_break(og, SMB_OPLOCK_BREAK_TO_NONE);
393 		smb_oplock_remove_grant(node, og);
394 		smb_oplock_clear_grant(og);
395 	}
396 }
397 
398 /*
399  * Schedule a call to smb_session_oplock_break
400  * using an smb_request on the owning session.
401  */
402 static void
403 smb_oplock_sched_async_break(smb_oplock_grant_t *og, uint8_t brk)
404 {
405 	smb_request_t		*sr;
406 	smb_ofile_t		*ofile;
407 
408 	/*
409 	 * Make sure we can get a hold on the ofile.  If we can't,
410 	 * the file is closing, and there's no point scheduling an
411 	 * oplock break on it because the close will release the
412 	 * oplock very soon. Same for the tree & user holds.
413 	 *
414 	 * These holds account for the pointers we copy into the
415 	 * smb_request fields: fid_ofile, tid_tree, uid_user.
416 	 * These holds are released via smb_request_free after
417 	 * the oplock break has been sent.
418 	 */
419 	ofile = og->og_ofile;	/* containing struct */
420 	if (!smb_ofile_hold(ofile))
421 		return;
422 
423 	if ((sr = smb_request_alloc(ofile->f_session, 0)) == NULL) {
424 		smb_ofile_release(ofile);
425 		return;
426 	}
427 
428 	smb_tree_hold_internal(ofile->f_tree);
429 	smb_user_hold_internal(ofile->f_user);
430 
431 	sr->sr_state = SMB_REQ_STATE_SUBMITTED;
432 	sr->user_cr = zone_kcred();
433 	sr->fid_ofile = ofile;
434 	sr->tid_tree = ofile->f_tree;
435 	sr->uid_user = ofile->f_user;
436 
437 	sr->arg.olbrk = *og; /* struct copy */
438 	sr->arg.olbrk.og_breaking = brk;
439 
440 	(void) taskq_dispatch(
441 	    sr->sr_server->sv_worker_pool,
442 	    smb_oplock_exec_async_break, sr, TQ_SLEEP);
443 }
444 
445 /*
446  * smb_oplock_exec_async_break
447  *
448  * Called via the taskq to handle an asynchronous oplock break.
449  * We have a hold on the ofile, which keeps the FID here valid.
450  */
451 static void
452 smb_oplock_exec_async_break(void *arg)
453 {
454 	smb_request_t *sr = arg;
455 	smb_oplock_grant_t *og = &sr->arg.olbrk;
456 
457 	SMB_REQ_VALID(sr);
458 	SMB_OPLOCK_GRANT_VALID(og);
459 
460 	mutex_enter(&sr->sr_mutex);
461 	sr->sr_worker = curthread;
462 	sr->sr_time_active = gethrtime();
463 
464 	switch (sr->sr_state) {
465 	case SMB_REQ_STATE_SUBMITTED:
466 		sr->sr_state = SMB_REQ_STATE_ACTIVE;
467 		mutex_exit(&sr->sr_mutex);
468 
469 		/*
470 		 * This is where we actually do the deferred work
471 		 * requested by smb_oplock_sched_async_break().
472 		 */
473 		smb_session_oplock_break(sr, og->og_breaking);
474 
475 		mutex_enter(&sr->sr_mutex);
476 		/* FALLTHROUGH */
477 
478 	default: /* typically cancelled */
479 		sr->sr_state = SMB_REQ_STATE_COMPLETED;
480 		mutex_exit(&sr->sr_mutex);
481 	}
482 
483 	smb_request_free(sr);
484 }
485 
486 /*
487  * smb_oplock_wait_ack
488  *
489  * Timed wait for an oplock break acknowledgement (or oplock release).
490  */
491 static void
492 smb_oplock_wait_ack(smb_node_t *node, uint32_t timeout)
493 {
494 	smb_oplock_t	*ol;
495 	clock_t		time;
496 
497 	ol = &node->n_oplock;
498 	mutex_enter(&ol->ol_mutex);
499 	time = MSEC_TO_TICK(timeout) + ddi_get_lbolt();
500 
501 	while (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
502 		if (cv_timedwait(&ol->ol_cv, &ol->ol_mutex, time) < 0) {
503 			smb_oplock_timedout(node);
504 			cv_broadcast(&ol->ol_cv);
505 			break;
506 		}
507 	}
508 	mutex_exit(&ol->ol_mutex);
509 }
510 
511 /*
512  * smb_oplock_timedout
513  *
514  * An oplock break has not been acknowledged within timeout
515  * 'smb_oplock_timeout'.
516  * Set oplock grant to the desired break level.
517  */
518 static void
519 smb_oplock_timedout(smb_node_t *node)
520 {
521 	smb_oplock_t		*ol;
522 	smb_oplock_grant_t	*og;
523 	list_t			*grants;
524 
525 	ol = &node->n_oplock;
526 	grants = &ol->ol_grants;
527 
528 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
529 
530 	og = smb_oplock_exclusive_grant(grants);
531 	if (og) {
532 		switch (ol->ol_break) {
533 		case SMB_OPLOCK_BREAK_TO_NONE:
534 			og->og_level = SMB_OPLOCK_NONE;
535 			smb_oplock_remove_grant(node, og);
536 			smb_oplock_clear_grant(og);
537 			break;
538 		case SMB_OPLOCK_BREAK_TO_LEVEL_II:
539 			og->og_level = SMB_OPLOCK_LEVEL_II;
540 			break;
541 		default:
542 			SMB_PANIC();
543 		}
544 	}
545 	ol->ol_break = SMB_OPLOCK_NO_BREAK;
546 }
547 
548 /*
549  * smb_oplock_release
550  *
551  * Release the oplock granted on ofile 'of'.
552  * Wake any threads waiting for an oplock break acknowledgement for
553  * this oplock.
554  * This is called when the ofile is being closed.
555  */
556 void
557 smb_oplock_release(smb_node_t *node, smb_ofile_t *of)
558 {
559 	smb_oplock_t		*ol;
560 	smb_oplock_grant_t	*og;
561 
562 	ol = &node->n_oplock;
563 	mutex_enter(&ol->ol_mutex);
564 	smb_oplock_wait(node);
565 
566 	og = smb_oplock_get_grant(ol, of);
567 	if (og) {
568 		smb_oplock_remove_grant(node, og);
569 		smb_oplock_clear_grant(og);
570 
571 		if (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
572 			ol->ol_break = SMB_OPLOCK_NO_BREAK;
573 			cv_broadcast(&ol->ol_cv);
574 		}
575 	}
576 
577 	mutex_exit(&ol->ol_mutex);
578 }
579 
580 /*
581  * smb_oplock_ack
582  *
583  * Process oplock acknowledgement received for ofile 'of'.
584  * - oplock.ol_break is the break level that was requested.
585  * - brk is the break level being acknowledged by the client.
586  *
587  * Update the oplock grant level to the lesser of ol_break and brk.
588  * If the grant is now SMB_OPLOCK_NONE, remove the grant from the
589  * oplock's grant list and delete it.
590  * If the requested break level (ol_break) was NONE and the brk is
591  * LEVEL_II, send another oplock break (NONE). Do not wait for an
592  * acknowledgement.
593  * Wake any threads waiting for the oplock break acknowledgement.
594  */
595 void
596 smb_oplock_ack(smb_node_t *node, smb_ofile_t *of, uint8_t brk)
597 {
598 	smb_oplock_t		*ol;
599 	smb_oplock_grant_t	*og;
600 
601 	ol = &node->n_oplock;
602 	mutex_enter(&ol->ol_mutex);
603 	smb_oplock_wait(node);
604 
605 	if ((ol->ol_break == SMB_OPLOCK_NO_BREAK) ||
606 	    ((og = smb_oplock_get_grant(ol, of)) == NULL)) {
607 		mutex_exit(&ol->ol_mutex);
608 		return;
609 	}
610 
611 	switch (brk) {
612 	case SMB_OPLOCK_BREAK_TO_NONE:
613 		og->og_level = SMB_OPLOCK_NONE;
614 		break;
615 	case SMB_OPLOCK_BREAK_TO_LEVEL_II:
616 		if (ol->ol_break == SMB_OPLOCK_BREAK_TO_LEVEL_II) {
617 			og->og_level = SMB_OPLOCK_LEVEL_II;
618 		} else {
619 			/* SMB_OPLOCK_BREAK_TO_NONE */
620 			og->og_level = SMB_OPLOCK_NONE;
621 			smb_oplock_sched_async_break(og,
622 			    SMB_OPLOCK_BREAK_TO_NONE);
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_clear_grant(og);
632 	}
633 
634 	ol->ol_break = SMB_OPLOCK_NO_BREAK;
635 	cv_broadcast(&ol->ol_cv);
636 
637 	mutex_exit(&ol->ol_mutex);
638 }
639 
640 /*
641  * smb_oplock_broadcast
642  *
643  * Called when an open with oplock request completes.
644  *
645  * ol->ol_xthread identifies the thread that was performing an oplock
646  * acquire. Other threads may be blocked awaiting completion of the
647  * acquire.
648  * If the calling thread is ol_xthread, wake any waiting threads.
649  */
650 void
651 smb_oplock_broadcast(smb_node_t *node)
652 {
653 	smb_oplock_t	*ol;
654 
655 	SMB_NODE_VALID(node);
656 	ol = &node->n_oplock;
657 
658 	mutex_enter(&ol->ol_mutex);
659 	if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) {
660 		ol->ol_xthread = NULL;
661 		if (ol->ol_brk_pending) {
662 			ol->ol_brk_pending = 0;
663 			smb_oplock_break_levelII_locked(node);
664 		}
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_set_grant
694  */
695 static smb_oplock_grant_t *
696 smb_oplock_set_grant(smb_ofile_t *of, uint8_t level)
697 {
698 	smb_oplock_grant_t	*og;
699 
700 	og = &of->f_oplock_grant;
701 
702 	og->og_magic = SMB_OPLOCK_GRANT_MAGIC;
703 	og->og_breaking = 0;
704 	og->og_level = level;
705 	og->og_ofile = of;
706 
707 	return (og);
708 }
709 
710 /*
711  * smb_oplock_clear_grant
712  */
713 void
714 smb_oplock_clear_grant(smb_oplock_grant_t *og)
715 {
716 	bzero(og, sizeof (smb_oplock_grant_t));
717 }
718 
719 /*
720  * smb_oplock_insert_grant
721  *
722  * If there are no grants in the oplock's list install the fem
723  * monitor.
724  * Insert the grant into the list and increment the grant count.
725  */
726 static int
727 smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og)
728 {
729 	smb_oplock_t *ol = &node->n_oplock;
730 
731 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
732 
733 	if (ol->ol_count == 0) {
734 		if (smb_oplock_install_fem(node) != 0)
735 			return (-1);
736 	}
737 
738 	list_insert_tail(&ol->ol_grants, og);
739 	++ol->ol_count;
740 	return (0);
741 }
742 
743 /*
744  * smb_oplock_remove_grant
745  *
746  * Remove the oplock grant from the list, decrement the grant count
747  * and, if there are no other grants in the list, uninstall the fem
748  * monitor.
749  */
750 static void
751 smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og)
752 {
753 	smb_oplock_t *ol = &node->n_oplock;
754 
755 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
756 	ASSERT(ol->ol_count > 0);
757 
758 	list_remove(&ol->ol_grants, og);
759 	if (--ol->ol_count == 0)
760 		smb_oplock_uninstall_fem(node);
761 }
762 
763 /*
764  * smb_oplock_exclusive_grant
765  *
766  * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists,
767  * return it. Otherwise return NULL.
768  */
769 static smb_oplock_grant_t *
770 smb_oplock_exclusive_grant(list_t *grants)
771 {
772 	smb_oplock_grant_t	*og;
773 
774 	og = list_head(grants);
775 	if (og) {
776 		SMB_OPLOCK_GRANT_VALID(og);
777 		if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
778 			return (og);
779 	}
780 	return (NULL);
781 }
782 
783 /*
784  * smb_oplock_get_grant
785  *
786  * Find oplock grant corresponding to the specified ofile.
787  */
788 static smb_oplock_grant_t *
789 smb_oplock_get_grant(smb_oplock_t *ol, smb_ofile_t *ofile)
790 {
791 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
792 
793 	if (SMB_OFILE_OPLOCK_GRANTED(ofile))
794 		return (&ofile->f_oplock_grant);
795 	else
796 		return (NULL);
797 }
798