xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_srv_oplock.c (revision 1a065e93eee983124652c3eb0cfdcb4776cd89ab)
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  */
15 
16 /*
17  * (SMB1/SMB2) Server-level Oplock support.
18  *
19  * Conceptually, this is a separate layer on top of the
20  * file system (FS) layer oplock code in smb_cmn_oplock.c.
21  * If these layers were more distinct, the FS layer would
22  * need to use call-back functions (installed from here)
23  * to "indicate an oplock break to the server" (see below).
24  * As these layers are all in the same kernel module, the
25  * delivery of these break indications just uses a direct
26  * function call to smb_oplock_ind_break() below.
27  *
28  * This layer is responsible for handling the break indication,
29  * which often requires scheduling a taskq job in the server,
30  * and sending an oplock break mesage to the client using
31  * the appropriate protocol for the open handle affected.
32  *
33  * The details of composing an oplock break message, the
34  * protocol-specific details of requesting an oplock, and
35  * returning that oplock to the client are in the files:
36  *  smb_oplock.c, smb2_oplock.c, smb2_lease.c
37  */
38 
39 #include <smbsrv/smb2_kproto.h>
40 #include <smbsrv/smb_oplock.h>
41 
42 /*
43  * Verify relationship between BREAK_TO_... and CACHE bits,
44  * used when setting the BREAK_TO_... below.
45  */
46 #if BREAK_TO_READ_CACHING != (READ_CACHING << BREAK_SHIFT)
47 #error "BREAK_TO_READ_CACHING"
48 #endif
49 #if BREAK_TO_HANDLE_CACHING != (HANDLE_CACHING << BREAK_SHIFT)
50 #error "BREAK_TO_HANDLE_CACHING"
51 #endif
52 #if BREAK_TO_WRITE_CACHING != (WRITE_CACHING << BREAK_SHIFT)
53 #error "BREAK_TO_WRITE_CACHING"
54 #endif
55 #define	CACHE_RWH (READ_CACHING | WRITE_CACHING | HANDLE_CACHING)
56 
57 /*
58  * This is the timeout used in the thread that sends an
59  * oplock break and waits for the client to respond
60  * before it breaks the oplock locally.
61  */
62 int smb_oplock_timeout_ack = 30000; /* mSec. */
63 
64 /*
65  * This is the timeout used in threads that have just
66  * finished some sort of oplock request and now must
67  * wait for (possibly multiple) breaks to complete.
68  * This value must be at least a couple seconds LONGER
69  * than the ack timeout above so that I/O callers won't
70  * give up waiting before the local ack timeout.
71  */
72 int smb_oplock_timeout_def = 45000; /* mSec. */
73 
74 static void smb_oplock_async_break(void *);
75 static void smb_oplock_hdl_clear(smb_ofile_t *);
76 
77 
78 /*
79  * 2.1.5.17.3 Indicating an Oplock Break to the Server
80  *
81  * The inputs for indicating an oplock break to the server are:
82  *
83  *	BreakingOplockOpen: The Open used to request the oplock
84  *	  that is now breaking.
85  *	 NewOplockLevel: The type of oplock the requested oplock
86  *	  has been broken to.  Valid values are as follows:
87  *		LEVEL_NONE (that is, no oplock)
88  *		LEVEL_TWO
89  *		A combination of one or more of the following flags:
90  *			READ_CACHING
91  *			HANDLE_CACHING
92  *			WRITE_CACHING
93  *	AcknowledgeRequired: A Boolean value; TRUE if the server
94  *	  MUST acknowledge the oplock break, FALSE if not,
95  *	  as specified in section 2.1.5.18.
96  *	OplockCompletionStatus: The NTSTATUS code to return to the server.
97  *
98  * This algorithm simply represents the completion of an oplock request,
99  * as specified in section 2.1.5.17.1 or section 2.1.5.17.2. The server
100  * is expected to associate the return status from this algorithm with
101  * BreakingOplockOpen, which is the Open passed in when it requested
102  * the oplock that is now breaking.
103  *
104  * It is important to note that because several oplocks can be outstanding
105  * in parallel, although this algorithm represents the completion of an
106  * oplock request, it might not result in the completion of the algorithm
107  * that called it. In particular, calling this algorithm will result in
108  * completion of the caller only if BreakingOplockOpen is the same as the
109  * Open with which the calling algorithm was itself called. To mitigate
110  * confusion, each algorithm that refers to this section will specify
111  * whether that algorithm's operation terminates at that point or not.
112  *
113  * The object store MUST return OplockCompletionStatus,
114  * AcknowledgeRequired, and NewOplockLevel to the server (the algorithm is
115  * as specified in section 2.1.5.17.1 and section 2.1.5.17.2).
116  *
117  * Implementation:
118  *
119  * We use two versions of this function:
120  *	smb_oplock_ind_break_in_ack
121  *	smb_oplock_ind_break
122  *
123  * The first is used when we're handling an Oplock Break Ack.
124  * The second is used when other operations cause a break,
125  * generally in one of the smb_oplock_break_... functions.
126  *
127  * Note that these are call-back functions that may be called with the
128  * node ofile list rwlock held and the node oplock mutex entered, so
129  * these should ONLY schedule oplock break work, and MUST NOT attempt
130  * any actions that might require either of those locks.
131  */
132 
133 /*
134  * smb_oplock_ind_break_in_ack
135  *
136  * Variant of smb_oplock_ind_break() for the oplock Ack handler.
137  * When we need to indicate another oplock break from within the
138  * Ack handler (during the Ack. of some previous oplock break)
139  * we need to make sure this new break indication goes out only
140  * AFTER the reply to the current break ack. is sent out.
141  *
142  * In this case, we always have an SR (the break ack) so we can
143  * append the "ind break" work to the current SR and let the
144  * request hander thread do this work after the reply is sent.
145  * Note: this is always an SMB2 or later request, because this
146  * only happens for "granular" oplocks, which are SMB2-only.
147  *
148  * This is mostly the same as smb_oplock_ind_break() except:
149  * - The only CompletionStatus possible is STATUS_CANT_GRANT.
150  * - Instead of taskq_dispatch this appends the new SR to
151  *   the "post work" queue on the current SR.
152  *
153  * Note called with the node ofile list rwlock held and
154  * the oplock mutex entered.
155  */
156 void
157 smb_oplock_ind_break_in_ack(smb_request_t *ack_sr, smb_ofile_t *ofile,
158     uint32_t NewLevel, boolean_t AckRequired)
159 {
160 	smb_request_t *new_sr;
161 
162 	/*
163 	 * This should happen only with SMB2 or later,
164 	 * but in case that ever changes...
165 	 */
166 	if (ack_sr->session->dialect < SMB_VERS_2_BASE) {
167 		smb_oplock_ind_break(ofile, NewLevel,
168 		    AckRequired, STATUS_CANT_GRANT);
169 		return;
170 	}
171 
172 	/*
173 	 * We're going to schedule a request that will have a
174 	 * reference to this ofile. Get the hold first.
175 	 */
176 	if (ofile->f_oplock.og_closing ||
177 	    !smb_ofile_hold_olbrk(ofile)) {
178 		/* It's closing (or whatever).  Nothing to do. */
179 		return;
180 	}
181 
182 	/*
183 	 * When called from Ack processing, we want to use a
184 	 * request on the session doing the ack.  If we can't
185 	 * allocate a request on that session (because it's
186 	 * now disconnecting) just fall-back to the normal
187 	 * oplock break code path which deals with that.
188 	 * Once we have a request on the ack session, that
189 	 * session won't go away until the request is done.
190 	 */
191 	new_sr = smb_request_alloc(ack_sr->session, 0);
192 	if (new_sr == NULL) {
193 		smb_oplock_ind_break(ofile, NewLevel,
194 		    AckRequired, STATUS_CANT_GRANT);
195 		smb_ofile_release(ofile);
196 		return;
197 	}
198 
199 	new_sr->sr_state = SMB_REQ_STATE_SUBMITTED;
200 	new_sr->smb2_async = B_TRUE;
201 	new_sr->user_cr = zone_kcred();
202 	new_sr->fid_ofile = ofile;
203 	if (ofile->f_tree != NULL) {
204 		new_sr->tid_tree = ofile->f_tree;
205 		smb_tree_hold_internal(ofile->f_tree);
206 	}
207 	if (ofile->f_user != NULL) {
208 		new_sr->uid_user = ofile->f_user;
209 		smb_user_hold_internal(ofile->f_user);
210 	}
211 	new_sr->arg.olbrk.NewLevel = NewLevel;
212 	new_sr->arg.olbrk.AckRequired = AckRequired;
213 
214 	/*
215 	 * Using smb2_cmd_code to indicate what to call.
216 	 * work func. will call smb_oplock_send_brk
217 	 */
218 	new_sr->smb2_cmd_code = SMB2_OPLOCK_BREAK;
219 	smb2sr_append_postwork(ack_sr, new_sr);
220 }
221 
222 /*
223  * smb_oplock_ind_break
224  *
225  * This is the function described in [MS-FSA] 2.1.5.17.3
226  * which is called many places in the oplock break code.
227  *
228  * Schedule a request & taskq job to do oplock break work
229  * as requested by the FS-level code (smb_cmn_oplock.c).
230  *
231  * Note called with the node ofile list rwlock held and
232  * the oplock mutex entered.
233  */
234 void
235 smb_oplock_ind_break(smb_ofile_t *ofile, uint32_t NewLevel,
236     boolean_t AckRequired, uint32_t CompletionStatus)
237 {
238 	smb_server_t *sv = ofile->f_server;
239 	smb_request_t *sr = NULL;
240 
241 	/*
242 	 * See notes at smb_oplock_async_break re. CompletionStatus
243 	 * Check for any invalid codes here, so assert happens in
244 	 * the thread passing an unexpected value.
245 	 * The real work happens in a taskq job.
246 	 */
247 	switch (CompletionStatus) {
248 
249 	case NT_STATUS_SUCCESS:
250 	case STATUS_CANT_GRANT:
251 		/* Send break via taskq job. */
252 		break;
253 
254 	case STATUS_NEW_HANDLE:
255 	case NT_STATUS_OPLOCK_HANDLE_CLOSED:
256 		smb_oplock_hdl_clear(ofile);
257 		return;
258 
259 	default:
260 		ASSERT(0);
261 		return;
262 	}
263 
264 	/*
265 	 * We're going to schedule a request that will have a
266 	 * reference to this ofile. Get the hold first.
267 	 */
268 	if (ofile->f_oplock.og_closing ||
269 	    !smb_ofile_hold_olbrk(ofile)) {
270 		/* It's closing (or whatever).  Nothing to do. */
271 		return;
272 	}
273 
274 	/*
275 	 * We need a request allocated on the session that owns
276 	 * this ofile in order to safely send on that session.
277 	 *
278 	 * Note that while we hold a ref. on the ofile, it's
279 	 * f_session will not change.  An ofile in state
280 	 * _ORPHANED will have f_session == NULL, but the
281 	 * f_session won't _change_ while we have a ref,
282 	 * and won't be torn down under our feet.
283 	 * Same for f_tree and f_user
284 	 *
285 	 * If f_session is NULL, or it's in a state that doesn't
286 	 * allow new requests, use the special "server" session.
287 	 */
288 	if (ofile->f_session != NULL)
289 		sr = smb_request_alloc(ofile->f_session, 0);
290 	if (sr == NULL)
291 		sr = smb_request_alloc(sv->sv_session, 0);
292 
293 	sr->sr_state = SMB_REQ_STATE_SUBMITTED;
294 	sr->smb2_async = B_TRUE;
295 	sr->user_cr = zone_kcred();
296 	sr->fid_ofile = ofile;
297 	if (ofile->f_tree != NULL) {
298 		sr->tid_tree = ofile->f_tree;
299 		smb_tree_hold_internal(sr->tid_tree);
300 	}
301 	if (ofile->f_user != NULL) {
302 		sr->uid_user = ofile->f_user;
303 		smb_user_hold_internal(sr->uid_user);
304 	}
305 	sr->arg.olbrk.NewLevel = NewLevel;
306 	sr->arg.olbrk.AckRequired = AckRequired;
307 	sr->smb2_status = CompletionStatus;
308 
309 	(void) taskq_dispatch(
310 	    sv->sv_worker_pool,
311 	    smb_oplock_async_break, sr, TQ_SLEEP);
312 }
313 
314 /*
315  * smb_oplock_async_break
316  *
317  * Called via the taskq to handle an asynchronous oplock break.
318  * We have a hold on the ofile, which will be released in
319  * smb_request_free (via sr->fid_ofile)
320  *
321  * Note we have: sr->uid_user == NULL, sr->tid_tree == NULL.
322  * Nothing called here needs those.
323  *
324  * Note that NewLevel as provided by the FS up-call does NOT
325  * include the GRANULAR flag.  The SMB level is expected to
326  * keep track of how each oplock was acquired (by lease or
327  * traditional oplock request) and put the GRANULAR flag
328  * back into the oplock state when calling down to the
329  * FS-level code.  Also note that the lease break message
330  * carries only the cache flags, not the GRANULAR flag.
331  */
332 static void
333 smb_oplock_async_break(void *arg)
334 {
335 	smb_request_t	*sr = arg;
336 	uint32_t	CompletionStatus;
337 
338 	SMB_REQ_VALID(sr);
339 
340 	CompletionStatus = sr->smb2_status;
341 	sr->smb2_status = NT_STATUS_SUCCESS;
342 
343 	mutex_enter(&sr->sr_mutex);
344 	sr->sr_worker = curthread;
345 	sr->sr_state = SMB_REQ_STATE_ACTIVE;
346 	mutex_exit(&sr->sr_mutex);
347 
348 	/*
349 	 * Note that the CompletionStatus from the FS level
350 	 * (smb_cmn_oplock.c) encodes what kind of action we
351 	 * need to take at the SMB level.
352 	 */
353 	switch (CompletionStatus) {
354 
355 	case STATUS_CANT_GRANT:
356 	case NT_STATUS_SUCCESS:
357 		smb_oplock_send_brk(sr);
358 		break;
359 
360 	default:
361 		/* Checked by caller. */
362 		ASSERT(0);
363 		break;
364 	}
365 
366 	if (sr->dh_nvl_dirty) {
367 		sr->dh_nvl_dirty = B_FALSE;
368 		smb2_dh_update_nvfile(sr);
369 	}
370 
371 	sr->sr_state = SMB_REQ_STATE_COMPLETED;
372 	smb_request_free(sr);
373 }
374 
375 #ifdef DEBUG
376 int smb_oplock_debug_wait = 0;
377 #endif
378 
379 /*
380  * Send an oplock break over the wire, or if we can't,
381  * then process the oplock break locally.
382  *
383  * Note that we have sr->fid_ofile here but all the other
384  * normal sr members may be NULL:  uid_user, tid_tree.
385  * Also sr->session may or may not be the same session as
386  * the ofile came from (ofile->f_session) depending on
387  * whether this is a "live" open or an orphaned DH,
388  * where ofile->f_session will be NULL.
389  *
390  * Given that we don't always have a session, we determine
391  * the oplock type (lease etc) from f_oplock.og_dialect.
392  */
393 void
394 smb_oplock_send_brk(smb_request_t *sr)
395 {
396 	smb_ofile_t	*ofile;
397 	smb_lease_t	*lease;
398 	uint32_t	NewLevel;
399 	boolean_t	AckReq;
400 	uint32_t	status;
401 	int		rc;
402 
403 	ofile = sr->fid_ofile;
404 	NewLevel = sr->arg.olbrk.NewLevel;
405 	AckReq = sr->arg.olbrk.AckRequired;
406 	lease = ofile->f_lease;
407 
408 	/*
409 	 * Build the break message in sr->reply.
410 	 * It's free'd in smb_request_free().
411 	 * Also updates the lease and NewLevel.
412 	 */
413 	sr->reply.max_bytes = MLEN;
414 	if (ofile->f_oplock.og_dialect >= SMB_VERS_2_BASE) {
415 		if (lease != NULL) {
416 			/*
417 			 * Oplock state has changed, so
418 			 * update the epoch.
419 			 */
420 			mutex_enter(&lease->ls_mutex);
421 			lease->ls_epoch++;
422 			mutex_exit(&lease->ls_mutex);
423 
424 			/* Note, needs "old" state in og_state */
425 			smb2_lease_break_notification(sr,
426 			    (NewLevel & CACHE_RWH), AckReq);
427 			NewLevel |= OPLOCK_LEVEL_GRANULAR;
428 		} else {
429 			smb2_oplock_break_notification(sr, NewLevel);
430 		}
431 	} else {
432 		/*
433 		 * SMB1 clients should only get Level II oplocks if they
434 		 * set the capability indicating they know about them.
435 		 */
436 		if (NewLevel == OPLOCK_LEVEL_TWO &&
437 		    ofile->f_oplock.og_dialect < NT_LM_0_12)
438 			NewLevel = OPLOCK_LEVEL_NONE;
439 		smb1_oplock_break_notification(sr, NewLevel);
440 	}
441 
442 	/*
443 	 * Keep track of what we last sent to the client,
444 	 * preserving the GRANULAR flag (if a lease).
445 	 * If we're expecting an ACK, set og_breaking
446 	 * (and maybe lease->ls_breaking) so we can
447 	 * later find the ofile with breaks pending.
448 	 */
449 	if (AckReq) {
450 		uint32_t BreakTo;
451 
452 		if (lease != NULL) {
453 			BreakTo = (NewLevel & CACHE_RWH) << BREAK_SHIFT;
454 			if (BreakTo == 0)
455 				BreakTo = BREAK_TO_NO_CACHING;
456 			lease->ls_breaking = BreakTo;
457 		} else {
458 			if ((NewLevel & LEVEL_TWO_OPLOCK) != 0)
459 				BreakTo = BREAK_TO_TWO;
460 			else
461 				BreakTo = BREAK_TO_NONE;
462 		}
463 		/* Will update og_state in ack. */
464 		ofile->f_oplock.og_breaking = BreakTo;
465 	} else {
466 		if (lease != NULL)
467 			lease->ls_state = NewLevel & CACHE_RWH;
468 		ofile->f_oplock.og_state = NewLevel;
469 
470 		if (ofile->dh_persist) {
471 			smb2_dh_update_oplock(sr, ofile);
472 		}
473 	}
474 
475 	/*
476 	 * Try to send the break message to the client.
477 	 * When we get to multi-channel, this is supposed to
478 	 * try to send on every channel before giving up.
479 	 */
480 	if (sr->session == ofile->f_session)
481 		rc = smb_session_send(sr->session, 0, &sr->reply);
482 	else
483 		rc = ENOTCONN;
484 
485 	if (rc == 0) {
486 		/*
487 		 * OK, we were able to send the break message.
488 		 * If no ack. required, we're done.
489 		 */
490 		if (!AckReq)
491 			return;
492 
493 		/*
494 		 * We're expecting an ACK.  Wait in this thread
495 		 * so we can log clients that don't respond.
496 		 *
497 		 * If debugging, may want to break after a
498 		 * short wait to look into why we might be
499 		 * holding up progress.  (i.e. locks?)
500 		 */
501 #ifdef DEBUG
502 		if (smb_oplock_debug_wait > 0) {
503 			status = smb_oplock_wait_break(ofile->f_node,
504 			    smb_oplock_debug_wait);
505 			if (status == 0)
506 				return;
507 			cmn_err(CE_NOTE, "clnt %s oplock break wait debug",
508 			    sr->session->ip_addr_str);
509 			debug_enter("oplock_wait");
510 		}
511 #endif
512 		status = smb_oplock_wait_break(ofile->f_node,
513 		    smb_oplock_timeout_ack);
514 		if (status == 0)
515 			return;
516 
517 		cmn_err(CE_NOTE, "clnt %s oplock break timeout",
518 		    sr->session->ip_addr_str);
519 		DTRACE_PROBE1(break_timeout, smb_ofile_t, ofile);
520 
521 		/*
522 		 * Will do local ack below.  Note, after timeout,
523 		 * do a break to none or "no caching" regardless
524 		 * of what the passed in cache level was.
525 		 * That means: clear all except GRANULAR.
526 		 */
527 		NewLevel &= OPLOCK_LEVEL_GRANULAR;
528 	} else {
529 		/*
530 		 * We were unable to send the oplock break request.
531 		 * Generally, that means we have no connection to this
532 		 * client right now, and this ofile will have state
533 		 * SMB_OFILE_STATE_ORPHANED.  We either close the handle
534 		 * or break the oplock locally, in which case the client
535 		 * gets the updated oplock state when they reconnect.
536 		 * Decide whether to keep or close.
537 		 *
538 		 * Relevant [MS-SMB2] sections:
539 		 *
540 		 * 3.3.4.6 Object Store Indicates an Oplock Break
541 		 * If Open.Connection is NULL, Open.IsResilient is FALSE,
542 		 * Open.IsDurable is FALSE and Open.IsPersistent is FALSE,
543 		 * the server SHOULD close the Open as specified in...
544 		 *
545 		 * 3.3.4.7 Object Store Indicates a Lease Break
546 		 * If Open.Connection is NULL, the server MUST close the
547 		 * Open as specified in ... for the following cases:
548 		 * - Open.IsResilient is FALSE, Open.IsDurable is FALSE,
549 		 *   and Open.IsPersistent is FALSE.
550 		 * - Lease.BreakToLeaseState does not contain
551 		 *   ...HANDLE_CACHING and Open.IsDurable is TRUE.
552 		 * If Lease.LeaseOpens is empty, (... local ack to "none").
553 		 */
554 
555 		/*
556 		 * See similar logic in smb_dh_should_save
557 		 */
558 		switch (ofile->dh_vers) {
559 		case SMB2_RESILIENT:
560 			break;			/* keep DH */
561 
562 		case SMB2_DURABLE_V2:
563 			if (ofile->dh_persist)
564 				break;		/* keep DH */
565 			/* FALLTHROUGH */
566 		case SMB2_DURABLE_V1:
567 			/* IS durable (v1 or v2) */
568 			if ((NewLevel & (OPLOCK_LEVEL_BATCH |
569 			    OPLOCK_LEVEL_CACHE_HANDLE)) != 0)
570 				break;		/* keep DH */
571 			/* FALLTHROUGH */
572 		case SMB2_NOT_DURABLE:
573 		default:
574 			smb_ofile_close(ofile, 0);
575 			return;
576 		}
577 		/* Keep this ofile (durable handle). */
578 
579 		if (!AckReq) {
580 			/* Nothing more to do. */
581 			return;
582 		}
583 	}
584 
585 	/*
586 	 * We get here after either an oplock break ack timeout,
587 	 * or a send failure for a durable handle type that we
588 	 * preserve rather than just close.  Do local ack.
589 	 */
590 	ofile->f_oplock.og_breaking = 0;
591 	if (lease != NULL)
592 		lease->ls_breaking = 0;
593 
594 	status = smb_oplock_ack_break(sr, ofile, &NewLevel);
595 	if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
596 		/* Not expecting this status return. */
597 		cmn_err(CE_NOTE, "clnt local oplock ack wait?");
598 		(void) smb_oplock_wait_break(ofile->f_node,
599 		    smb_oplock_timeout_ack);
600 		status = 0;
601 	}
602 	if (status != 0) {
603 		cmn_err(CE_NOTE, "clnt local oplock ack, "
604 		    "status=0x%x", status);
605 	}
606 
607 	/* Update og_state as if we heard from the client. */
608 	ofile->f_oplock.og_state = NewLevel;
609 	if (lease != NULL) {
610 		lease->ls_state = NewLevel & CACHE_RWH;
611 	}
612 
613 	if (ofile->dh_persist) {
614 		smb2_dh_update_oplock(sr, ofile);
615 	}
616 }
617 
618 /*
619  * See: NT_STATUS_OPLOCK_HANDLE_CLOSED above,
620  * and: STATUS_NEW_HANDLE
621  *
622  * The FS-level oplock layer calls this to update the
623  * SMB-level state when a handle loses its oplock.
624  */
625 static void
626 smb_oplock_hdl_clear(smb_ofile_t *ofile)
627 {
628 	smb_lease_t *lease = ofile->f_lease;
629 
630 	if (lease != NULL) {
631 		if (lease->ls_oplock_ofile == ofile) {
632 			/* Last close on the lease. */
633 			lease->ls_oplock_ofile = NULL;
634 		}
635 	}
636 	ofile->f_oplock.og_state = 0;
637 	ofile->f_oplock.og_breaking = 0;
638 }
639 
640 /*
641  * Wait up to "timeout" mSec. for the current oplock "breaking" flags
642  * to be cleared (by smb_oplock_ack_break or smb_oplock_break_CLOSE).
643  *
644  * Callers of the above public oplock functions:
645  *	smb_oplock_request()
646  *	smb_oplock_ack_break()
647  *	smb_oplock_break_OPEN() ...
648  * check for return status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS
649  * and call this function to wait for the break to complete.
650  *
651  * Most callers should use this default timeout, which they get
652  * by passing zero as the timeout arg.  This include places where
653  * we're about to do something that invalidates some cache.
654  */
655 uint32_t
656 smb_oplock_wait_break(smb_node_t *node, int timeout)  /* mSec. */
657 {
658 	smb_oplock_t	*ol;
659 	clock_t		time, rv;
660 	uint32_t	status = 0;
661 
662 	if (timeout == 0)
663 		timeout = smb_oplock_timeout_def;
664 
665 	SMB_NODE_VALID(node);
666 	ol = &node->n_oplock;
667 
668 	mutex_enter(&ol->ol_mutex);
669 	time = MSEC_TO_TICK(timeout) + ddi_get_lbolt();
670 
671 	while ((ol->ol_state & BREAK_ANY) != 0) {
672 		ol->waiters++;
673 		rv = cv_timedwait(&ol->WaitingOpenCV,
674 		    &ol->ol_mutex, time);
675 		ol->waiters--;
676 		if (rv < 0) {
677 			status = NT_STATUS_CANNOT_BREAK_OPLOCK;
678 			break;
679 		}
680 	}
681 
682 	mutex_exit(&ol->ol_mutex);
683 
684 	return (status);
685 }
686