1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
14 * Copyright 2021-2023 RackTop Systems, Inc.
15 */
16
17 /*
18 * (SMB1/SMB2) Server-level Oplock support.
19 *
20 * Conceptually, this is a separate layer on top of the
21 * file system (FS) layer oplock code in smb_cmn_oplock.c.
22 * If these layers were more distinct, the FS layer would
23 * need to use call-back functions (installed from here)
24 * to "indicate an oplock break to the server" (see below).
25 * As these layers are all in the same kernel module, the
26 * delivery of these break indications just uses a direct
27 * function call to smb_oplock_ind_break() below.
28 *
29 * This layer is responsible for handling the break indication,
30 * which often requires scheduling a taskq job in the server,
31 * and sending an oplock break mesage to the client using
32 * the appropriate protocol for the open handle affected.
33 *
34 * The details of composing an oplock break message, the
35 * protocol-specific details of requesting an oplock, and
36 * returning that oplock to the client are in the files:
37 * smb_oplock.c, smb2_oplock.c, smb2_lease.c
38 */
39
40 #include <smbsrv/smb2_kproto.h>
41 #include <smbsrv/smb_oplock.h>
42
43 /*
44 * Verify relationship between BREAK_TO_... and CACHE bits,
45 * used when setting the BREAK_TO_... below.
46 */
47 #if BREAK_TO_READ_CACHING != (READ_CACHING << BREAK_SHIFT)
48 #error "BREAK_TO_READ_CACHING"
49 #endif
50 #if BREAK_TO_HANDLE_CACHING != (HANDLE_CACHING << BREAK_SHIFT)
51 #error "BREAK_TO_HANDLE_CACHING"
52 #endif
53 #if BREAK_TO_WRITE_CACHING != (WRITE_CACHING << BREAK_SHIFT)
54 #error "BREAK_TO_WRITE_CACHING"
55 #endif
56 #define CACHE_RWH (READ_CACHING | WRITE_CACHING | HANDLE_CACHING)
57
58 /*
59 * This is the timeout used in the thread that sends an
60 * oplock break and waits for the client to respond
61 * before it breaks the oplock locally.
62 */
63 int smb_oplock_timeout_ack = 30000; /* mSec. */
64
65 /*
66 * This is the timeout used in threads that have just
67 * finished some sort of oplock request and now must
68 * wait for (possibly multiple) breaks to complete.
69 * This value must be at least a couple seconds LONGER
70 * than the ack timeout above so that I/O callers won't
71 * give up waiting before the local ack timeout.
72 */
73 int smb_oplock_timeout_def = 45000; /* mSec. */
74
75 static void smb_oplock_async_break(void *);
76 static void smb_oplock_hdl_update(smb_request_t *sr);
77 static void smb_oplock_hdl_moved(smb_ofile_t *);
78 static void smb_oplock_hdl_closed(smb_ofile_t *);
79 static void smb_oplock_wait_break_cancel(smb_request_t *sr);
80
81
82 /*
83 * 2.1.5.17.3 Indicating an Oplock Break to the Server
84 *
85 * The inputs for indicating an oplock break to the server are:
86 *
87 * BreakingOplockOpen: The Open used to request the oplock
88 * that is now breaking.
89 * NewOplockLevel: The type of oplock the requested oplock
90 * has been broken to. Valid values are as follows:
91 * LEVEL_NONE (that is, no oplock)
92 * LEVEL_TWO
93 * A combination of one or more of the following flags:
94 * READ_CACHING
95 * HANDLE_CACHING
96 * WRITE_CACHING
97 * AcknowledgeRequired: A Boolean value; TRUE if the server
98 * MUST acknowledge the oplock break, FALSE if not,
99 * as specified in section 2.1.5.18.
100 * OplockCompletionStatus: The NTSTATUS code to return to the server.
101 *
102 * This algorithm simply represents the completion of an oplock request,
103 * as specified in section 2.1.5.17.1 or section 2.1.5.17.2. The server
104 * is expected to associate the return status from this algorithm with
105 * BreakingOplockOpen, which is the Open passed in when it requested
106 * the oplock that is now breaking.
107 *
108 * It is important to note that because several oplocks can be outstanding
109 * in parallel, although this algorithm represents the completion of an
110 * oplock request, it might not result in the completion of the algorithm
111 * that called it. In particular, calling this algorithm will result in
112 * completion of the caller only if BreakingOplockOpen is the same as the
113 * Open with which the calling algorithm was itself called. To mitigate
114 * confusion, each algorithm that refers to this section will specify
115 * whether that algorithm's operation terminates at that point or not.
116 *
117 * The object store MUST return OplockCompletionStatus,
118 * AcknowledgeRequired, and NewOplockLevel to the server (the algorithm is
119 * as specified in section 2.1.5.17.1 and section 2.1.5.17.2).
120 *
121 * Implementation:
122 *
123 * We use two versions of this function:
124 * smb_oplock_ind_break_in_ack
125 * smb_oplock_ind_break
126 *
127 * The first is used when we're handling an Oplock Break Ack.
128 * The second is used when other operations cause a break,
129 * generally in one of the smb_oplock_break_... functions.
130 *
131 * Note that these are call-back functions that may be called with the
132 * node ofile list rwlock held and the node oplock mutex entered, so
133 * these should ONLY schedule oplock break work, and MUST NOT attempt
134 * any actions that might require either of those locks.
135 */
136
137 /*
138 * smb_oplock_ind_break_in_ack
139 *
140 * Variant of smb_oplock_ind_break() for the oplock Ack handler.
141 * When we need to indicate another oplock break from within the
142 * Ack handler (during the Ack. of some previous oplock break)
143 * we need to make sure this new break indication goes out only
144 * AFTER the reply to the current break ack. is sent out.
145 *
146 * In this case, we always have an SR (the break ack) so we can
147 * append the "ind break" work to the current SR and let the
148 * request hander thread do this work after the reply is sent.
149 * Note: this is always an SMB2 or later request, because this
150 * only happens for "granular" oplocks, which are SMB2-only.
151 *
152 * This is mostly the same as smb_oplock_ind_break() except:
153 * - The only CompletionStatus possible is STATUS_CANT_GRANT.
154 * - Instead of taskq_dispatch this appends the new SR to
155 * the "post work" queue on the current SR (if possible).
156 *
157 * Note called with the node ofile list rwlock held and
158 * the oplock mutex entered.
159 */
160 void
smb_oplock_ind_break_in_ack(smb_request_t * ack_sr,smb_ofile_t * ofile,uint32_t NewLevel,boolean_t AckRequired)161 smb_oplock_ind_break_in_ack(smb_request_t *ack_sr, smb_ofile_t *ofile,
162 uint32_t NewLevel, boolean_t AckRequired)
163 {
164 smb_server_t *sv = ofile->f_server;
165 smb_node_t *node = ofile->f_node;
166 smb_request_t *sr = NULL;
167 taskqid_t tqid;
168 boolean_t use_postwork = B_TRUE;
169
170 ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
171 ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
172
173 /*
174 * This should happen only with SMB2 or later,
175 * but in case that ever changes...
176 */
177 if (ack_sr->session->dialect < SMB_VERS_2_BASE) {
178 smb_oplock_ind_break(ofile, NewLevel,
179 AckRequired, STATUS_CANT_GRANT);
180 return;
181 }
182
183 /*
184 * We're going to schedule a request that will have a
185 * reference to this ofile. Get the hold first.
186 */
187 if (!smb_ofile_hold_olbrk(ofile)) {
188 /* It's closing (or whatever). Nothing to do. */
189 return;
190 }
191
192 /*
193 * When called from Ack processing, we want to use a
194 * request on the session doing the ack, so we can
195 * append "post work" to that session. If we can't
196 * allocate a request on that session (because it's
197 * now disconnecting) use a request from the server
198 * session like smb_oplock_ind_break does, and then
199 * use taskq_dispatch instead of postwork.
200 */
201 sr = smb_request_alloc(ack_sr->session, 0);
202 if (sr == NULL) {
203 use_postwork = B_FALSE;
204 sr = smb_request_alloc(sv->sv_session, 0);
205 }
206 if (sr == NULL) {
207 /*
208 * Server must be shutting down. We took a
209 * hold on the ofile that must be released,
210 * but we can't release here because we're
211 * called with the node ofile list entered.
212 * See smb_ofile_release_LL.
213 */
214 smb_llist_post(&node->n_ofile_list, ofile,
215 smb_ofile_release_LL);
216 return;
217 }
218
219 sr->sr_state = SMB_REQ_STATE_SUBMITTED;
220 sr->smb2_async = B_TRUE;
221 sr->user_cr = zone_kcred();
222 sr->fid_ofile = ofile;
223 if (ofile->f_tree != NULL) {
224 sr->tid_tree = ofile->f_tree;
225 smb_tree_hold_internal(sr->tid_tree);
226 }
227 if (ofile->f_user != NULL) {
228 sr->uid_user = ofile->f_user;
229 smb_user_hold_internal(sr->uid_user);
230 }
231 if (ofile->f_lease != NULL)
232 NewLevel |= OPLOCK_LEVEL_GRANULAR;
233
234 sr->arg.olbrk.NewLevel = NewLevel;
235 sr->arg.olbrk.AckRequired = AckRequired;
236
237 /*
238 * Could do this in _hdl_update but this way it's
239 * visible in the dtrace fbt entry probe.
240 */
241 sr->arg.olbrk.OldLevel = ofile->f_oplock.og_breakto;
242
243 smb_oplock_hdl_update(sr);
244
245 if (use_postwork) {
246 /*
247 * Using smb2_cmd_code to indicate what to call.
248 * work func. will call smb_oplock_send_brk
249 */
250 sr->smb2_cmd_code = SMB2_OPLOCK_BREAK;
251 smb2sr_append_postwork(ack_sr, sr);
252 return;
253 }
254
255 /* Will call smb_oplock_send_break */
256 sr->smb2_status = STATUS_CANT_GRANT;
257 tqid = taskq_dispatch(sv->sv_notify_pool,
258 smb_oplock_async_break, sr, TQ_SLEEP);
259 VERIFY(tqid != TASKQID_INVALID);
260 }
261
262 /*
263 * smb_oplock_ind_break
264 *
265 * This is the function described in [MS-FSA] 2.1.5.17.3
266 * which is called many places in the oplock break code.
267 *
268 * Schedule a request & taskq job to do oplock break work
269 * as requested by the FS-level code (smb_cmn_oplock.c).
270 *
271 * See also: smb_oplock_ind_break_in_ack
272 *
273 * Note called with the node ofile list rwlock held and
274 * the oplock mutex entered.
275 */
276 void
smb_oplock_ind_break(smb_ofile_t * ofile,uint32_t NewLevel,boolean_t AckRequired,uint32_t CompletionStatus)277 smb_oplock_ind_break(smb_ofile_t *ofile, uint32_t NewLevel,
278 boolean_t AckRequired, uint32_t CompletionStatus)
279 {
280 smb_server_t *sv = ofile->f_server;
281 smb_node_t *node = ofile->f_node;
282 smb_request_t *sr = NULL;
283 taskqid_t tqid;
284
285 ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
286 ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
287
288 /*
289 * See notes at smb_oplock_async_break re. CompletionStatus
290 * Check for any invalid codes here, so assert happens in
291 * the thread passing an unexpected value.
292 * The real work happens in a taskq job.
293 */
294 switch (CompletionStatus) {
295
296 case NT_STATUS_SUCCESS:
297 case STATUS_CANT_GRANT:
298 /* Send break via taskq job. */
299 break;
300
301 case STATUS_NEW_HANDLE:
302 smb_oplock_hdl_moved(ofile);
303 return;
304
305 case NT_STATUS_OPLOCK_HANDLE_CLOSED:
306 smb_oplock_hdl_closed(ofile);
307 return;
308
309 default:
310 ASSERT(0);
311 return;
312 }
313
314 /*
315 * We're going to schedule a request that will have a
316 * reference to this ofile. Get the hold first.
317 */
318 if (!smb_ofile_hold_olbrk(ofile)) {
319 /* It's closing (or whatever). Nothing to do. */
320 return;
321 }
322
323 /*
324 * We need a request allocated on the session that owns
325 * this ofile in order to safely send on that session.
326 *
327 * Note that while we hold a ref. on the ofile, it's
328 * f_session will not change. An ofile in state
329 * _ORPHANED will have f_session == NULL, but the
330 * f_session won't _change_ while we have a ref,
331 * and won't be torn down under our feet.
332 * Same for f_tree and f_user
333 *
334 * If f_session is NULL, or it's in a state that doesn't
335 * allow new requests, use the special "server" session.
336 */
337 if (ofile->f_session != NULL)
338 sr = smb_request_alloc(ofile->f_session, 0);
339 if (sr == NULL)
340 sr = smb_request_alloc(sv->sv_session, 0);
341 if (sr == NULL) {
342 /*
343 * Server must be shutting down. We took a
344 * hold on the ofile that must be released,
345 * but we can't release here because we're
346 * called with the node ofile list entered.
347 * See smb_ofile_release_LL.
348 */
349 smb_llist_post(&node->n_ofile_list, ofile,
350 smb_ofile_release_LL);
351 return;
352 }
353
354 sr->sr_state = SMB_REQ_STATE_SUBMITTED;
355 sr->smb2_async = B_TRUE;
356 sr->user_cr = zone_kcred();
357 sr->fid_ofile = ofile;
358 if (ofile->f_tree != NULL) {
359 sr->tid_tree = ofile->f_tree;
360 smb_tree_hold_internal(sr->tid_tree);
361 }
362 if (ofile->f_user != NULL) {
363 sr->uid_user = ofile->f_user;
364 smb_user_hold_internal(sr->uid_user);
365 }
366 if (ofile->f_lease != NULL)
367 NewLevel |= OPLOCK_LEVEL_GRANULAR;
368
369 sr->arg.olbrk.NewLevel = NewLevel;
370 sr->arg.olbrk.AckRequired = AckRequired;
371 sr->smb2_status = CompletionStatus;
372
373 /*
374 * Could do this in _hdl_update but this way it's
375 * visible in the dtrace fbt entry probe.
376 */
377 sr->arg.olbrk.OldLevel = ofile->f_oplock.og_breakto;
378
379 smb_oplock_hdl_update(sr);
380
381 /* Will call smb_oplock_send_break */
382 tqid = taskq_dispatch(sv->sv_notify_pool,
383 smb_oplock_async_break, sr, TQ_SLEEP);
384 VERIFY(tqid != TASKQID_INVALID);
385 }
386
387 /*
388 * smb_oplock_async_break
389 *
390 * Called via the taskq to handle an asynchronous oplock break.
391 * We have a hold on the ofile, which will be released in
392 * smb_request_free (via sr->fid_ofile)
393 *
394 * Note we may have: sr->uid_user == NULL, sr->tid_tree == NULL.
395 */
396 static void
smb_oplock_async_break(void * arg)397 smb_oplock_async_break(void *arg)
398 {
399 smb_request_t *sr = arg;
400 uint32_t CompletionStatus;
401
402 SMB_REQ_VALID(sr);
403
404 CompletionStatus = sr->smb2_status;
405 sr->smb2_status = NT_STATUS_SUCCESS;
406
407 mutex_enter(&sr->sr_mutex);
408 sr->sr_worker = curthread;
409 sr->sr_state = SMB_REQ_STATE_ACTIVE;
410 mutex_exit(&sr->sr_mutex);
411
412 /*
413 * Note that the CompletionStatus from the FS level
414 * (smb_cmn_oplock.c) encodes what kind of action we
415 * need to take at the SMB level.
416 */
417 switch (CompletionStatus) {
418
419 case STATUS_CANT_GRANT:
420 case NT_STATUS_SUCCESS:
421 smb_oplock_send_break(sr);
422 break;
423
424 default:
425 /* Checked by caller. */
426 ASSERT(0);
427 break;
428 }
429
430 if (sr->dh_nvl_dirty) {
431 sr->dh_nvl_dirty = B_FALSE;
432 smb2_dh_update_nvfile(sr);
433 }
434
435 sr->sr_state = SMB_REQ_STATE_COMPLETED;
436 smb_request_free(sr);
437 }
438
439 /*
440 * Send an oplock (or lease) break to the client.
441 * If we can't, then do a local break.
442 *
443 * This is called either from smb_oplock_async_break via a
444 * taskq job scheduled in smb_oplock_ind_break, or from the
445 * smb2sr_append_postwork() mechanism when we're doing a
446 * "break in ack", via smb_oplock_ind_break_in_ack.
447 *
448 * We don't always have an sr->session here, so
449 * determine the oplock type (lease etc) from
450 * f_lease and f_oplock.og_dialect etc.
451 */
452 void
smb_oplock_send_break(smb_request_t * sr)453 smb_oplock_send_break(smb_request_t *sr)
454 {
455 smb_ofile_t *ofile = sr->fid_ofile;
456
457 if (ofile->f_lease != NULL)
458 smb2_lease_send_break(sr);
459 else if (ofile->f_oplock.og_dialect >= SMB_VERS_2_BASE)
460 smb2_oplock_send_break(sr);
461 else
462 smb1_oplock_send_break(sr);
463 }
464
465 /*
466 * Called by smb_oplock_ind_break for the case STATUS_NEW_HANDLE,
467 * which is an alias for NT_STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE.
468 *
469 * The FS-level oplock layer calls this to update the SMB-level state
470 * when the oplock for some lease is about to move to a different
471 * ofile on the lease.
472 *
473 * To avoid later confusion, clear og_state on this ofile now.
474 * Without this, smb_oplock_move() may issue debug complaints
475 * about moving oplock state onto a non-empty oplock.
476 */
477 static const smb_ofile_t invalid_ofile;
478 static void
smb_oplock_hdl_moved(smb_ofile_t * ofile)479 smb_oplock_hdl_moved(smb_ofile_t *ofile)
480 {
481 smb_lease_t *ls = ofile->f_lease;
482
483 ASSERT(ls != NULL);
484 if (ls != NULL && ls->ls_oplock_ofile == ofile)
485 ls->ls_oplock_ofile = (smb_ofile_t *)&invalid_ofile;
486
487 ofile->f_oplock.og_state = 0;
488 ofile->f_oplock.og_breakto = 0;
489 ofile->f_oplock.og_breaking = B_FALSE;
490 }
491
492 /*
493 * See: NT_STATUS_OPLOCK_HANDLE_CLOSED above and
494 * smb_ofile_close, smb_oplock_break_CLOSE.
495 *
496 * The FS-level oplock layer calls this to update the
497 * SMB-level state when a handle loses its oplock.
498 */
499 static void
smb_oplock_hdl_closed(smb_ofile_t * ofile)500 smb_oplock_hdl_closed(smb_ofile_t *ofile)
501 {
502 smb_lease_t *lease = ofile->f_lease;
503
504 if (lease != NULL) {
505 if (lease->ls_oplock_ofile == ofile) {
506 /*
507 * smb2_lease_ofile_close should have
508 * moved the oplock to another ofile.
509 */
510 ASSERT(0);
511 lease->ls_oplock_ofile = NULL;
512 }
513 }
514 ofile->f_oplock.og_state = 0;
515 ofile->f_oplock.og_breakto = 0;
516 ofile->f_oplock.og_breaking = B_FALSE;
517 }
518
519 /*
520 * smb_oplock_hdl_update
521 *
522 * Called by smb_oplock_ind_break (and ...in_ack) just before we
523 * schedule smb_oplock_async_break / mb_oplock_send_break taskq job,
524 * so we can make any state changes that should happen immediately.
525 *
526 * Here, keep track of what we will send to the client.
527 * Saves old state in arg.olbck.OldLevel
528 *
529 * Note that because we may be in the midst of processing an
530 * smb_oplock_ack_break call here, the _breaking flag will be
531 * temporarily false, and is set true again if this ack causes
532 * another break. This makes it tricky to know when to update
533 * the epoch, which is not supposed to increment when there's
534 * already an unacknowledged break out to the client.
535 * We can recognize that by comparing ls_state vs ls_breakto.
536 * If no unacknowledged break, ls_state == ls_breakto.
537 */
538 static void
smb_oplock_hdl_update(smb_request_t * sr)539 smb_oplock_hdl_update(smb_request_t *sr)
540 {
541 smb_ofile_t *ofile = sr->fid_ofile;
542 smb_lease_t *lease = ofile->f_lease;
543 uint32_t NewLevel = sr->arg.olbrk.NewLevel;
544 boolean_t AckReq = sr->arg.olbrk.AckRequired;
545
546 #ifdef DEBUG
547 smb_node_t *node = ofile->f_node;
548 ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
549 ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
550 #endif
551
552 /* Caller sets arg.olbrk.OldLevel */
553 ofile->f_oplock.og_breakto = NewLevel;
554 ofile->f_oplock.og_breaking = B_TRUE;
555 if (lease != NULL) {
556 // If no unacknowledged break, update epoch.
557 if (lease->ls_breakto == lease->ls_state)
558 lease->ls_epoch++;
559
560 lease->ls_breakto = NewLevel;
561 lease->ls_breaking = B_TRUE;
562 }
563
564 if (!AckReq) {
565 /*
566 * Not expecting an Ack from the client.
567 * Update state immediately.
568 */
569 ofile->f_oplock.og_state = NewLevel;
570 ofile->f_oplock.og_breaking = B_FALSE;
571 if (lease != NULL) {
572 lease->ls_state = NewLevel;
573 lease->ls_breaking = B_FALSE;
574 }
575 if (ofile->dh_persist) {
576 smb2_dh_update_oplock(sr, ofile);
577 }
578 }
579 }
580
581 /*
582 * Helper for smb_ofile_close
583 *
584 * Note that a client may close an ofile in response to an
585 * oplock break or lease break intead of doing an Ack break,
586 * so this must wake anything that might be waiting on an ack.
587 */
588 void
smb_oplock_close(smb_ofile_t * ofile)589 smb_oplock_close(smb_ofile_t *ofile)
590 {
591 smb_node_t *node = ofile->f_node;
592
593 smb_llist_enter(&node->n_ofile_list, RW_READER);
594 mutex_enter(&node->n_oplock.ol_mutex);
595
596 if (ofile->f_oplock_closing == B_FALSE) {
597 ofile->f_oplock_closing = B_TRUE;
598
599 if (ofile->f_lease != NULL)
600 smb2_lease_ofile_close(ofile);
601
602 smb_oplock_break_CLOSE(node, ofile);
603
604 ofile->f_oplock.og_state = 0;
605 ofile->f_oplock.og_breakto = 0;
606 ofile->f_oplock.og_breaking = B_FALSE;
607 cv_broadcast(&ofile->f_oplock.og_ack_cv);
608 }
609
610 mutex_exit(&node->n_oplock.ol_mutex);
611 smb_llist_exit(&node->n_ofile_list);
612 }
613
614 /*
615 * Called by smb_request_cancel() via sr->cancel_method
616 * Arg is the smb_node_t with the breaking oplock.
617 */
618 static void
smb_oplock_wait_ack_cancel(smb_request_t * sr)619 smb_oplock_wait_ack_cancel(smb_request_t *sr)
620 {
621 kcondvar_t *cvp = sr->cancel_arg2;
622 smb_ofile_t *ofile = sr->fid_ofile;
623 smb_node_t *node = ofile->f_node;
624
625 mutex_enter(&node->n_oplock.ol_mutex);
626 cv_broadcast(cvp);
627 mutex_exit(&node->n_oplock.ol_mutex);
628 }
629
630 /*
631 * Wait for an oplock break ACK to arrive. This is called after
632 * we've sent an oplock break or lease break to the client where
633 * an "Ack break" is expected back. If we get an Ack, that will
634 * wake us up via smb2_oplock_break_ack or smb2_lease_break_ack.
635 *
636 * Wait until state reduced to NewLevel (or less).
637 * Note that in multi-break cases, we might wait here for just
638 * one ack when another has become pending, in which case the
639 * og_breakto might be a subset of NewLevel. Wait until the
640 * state field is no longer a superset of NewLevel.
641 */
642 uint32_t
smb_oplock_wait_ack(smb_request_t * sr,uint32_t NewLevel)643 smb_oplock_wait_ack(smb_request_t *sr, uint32_t NewLevel)
644 {
645 smb_ofile_t *ofile = sr->fid_ofile;
646 smb_lease_t *lease = ofile->f_lease;
647 smb_node_t *node = ofile->f_node;
648 smb_oplock_t *ol = &node->n_oplock;
649 uint32_t *state_p;
650 kcondvar_t *cv_p;
651 clock_t time, rv;
652 uint32_t status = 0;
653 smb_req_state_t srstate;
654 uint32_t wait_mask;
655
656 time = ddi_get_lbolt() +
657 MSEC_TO_TICK(smb_oplock_timeout_ack);
658
659 /*
660 * Wait on either lease state or oplock state
661 */
662 if (lease != NULL) {
663 state_p = &lease->ls_state;
664 cv_p = &lease->ls_ack_cv;
665 } else {
666 state_p = &ofile->f_oplock.og_state;
667 cv_p = &ofile->f_oplock.og_ack_cv;
668 }
669
670 /*
671 * These are all the bits that we wait to be cleared.
672 */
673 wait_mask = ~NewLevel & (CACHE_RWH |
674 LEVEL_TWO | LEVEL_ONE | LEVEL_BATCH);
675
676 /*
677 * Setup cancellation callback
678 */
679 mutex_enter(&sr->sr_mutex);
680 if (sr->sr_state != SMB_REQ_STATE_ACTIVE) {
681 mutex_exit(&sr->sr_mutex);
682 return (NT_STATUS_CANCELLED);
683 }
684 sr->sr_state = SMB_REQ_STATE_WAITING_OLBRK;
685 sr->cancel_method = smb_oplock_wait_ack_cancel;
686 sr->cancel_arg2 = cv_p;
687 mutex_exit(&sr->sr_mutex);
688
689 /*
690 * Enter the wait loop
691 */
692 mutex_enter(&ol->ol_mutex);
693
694 while ((*state_p & wait_mask) != 0) {
695 rv = cv_timedwait(cv_p, &ol->ol_mutex, time);
696 if (rv < 0) {
697 /* cv_timewait timeout */
698 char *fname;
699 char *opname;
700 int rc;
701
702 /*
703 * Get the path name of the open file
704 */
705 fname = smb_srm_zalloc(sr, MAXPATHLEN);
706 rc = smb_node_getpath(node, NULL, fname, MAXPATHLEN);
707 if (rc != 0) {
708 /* Not expected. Just show last part. */
709 (void) snprintf(fname, MAXPATHLEN, "(?)/%s",
710 node->od_name);
711 }
712
713 /*
714 * Get an operation name reflecting which kind of
715 * lease or oplock break got us here, so the log
716 * message will say "lease break" or whatever.
717 */
718 if (lease != NULL) {
719 opname = "lease";
720 } else if (ofile->f_oplock.og_dialect >=
721 SMB_VERS_2_BASE) {
722 opname = "oplock2";
723 } else {
724 opname = "oplock1";
725 }
726
727 cmn_err(CE_NOTE, "!client %s %s break timeout for %s",
728 sr->session->ip_addr_str, opname, fname);
729
730 status = NT_STATUS_CANNOT_BREAK_OPLOCK;
731 break;
732 }
733
734 /*
735 * Check if we were woken by smb_request_cancel,
736 * which sets state SMB_REQ_STATE_CANCEL_PENDING
737 * and signals the CV. The mutex enter/exit is
738 * just to ensure cache visibility of sr_state
739 * that was updated in smb_request_cancel.
740 */
741 mutex_enter(&sr->sr_mutex);
742 srstate = sr->sr_state;
743 mutex_exit(&sr->sr_mutex);
744 if (srstate != SMB_REQ_STATE_WAITING_OLBRK) {
745 break;
746 }
747 }
748 mutex_exit(&ol->ol_mutex);
749
750 /*
751 * See if it completed or if it was cancelled.
752 */
753 mutex_enter(&sr->sr_mutex);
754 switch_state:
755 switch (sr->sr_state) {
756 case SMB_REQ_STATE_WAITING_OLBRK:
757 /* Normal wakeup. Keep status from above. */
758 sr->sr_state = SMB_REQ_STATE_ACTIVE;
759 /* status from above */
760 break;
761 case SMB_REQ_STATE_CANCEL_PENDING:
762 /* cancel_method running. wait. */
763 cv_wait(&sr->sr_st_cv, &sr->sr_mutex);
764 goto switch_state;
765 case SMB_REQ_STATE_CANCELLED:
766 status = NT_STATUS_CANCELLED;
767 break;
768 default:
769 status = NT_STATUS_INTERNAL_ERROR;
770 break;
771 }
772 sr->cancel_method = NULL;
773 sr->cancel_arg2 = NULL;
774 mutex_exit(&sr->sr_mutex);
775
776 return (status);
777 }
778
779 /*
780 * Called by smb_request_cancel() via sr->cancel_method
781 * Arg is the smb_node_t with the breaking oplock.
782 */
783 static void
smb_oplock_wait_break_cancel(smb_request_t * sr)784 smb_oplock_wait_break_cancel(smb_request_t *sr)
785 {
786 smb_node_t *node = sr->cancel_arg2;
787 smb_oplock_t *ol;
788
789 SMB_NODE_VALID(node);
790 ol = &node->n_oplock;
791
792 mutex_enter(&ol->ol_mutex);
793 cv_broadcast(&ol->WaitingOpenCV);
794 mutex_exit(&ol->ol_mutex);
795 }
796
797 /*
798 * Wait up to "timeout" mSec. for the current oplock "breaking" flags
799 * to be cleared (by smb_oplock_ack_break or smb_oplock_break_CLOSE).
800 *
801 * Callers of the above public oplock functions:
802 * smb_oplock_request()
803 * smb_oplock_ack_break()
804 * smb_oplock_break_OPEN() ...
805 * check for return status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS
806 * and call this function to wait for the break to complete.
807 *
808 * Most callers should use this default timeout, which they get
809 * by passing zero as the timeout arg. This include places where
810 * we're about to do something that invalidates some cache.
811 */
812 uint32_t
smb_oplock_wait_break(smb_request_t * sr,smb_node_t * node,int timeout)813 smb_oplock_wait_break(smb_request_t *sr, smb_node_t *node, int timeout)
814 {
815 smb_oplock_t *ol;
816 clock_t time, rv;
817 uint32_t status = 0;
818 smb_req_state_t srstate;
819
820 SMB_NODE_VALID(node);
821 ol = &node->n_oplock;
822
823 if (timeout == 0)
824 timeout = smb_oplock_timeout_def;
825 time = MSEC_TO_TICK(timeout) + ddi_get_lbolt();
826
827 /*
828 * Setup cancellation callback
829 */
830 mutex_enter(&sr->sr_mutex);
831 if (sr->sr_state != SMB_REQ_STATE_ACTIVE) {
832 mutex_exit(&sr->sr_mutex);
833 return (NT_STATUS_CANCELLED);
834 }
835 sr->sr_state = SMB_REQ_STATE_WAITING_OLBRK;
836 sr->cancel_method = smb_oplock_wait_break_cancel;
837 sr->cancel_arg2 = node;
838 mutex_exit(&sr->sr_mutex);
839
840 mutex_enter(&ol->ol_mutex);
841 while ((ol->ol_state & BREAK_ANY) != 0) {
842 ol->waiters++;
843 rv = cv_timedwait(&ol->WaitingOpenCV,
844 &ol->ol_mutex, time);
845 ol->waiters--;
846 if (rv < 0) {
847 /* cv_timewait timeout */
848 status = NT_STATUS_CANNOT_BREAK_OPLOCK;
849 break;
850 }
851
852 /*
853 * Check if we were woken by smb_request_cancel,
854 * which sets state SMB_REQ_STATE_CANCEL_PENDING
855 * and signals the CV. The mutex enter/exit is
856 * just to ensure cache visibility of sr_state
857 * that was updated in smb_request_cancel.
858 */
859 mutex_enter(&sr->sr_mutex);
860 srstate = sr->sr_state;
861 mutex_exit(&sr->sr_mutex);
862 if (srstate != SMB_REQ_STATE_WAITING_OLBRK) {
863 break;
864 }
865 }
866 mutex_exit(&ol->ol_mutex);
867
868 /*
869 * Check whether it completed or was cancelled.
870 */
871 mutex_enter(&sr->sr_mutex);
872 switch_state:
873 switch (sr->sr_state) {
874 case SMB_REQ_STATE_WAITING_OLBRK:
875 /* Normal wakeup. Keep status from above. */
876 sr->sr_state = SMB_REQ_STATE_ACTIVE;
877 break;
878 case SMB_REQ_STATE_CANCEL_PENDING:
879 /* cancel_method running. wait. */
880 cv_wait(&sr->sr_st_cv, &sr->sr_mutex);
881 goto switch_state;
882 case SMB_REQ_STATE_CANCELLED:
883 status = NT_STATUS_CANCELLED;
884 break;
885 default:
886 status = NT_STATUS_INTERNAL_ERROR;
887 break;
888 }
889 sr->cancel_method = NULL;
890 sr->cancel_arg2 = NULL;
891 mutex_exit(&sr->sr_mutex);
892
893 return (status);
894 }
895
896 /*
897 * Simplified version used in smb_fem.c, like above,
898 * but no smb_request_cancel stuff.
899 */
900 uint32_t
smb_oplock_wait_break_fem(smb_node_t * node,int timeout)901 smb_oplock_wait_break_fem(smb_node_t *node, int timeout) /* mSec. */
902 {
903 smb_oplock_t *ol;
904 clock_t time, rv;
905 uint32_t status = 0;
906
907 if (timeout == 0)
908 timeout = smb_oplock_timeout_def;
909
910 SMB_NODE_VALID(node);
911 ol = &node->n_oplock;
912
913 mutex_enter(&ol->ol_mutex);
914 time = MSEC_TO_TICK(timeout) + ddi_get_lbolt();
915
916 while ((ol->ol_state & BREAK_ANY) != 0) {
917 ol->waiters++;
918 rv = cv_timedwait(&ol->WaitingOpenCV,
919 &ol->ol_mutex, time);
920 ol->waiters--;
921 if (rv < 0) {
922 status = NT_STATUS_CANNOT_BREAK_OPLOCK;
923 break;
924 }
925 }
926
927 mutex_exit(&ol->ol_mutex);
928
929 return (status);
930 }
931