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
smb_oplock_install_fem(smb_node_t * node)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
smb_oplock_uninstall_fem(smb_node_t * node)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
smb_oplock_acquire(smb_request_t * sr,smb_node_t * node,smb_ofile_t * ofile)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
smb_oplock_break(smb_request_t * sr,smb_node_t * node,uint32_t flags)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
smb_oplock_break_levelII(smb_node_t * node)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
smb_oplock_break_levelII_locked(smb_node_t * node)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
smb_oplock_sched_async_break(smb_oplock_grant_t * og,uint8_t brk)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
smb_oplock_exec_async_break(void * arg)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
smb_oplock_wait_ack(smb_node_t * node,uint32_t timeout)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
smb_oplock_timedout(smb_node_t * node)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
smb_oplock_release(smb_node_t * node,smb_ofile_t * of)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
smb_oplock_ack(smb_node_t * node,smb_ofile_t * of,uint8_t brk)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
smb_oplock_broadcast(smb_node_t * node)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
smb_oplock_wait(smb_node_t * node)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 *
smb_oplock_set_grant(smb_ofile_t * of,uint8_t level)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
smb_oplock_clear_grant(smb_oplock_grant_t * og)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
smb_oplock_insert_grant(smb_node_t * node,smb_oplock_grant_t * og)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
smb_oplock_remove_grant(smb_node_t * node,smb_oplock_grant_t * og)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 *
smb_oplock_exclusive_grant(list_t * grants)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 *
smb_oplock_get_grant(smb_oplock_t * ol,smb_ofile_t * ofile)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