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