xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_oplock.c (revision d2a70789f056fc6c9ce3ab047b52126d80b0e3da)
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 	list_t			*grants;
248 	uint32_t		timeout;
249 	uint8_t			brk;
250 
251 	SMB_NODE_VALID(node);
252 	ol = &node->n_oplock;
253 	grants = &ol->ol_grants;
254 
255 	mutex_enter(&ol->ol_mutex);
256 	smb_oplock_wait(node);
257 
258 	og = list_head(grants);
259 	if (og == NULL) {
260 		mutex_exit(&ol->ol_mutex);
261 		return (0);
262 	}
263 
264 	SMB_OPLOCK_GRANT_VALID(og);
265 
266 	/* break levelII oplocks */
267 	if (og->og_level == SMB_OPLOCK_LEVEL_II) {
268 		mutex_exit(&ol->ol_mutex);
269 
270 		if ((flags & SMB_OPLOCK_BREAK_TO_NONE) &&
271 		    !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) &&
272 		    !(flags & SMB_OPLOCK_BREAK_BATCH))  {
273 			smb_oplock_break_levelII(node);
274 		}
275 		return (0);
276 	}
277 
278 	/* break exclusive oplock */
279 	if ((flags & SMB_OPLOCK_BREAK_BATCH) &&
280 	    (og->og_level != SMB_OPLOCK_BATCH)) {
281 		mutex_exit(&ol->ol_mutex);
282 		return (0);
283 	}
284 
285 	if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) &&
286 	    smb_session_levelII_oplocks(og->og_session)) {
287 		brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
288 	} else {
289 		brk = SMB_OPLOCK_BREAK_TO_NONE;
290 	}
291 
292 	switch (ol->ol_break) {
293 	case SMB_OPLOCK_NO_BREAK:
294 		ol->ol_break = brk;
295 		smb_oplock_sched_async_break(og, brk);
296 		break;
297 	case SMB_OPLOCK_BREAK_TO_LEVEL_II:
298 		if (brk == SMB_OPLOCK_BREAK_TO_NONE)
299 			ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE;
300 		break;
301 	case SMB_OPLOCK_BREAK_TO_NONE:
302 	default:
303 		break;
304 	}
305 
306 	if (flags & SMB_OPLOCK_BREAK_NOWAIT) {
307 		mutex_exit(&ol->ol_mutex);
308 		return (EAGAIN);
309 	}
310 
311 	if (sr && (sr->session == og->og_session) &&
312 	    (sr->smb_uid == og->og_uid)) {
313 		timeout = smb_oplock_min_timeout;
314 	} else {
315 		timeout = smb_oplock_timeout;
316 	}
317 
318 	mutex_exit(&ol->ol_mutex);
319 	smb_oplock_wait_ack(node, timeout);
320 	return (0);
321 }
322 
323 /*
324  * smb_oplock_break_levelII
325  *
326  * This is called after a file is modified in some way.  If there are
327  * LevelII (shared) oplocks, break those to none.  If there is an
328  * exclusive oplock, there can be no LevelII oplocks, so do nothing.
329  *
330  * LevelII (shared) oplock breaks are processed asynchronously.
331  * Unlike exclusive oplock breaks, the thread initiating the break
332  * is NOT blocked while the request is processed.
333  *
334  * There may be a thread with exclusive rights to oplock state for
335  * this node (via ol_xthread in smb_oplock_wait) and if so, we must
336  * avoid breaking oplocks until that's out of the way.  However, we
337  * really don't want to block here, so when ol_xthread is set, we'll
338  * just mark that a "break level II to none" is pending, and let the
339  * exclusive thread do this work when it's done being exclusive.
340  */
341 void
342 smb_oplock_break_levelII(smb_node_t *node)
343 {
344 	smb_oplock_t		*ol;
345 
346 	ol = &node->n_oplock;
347 	mutex_enter(&ol->ol_mutex);
348 
349 	/* Instead of: smb_oplock_wait() ... */
350 	if (ol->ol_xthread != NULL) {
351 		/* Defer the call to smb_oplock_broadcast(). */
352 		ol->ol_brk_pending = SMB_OPLOCK_BREAK_TO_NONE;
353 	} else {
354 		/* Equivalent of smb_oplock_wait() done. */
355 		smb_oplock_break_levelII_locked(node);
356 	}
357 
358 	mutex_exit(&ol->ol_mutex);
359 }
360 
361 /*
362  * smb_oplock_break_levelII_locked
363  * Internal helper for smb_oplock_break_levelII()
364  *
365  * Called with the oplock mutex already held, and _after_
366  * (the equivalent of) an smb_oplock_wait().
367  */
368 static void
369 smb_oplock_break_levelII_locked(smb_node_t *node)
370 {
371 	smb_oplock_t		*ol;
372 	smb_oplock_grant_t	*og;
373 	list_t			*grants;
374 
375 	ol = &node->n_oplock;
376 	grants = &ol->ol_grants;
377 
378 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
379 	ASSERT(ol->ol_xthread == NULL);
380 
381 	while ((og = list_head(grants)) != NULL) {
382 		SMB_OPLOCK_GRANT_VALID(og);
383 
384 		/*
385 		 * If there's an exclusive oplock, there are
386 		 * no LevelII oplocks, so do nothing.
387 		 */
388 		if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
389 			break;
390 
391 		smb_oplock_sched_async_break(og, SMB_OPLOCK_BREAK_TO_NONE);
392 		smb_oplock_remove_grant(node, og);
393 		smb_oplock_clear_grant(og);
394 	}
395 }
396 
397 /*
398  * Schedule a call to smb_session_oplock_break
399  * using an smb_request on the owning session.
400  */
401 static void
402 smb_oplock_sched_async_break(smb_oplock_grant_t *og, uint8_t brk)
403 {
404 	smb_request_t		*sr;
405 	smb_ofile_t		*ofile;
406 
407 	/*
408 	 * Make sure we can get a hold on the ofile.  If we can't,
409 	 * the file is closing, and there's no point scheduling an
410 	 * oplock break on it.  (Also hold the tree and user.)
411 	 * These holds account for the pointers we copy into the
412 	 * smb_request fields: fid_ofile, tid_tree, uid_user.
413 	 * These holds are released via smb_request_free after
414 	 * the oplock break has been sent.
415 	 */
416 	ofile = og->og_ofile;
417 	if (!smb_ofile_hold(ofile))
418 		return;
419 	smb_tree_hold_internal(ofile->f_tree);
420 	smb_user_hold_internal(ofile->f_user);
421 
422 	sr = smb_request_alloc(og->og_session, 0);
423 	sr->sr_state = SMB_REQ_STATE_SUBMITTED;
424 	sr->user_cr = zone_kcred();
425 	sr->fid_ofile = ofile;
426 	sr->tid_tree = ofile->f_tree;
427 	sr->uid_user = ofile->f_user;
428 
429 	sr->arg.olbrk = *og; /* struct copy */
430 	sr->arg.olbrk.og_breaking = brk;
431 
432 	(void) taskq_dispatch(
433 	    sr->sr_server->sv_worker_pool,
434 	    smb_oplock_exec_async_break, sr, TQ_SLEEP);
435 }
436 
437 /*
438  * smb_oplock_exec_async_break
439  *
440  * Called via the taskq to handle an asynchronous oplock break.
441  * We have a hold on the ofile, which keeps the FID here valid.
442  */
443 static void
444 smb_oplock_exec_async_break(void *arg)
445 {
446 	smb_request_t *sr = arg;
447 	smb_oplock_grant_t *og = &sr->arg.olbrk;
448 
449 	SMB_REQ_VALID(sr);
450 	SMB_OPLOCK_GRANT_VALID(og);
451 
452 	mutex_enter(&sr->sr_mutex);
453 	sr->sr_worker = curthread;
454 	sr->sr_time_active = gethrtime();
455 
456 	switch (sr->sr_state) {
457 	case SMB_REQ_STATE_SUBMITTED:
458 		sr->sr_state = SMB_REQ_STATE_ACTIVE;
459 		mutex_exit(&sr->sr_mutex);
460 
461 		/*
462 		 * This is where we actually do the deferred work
463 		 * requested by smb_oplock_sched_async_break().
464 		 */
465 		smb_session_oplock_break(sr, og->og_breaking);
466 
467 		mutex_enter(&sr->sr_mutex);
468 		/* FALLTHROUGH */
469 
470 	default: /* typically cancelled */
471 		sr->sr_state = SMB_REQ_STATE_COMPLETED;
472 		mutex_exit(&sr->sr_mutex);
473 	}
474 
475 	smb_request_free(sr);
476 }
477 
478 /*
479  * smb_oplock_wait_ack
480  *
481  * Timed wait for an oplock break acknowledgement (or oplock release).
482  */
483 static void
484 smb_oplock_wait_ack(smb_node_t *node, uint32_t timeout)
485 {
486 	smb_oplock_t	*ol;
487 	clock_t		time;
488 
489 	ol = &node->n_oplock;
490 	mutex_enter(&ol->ol_mutex);
491 	time = MSEC_TO_TICK(timeout) + ddi_get_lbolt();
492 
493 	while (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
494 		if (cv_timedwait(&ol->ol_cv, &ol->ol_mutex, time) < 0) {
495 			smb_oplock_timedout(node);
496 			cv_broadcast(&ol->ol_cv);
497 			break;
498 		}
499 	}
500 	mutex_exit(&ol->ol_mutex);
501 }
502 
503 /*
504  * smb_oplock_timedout
505  *
506  * An oplock break has not been acknowledged within timeout
507  * 'smb_oplock_timeout'.
508  * Set oplock grant to the desired break level.
509  */
510 static void
511 smb_oplock_timedout(smb_node_t *node)
512 {
513 	smb_oplock_t		*ol;
514 	smb_oplock_grant_t	*og;
515 	list_t			*grants;
516 
517 	ol = &node->n_oplock;
518 	grants = &ol->ol_grants;
519 
520 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
521 
522 	og = smb_oplock_exclusive_grant(grants);
523 	if (og) {
524 		switch (ol->ol_break) {
525 		case SMB_OPLOCK_BREAK_TO_NONE:
526 			og->og_level = SMB_OPLOCK_NONE;
527 			smb_oplock_remove_grant(node, og);
528 			smb_oplock_clear_grant(og);
529 			break;
530 		case SMB_OPLOCK_BREAK_TO_LEVEL_II:
531 			og->og_level = SMB_OPLOCK_LEVEL_II;
532 			break;
533 		default:
534 			SMB_PANIC();
535 		}
536 	}
537 	ol->ol_break = SMB_OPLOCK_NO_BREAK;
538 }
539 
540 /*
541  * smb_oplock_release
542  *
543  * Release the oplock granted on ofile 'of'.
544  * Wake any threads waiting for an oplock break acknowledgement for
545  * this oplock.
546  * This is called when the ofile is being closed.
547  */
548 void
549 smb_oplock_release(smb_node_t *node, smb_ofile_t *of)
550 {
551 	smb_oplock_t		*ol;
552 	smb_oplock_grant_t	*og;
553 
554 	ol = &node->n_oplock;
555 	mutex_enter(&ol->ol_mutex);
556 	smb_oplock_wait(node);
557 
558 	og = smb_oplock_get_grant(ol, of);
559 	if (og) {
560 		smb_oplock_remove_grant(node, og);
561 		smb_oplock_clear_grant(og);
562 
563 		if (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
564 			ol->ol_break = SMB_OPLOCK_NO_BREAK;
565 			cv_broadcast(&ol->ol_cv);
566 		}
567 	}
568 
569 	mutex_exit(&ol->ol_mutex);
570 }
571 
572 /*
573  * smb_oplock_ack
574  *
575  * Process oplock acknowledgement received for ofile 'of'.
576  * - oplock.ol_break is the break level that was requested.
577  * - brk is the break level being acknowledged by the client.
578  *
579  * Update the oplock grant level to the lesser of ol_break and brk.
580  * If the grant is now SMB_OPLOCK_NONE, remove the grant from the
581  * oplock's grant list and delete it.
582  * If the requested break level (ol_break) was NONE and the brk is
583  * LEVEL_II, send another oplock break (NONE). Do not wait for an
584  * acknowledgement.
585  * Wake any threads waiting for the oplock break acknowledgement.
586  */
587 void
588 smb_oplock_ack(smb_node_t *node, smb_ofile_t *of, uint8_t brk)
589 {
590 	smb_oplock_t		*ol;
591 	smb_oplock_grant_t	*og;
592 
593 	ol = &node->n_oplock;
594 	mutex_enter(&ol->ol_mutex);
595 	smb_oplock_wait(node);
596 
597 	if ((ol->ol_break == SMB_OPLOCK_NO_BREAK) ||
598 	    ((og = smb_oplock_get_grant(ol, of)) == NULL)) {
599 		mutex_exit(&ol->ol_mutex);
600 		return;
601 	}
602 
603 	switch (brk) {
604 	case SMB_OPLOCK_BREAK_TO_NONE:
605 		og->og_level = SMB_OPLOCK_NONE;
606 		break;
607 	case SMB_OPLOCK_BREAK_TO_LEVEL_II:
608 		if (ol->ol_break == SMB_OPLOCK_BREAK_TO_LEVEL_II) {
609 			og->og_level = SMB_OPLOCK_LEVEL_II;
610 		} else {
611 			/* SMB_OPLOCK_BREAK_TO_NONE */
612 			og->og_level = SMB_OPLOCK_NONE;
613 			smb_oplock_sched_async_break(og,
614 			    SMB_OPLOCK_BREAK_TO_NONE);
615 		}
616 		break;
617 	default:
618 		SMB_PANIC();
619 	}
620 
621 	if (og->og_level == SMB_OPLOCK_NONE) {
622 		smb_oplock_remove_grant(node, og);
623 		smb_oplock_clear_grant(og);
624 	}
625 
626 	ol->ol_break = SMB_OPLOCK_NO_BREAK;
627 	cv_broadcast(&ol->ol_cv);
628 
629 	mutex_exit(&ol->ol_mutex);
630 }
631 
632 /*
633  * smb_oplock_broadcast
634  *
635  * Called when an open with oplock request completes.
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_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 		if (ol->ol_brk_pending) {
654 			ol->ol_brk_pending = 0;
655 			smb_oplock_break_levelII_locked(node);
656 		}
657 		cv_broadcast(&ol->ol_cv);
658 	}
659 	mutex_exit(&ol->ol_mutex);
660 }
661 
662 /*
663  * smb_oplock_wait
664  *
665  * Wait for the completion of an oplock acquire.
666  * If ol_xthread is not NULL and doesn't contain the pointer to the
667  * context of the calling thread, the caller will sleep until the
668  * ol_xthread is reset to NULL (via smb_oplock_broadcast()).
669  */
670 static void
671 smb_oplock_wait(smb_node_t *node)
672 {
673 	smb_oplock_t	*ol;
674 
675 	ol = &node->n_oplock;
676 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
677 
678 	if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) {
679 		while (ol->ol_xthread != NULL)
680 			cv_wait(&ol->ol_cv, &ol->ol_mutex);
681 	}
682 }
683 
684 /*
685  * smb_oplock_set_grant
686  */
687 static smb_oplock_grant_t *
688 smb_oplock_set_grant(smb_ofile_t *of, uint8_t level)
689 {
690 	smb_oplock_grant_t	*og;
691 
692 	og = &of->f_oplock_grant;
693 
694 	og->og_magic = SMB_OPLOCK_GRANT_MAGIC;
695 	og->og_breaking = 0;
696 	og->og_level = level;
697 	og->og_ofile = of;
698 	og->og_fid = of->f_fid;
699 	og->og_tid = of->f_tree->t_tid;
700 	og->og_uid = of->f_user->u_uid;
701 	og->og_session = of->f_session;
702 	return (og);
703 }
704 
705 /*
706  * smb_oplock_clear_grant
707  */
708 void
709 smb_oplock_clear_grant(smb_oplock_grant_t *og)
710 {
711 	bzero(og, sizeof (smb_oplock_grant_t));
712 }
713 
714 /*
715  * smb_oplock_insert_grant
716  *
717  * If there are no grants in the oplock's list install the fem
718  * monitor.
719  * Insert the grant into the list and increment the grant count.
720  */
721 static int
722 smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og)
723 {
724 	smb_oplock_t *ol = &node->n_oplock;
725 
726 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
727 
728 	if (ol->ol_count == 0) {
729 		if (smb_oplock_install_fem(node) != 0)
730 			return (-1);
731 	}
732 
733 	list_insert_tail(&ol->ol_grants, og);
734 	++ol->ol_count;
735 	return (0);
736 }
737 
738 /*
739  * smb_oplock_remove_grant
740  *
741  * Remove the oplock grant from the list, decrement the grant count
742  * and, if there are no other grants in the list, uninstall the fem
743  * monitor.
744  */
745 static void
746 smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og)
747 {
748 	smb_oplock_t *ol = &node->n_oplock;
749 
750 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
751 	ASSERT(ol->ol_count > 0);
752 
753 	list_remove(&ol->ol_grants, og);
754 	if (--ol->ol_count == 0)
755 		smb_oplock_uninstall_fem(node);
756 }
757 
758 /*
759  * smb_oplock_exclusive_grant
760  *
761  * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists,
762  * return it. Otherwise return NULL.
763  */
764 static smb_oplock_grant_t *
765 smb_oplock_exclusive_grant(list_t *grants)
766 {
767 	smb_oplock_grant_t	*og;
768 
769 	og = list_head(grants);
770 	if (og) {
771 		SMB_OPLOCK_GRANT_VALID(og);
772 		if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
773 			return (og);
774 	}
775 	return (NULL);
776 }
777 
778 /*
779  * smb_oplock_get_grant
780  *
781  * Find oplock grant corresponding to the specified ofile.
782  */
783 static smb_oplock_grant_t *
784 smb_oplock_get_grant(smb_oplock_t *ol, smb_ofile_t *ofile)
785 {
786 	ASSERT(MUTEX_HELD(&ol->ol_mutex));
787 
788 	if (SMB_OFILE_OPLOCK_GRANTED(ofile))
789 		return (&ofile->f_oplock_grant);
790 	else
791 		return (NULL);
792 }
793