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 2020 Nexenta by DDN, Inc.  All rights reserved.
14  */
15 
16 /*
17  * (SMB1/SMB2) common (FS-level) Oplock support.
18  *
19  * This is the file-system (FS) level oplock code.  This level
20  * knows about the rules by which various kinds of oplocks may
21  * coexist and how they interact.  Note that this code should
22  * have NO knowledge of specific SMB protocol details.  Those
23  * details are handled in smb_srv_oplock.c and related.
24  *
25  * This file is intentionally written to very closely follow the
26  * [MS-FSA] specification sections about oplocks.  Almost every
27  * section of code is preceeded by a block of text from that
28  * specification describing the logic.  Where the implementation
29  * differs from what the spec. describes, there are notes like:
30  * Implementation specific: ...
31  */
32 
33 #include <smbsrv/smb_kproto.h>
34 #include <smbsrv/smb_oplock.h>
35 
36 /*
37  * Several short-hand defines and enums used in this file.
38  */
39 
40 #define	NODE_FLAGS_DELETING	(NODE_FLAGS_DELETE_ON_CLOSE |\
41 				NODE_FLAGS_DELETE_COMMITTED)
42 
43 static uint32_t
44 smb_oplock_req_excl(
45     smb_ofile_t *ofile,		/* in: the "Open" */
46     uint32_t *rop);		/* in: "RequestedOplock", out:NewOplockLevel */
47 
48 static uint32_t
49 smb_oplock_req_shared(
50     smb_ofile_t *ofile,		/* the "Open" */
51     uint32_t *rop,		/* in: "RequestedOplock", out:NewOplockLevel */
52     boolean_t GrantingInAck);
53 
54 static uint32_t smb_oplock_break_cmn(smb_node_t *node,
55     smb_ofile_t *ofile, uint32_t BreakCacheLevel);
56 
57 
58 /*
59  * [MS-FSA] 2.1.4.12.2 Algorithm to Compare Oplock Keys
60  *
61  * The inputs for this algorithm are:
62  *
63  *	OperationOpen: The Open used in the request that can
64  *	  cause an oplock to break.
65  *	OplockOpen: The Open originally used to request the oplock,
66  *	  as specified in section 2.1.5.17.
67  *	Flags: If unspecified it is considered to contain 0.
68  *	  Valid nonzero values are:
69  *		PARENT_OBJECT
70  *
71  * This algorithm returns TRUE if the appropriate oplock key field of
72  * OperationOpen equals OplockOpen.TargetOplockKey, and FALSE otherwise.
73  *
74  * Note: Unlike many comparison functions, ARG ORDER MATTERS.
75  */
76 
77 static boolean_t
78 CompareOplockKeys(smb_ofile_t *OperOpen, smb_ofile_t *OplockOpen, int flags)
79 {
80 	static const uint8_t key0[SMB_LEASE_KEY_SZ] = { 0 };
81 
82 	/*
83 	 * When we're called via FEM, (smb_oplock_break_...)
84 	 * the OperOpen arg is NULL because I/O outside of SMB
85 	 * doesn't have an "ofile".  That's "not a match".
86 	 */
87 	if (OperOpen == NULL)
88 		return (B_FALSE);
89 	ASSERT(OplockOpen != NULL);
90 
91 	/*
92 	 * If OperationOpen equals OplockOpen:
93 	 * Return TRUE.
94 	 */
95 	if (OperOpen == OplockOpen)
96 		return (B_TRUE);
97 
98 	/*
99 	 * If both OperationOpen.TargetOplockKey and
100 	 * OperationOpen.ParentOplockKey are empty
101 	 * or both OplockOpen.TargetOplockKey and
102 	 * OplockOpen.ParentOplockKey are empty:
103 	 * Return FALSE.
104 	 */
105 	if (bcmp(OperOpen->TargetOplockKey, key0, sizeof (key0)) == 0 &&
106 	    bcmp(OperOpen->ParentOplockKey, key0, sizeof (key0)) == 0)
107 		return (B_FALSE);
108 	if (bcmp(OplockOpen->TargetOplockKey, key0, sizeof (key0)) == 0 &&
109 	    bcmp(OplockOpen->ParentOplockKey, key0, sizeof (key0)) == 0)
110 		return (B_FALSE);
111 
112 	/*
113 	 * If OplockOpen.TargetOplockKey is empty or...
114 	 */
115 	if (bcmp(OplockOpen->TargetOplockKey, key0, sizeof (key0)) == 0)
116 		return (B_FALSE);
117 
118 	/*
119 	 * If Flags contains PARENT_OBJECT:
120 	 */
121 	if ((flags & PARENT_OBJECT) != 0) {
122 		/*
123 		 * If OperationOpen.ParentOplockKey is empty:
124 		 * Return FALSE.
125 		 */
126 		if (bcmp(OperOpen->ParentOplockKey, key0, sizeof (key0)) == 0)
127 			return (B_FALSE);
128 
129 		/*
130 		 * If OperationOpen.ParentOplockKey equals
131 		 * OplockOpen.TargetOplockKey:
132 		 * return TRUE, else FALSE
133 		 */
134 		if (bcmp(OperOpen->ParentOplockKey,
135 		    OplockOpen->TargetOplockKey,
136 		    SMB_LEASE_KEY_SZ) == 0) {
137 			return (B_TRUE);
138 		}
139 	} else {
140 		/*
141 		 * ... from above:
142 		 * (Flags does not contain PARENT_OBJECT and
143 		 * OperationOpen.TargetOplockKey is empty):
144 		 * Return FALSE.
145 		 */
146 		if (bcmp(OperOpen->TargetOplockKey, key0, sizeof (key0)) == 0)
147 			return (B_FALSE);
148 
149 		/*
150 		 * If OperationOpen.TargetOplockKey equals
151 		 * OplockOpen.TargetOplockKey:
152 		 *  Return TRUE, else FALSE
153 		 */
154 		if (bcmp(OperOpen->TargetOplockKey,
155 		    OplockOpen->TargetOplockKey,
156 		    SMB_LEASE_KEY_SZ) == 0) {
157 			return (B_TRUE);
158 		}
159 	}
160 
161 	return (B_FALSE);
162 }
163 
164 /*
165  * 2.1.4.13 Algorithm to Recompute the State of a Shared Oplock
166  *
167  * The inputs for this algorithm are:
168  *	ThisOplock: The Oplock on whose state is being recomputed.
169  */
170 static void
171 RecomputeOplockState(smb_node_t *node)
172 {
173 	smb_oplock_t *ol = &node->n_oplock;
174 
175 	ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
176 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
177 
178 	/*
179 	 * If ThisOplock.IIOplocks, ThisOplock.ROplocks, ThisOplock.RHOplocks,
180 	 * and ThisOplock.RHBreakQueue are all empty:
181 	 *	Set ThisOplock.State to NO_OPLOCK.
182 	 */
183 	if (ol->cnt_II == 0 && ol->cnt_R == 0 &&
184 	    ol->cnt_RH == 0 && ol->cnt_RHBQ == 0) {
185 		ol->ol_state = NO_OPLOCK;
186 		return;
187 	}
188 
189 	/*
190 	 * Else If ThisOplock.ROplocks is not empty and either
191 	 *    ThisOplock.RHOplocks or ThisOplock.RHBreakQueue are not empty:
192 	 *	Set ThisOplock.State to
193 	 *	  (READ_CACHING|HANDLE_CACHING|MIXED_R_AND_RH).
194 	 */
195 	else if (ol->cnt_R != 0 && (ol->cnt_RH != 0 || ol->cnt_RHBQ != 0)) {
196 		ol->ol_state = (READ_CACHING|HANDLE_CACHING|MIXED_R_AND_RH);
197 	}
198 
199 	/*
200 	 * Else If ThisOplock.ROplocks is empty and
201 	 * ThisOplock.RHOplocks is not empty:
202 	 *	Set ThisOplock.State to (READ_CACHING|HANDLE_CACHING).
203 	 */
204 	else if (ol->cnt_R == 0 && ol->cnt_RH != 0) {
205 		ol->ol_state = (READ_CACHING|HANDLE_CACHING);
206 	}
207 
208 	/*
209 	 * Else If ThisOplock.ROplocks is not empty and
210 	 * ThisOplock.IIOplocks is not empty:
211 	 *	Set ThisOplock.State to (READ_CACHING|LEVEL_TWO_OPLOCK).
212 	 */
213 	else if (ol->cnt_R != 0 && ol->cnt_II != 0) {
214 		ol->ol_state = (READ_CACHING|LEVEL_TWO_OPLOCK);
215 	}
216 
217 	/*
218 	 * Else If ThisOplock.ROplocks is not empty and
219 	 * ThisOplock.IIOplocks is empty:
220 	 *	Set ThisOplock.State to READ_CACHING.
221 	 */
222 	else if (ol->cnt_R != 0 && ol->cnt_II == 0) {
223 		ol->ol_state = READ_CACHING;
224 	}
225 
226 	/*
227 	 * Else If ThisOplock.ROplocks is empty and
228 	 * ThisOplock.IIOplocks is not empty:
229 	 *	Set ThisOplock.State to LEVEL_TWO_OPLOCK.
230 	 */
231 	else if (ol->cnt_R == 0 && ol->cnt_II != 0) {
232 		ol->ol_state = LEVEL_TWO_OPLOCK;
233 	}
234 
235 	else {
236 		smb_ofile_t *o;
237 		int cntBrkToRead;
238 
239 		/*
240 		 * ThisOplock.RHBreakQueue MUST be non-empty by this point.
241 		 */
242 		ASSERT(ol->cnt_RHBQ != 0);
243 
244 		/*
245 		 * How many on RHBQ have BreakingToRead set?
246 		 */
247 		cntBrkToRead = 0;
248 		FOREACH_NODE_OFILE(node, o) {
249 			if (o->f_oplock.onlist_RHBQ == 0)
250 				continue;
251 			if (o->f_oplock.BreakingToRead)
252 				cntBrkToRead++;
253 		}
254 
255 		/*
256 		 * If RHOpContext.BreakingToRead is TRUE for
257 		 *  every RHOpContext on ThisOplock.RHBreakQueue:
258 		 */
259 		if (cntBrkToRead == ol->cnt_RHBQ) {
260 			/*
261 			 * Set ThisOplock.State to
262 			 * (READ_CACHING|HANDLE_CACHING|BREAK_TO_READ_CACHING).
263 			 */
264 			ol->ol_state = (READ_CACHING|HANDLE_CACHING|
265 			    BREAK_TO_READ_CACHING);
266 		}
267 
268 		/*
269 		 * Else If RHOpContext.BreakingToRead is FALSE for
270 		 *  every RHOpContext on ThisOplock.RHBreakQueue:
271 		 */
272 		else if (cntBrkToRead == 0) {
273 			/*
274 			 * Set ThisOplock.State to
275 			 *  (READ_CACHING|HANDLE_CACHING|BREAK_TO_NO_CACHING).
276 			 */
277 			ol->ol_state = (READ_CACHING|HANDLE_CACHING|
278 			    BREAK_TO_NO_CACHING);
279 		} else {
280 			/*
281 			 * Set ThisOplock.State to
282 			 *  (READ_CACHING|HANDLE_CACHING).
283 			 */
284 			ol->ol_state = (READ_CACHING|HANDLE_CACHING);
285 		}
286 	}
287 }
288 
289 /*
290  * [MS-FSA] 2.1.5.17 Server Requests an Oplock
291  *
292  * The server (caller) provides:
293  *	Open - The Open on which the oplock is being requested. (ofile)
294  *	Type - The type of oplock being requested. Valid values are as follows:
295  *		LEVEL_TWO (Corresponds to SMB2_OPLOCK_LEVEL_II)
296  *		LEVEL_ONE (Corresponds to SMB2_OPLOCK_LEVEL_EXCLUSIVE)
297  *		LEVEL_BATCH (Corresponds to SMB2_OPLOCK_LEVEL_BATCH)
298  *		LEVEL_GRANULAR (Corresponds to SMB2_OPLOCK_LEVEL_LEASE)
299  *	RequestedOplockLevel - A combination of zero or more of the
300  *	  following flags (ignored if Type != LEVEL_GRANULAR)
301  *		READ_CACHING
302  *		HANDLE_CACHING
303  *		WRITE_CACHING
304  *
305  *	(Type + RequestedOplockLevel come in *statep)
306  *
307  * Returns:
308  *	*statep = NewOplockLevel (possibly less than requested)
309  *		  containing: LEVEL_NONE, LEVEL_TWO + cache_flags
310  *	NTSTATUS
311  */
312 
313 uint32_t
314 smb_oplock_request(smb_request_t *sr, smb_ofile_t *ofile, uint32_t *statep)
315 {
316 	smb_node_t *node = ofile->f_node;
317 	uint32_t type = *statep & OPLOCK_LEVEL_TYPE_MASK;
318 	uint32_t level = *statep & OPLOCK_LEVEL_CACHE_MASK;
319 	uint32_t status;
320 
321 	*statep = LEVEL_NONE;
322 
323 	/*
324 	 * If Open.Stream.StreamType is DirectoryStream:
325 	 *	The operation MUST be failed with STATUS_INVALID_PARAMETER
326 	 *	under either of the following conditions:
327 	 *	* Type is not LEVEL_GRANULAR.
328 	 *	* Type is LEVEL_GRANULAR but RequestedOplockLevel is
329 	 *	  neither READ_CACHING nor (READ_CACHING|HANDLE_CACHING).
330 	 */
331 	if (!smb_node_is_file(node)) {
332 		/* ofile is a directory. */
333 		if (type != LEVEL_GRANULAR)
334 			return (NT_STATUS_INVALID_PARAMETER);
335 		if (level != READ_CACHING &&
336 		    level != (READ_CACHING|HANDLE_CACHING))
337 			return (NT_STATUS_INVALID_PARAMETER);
338 		/*
339 		 * We're not supporting directory leases yet.
340 		 * Todo.
341 		 */
342 		return (NT_STATUS_OPLOCK_NOT_GRANTED);
343 	}
344 
345 	smb_llist_enter(&node->n_ofile_list, RW_READER);
346 	mutex_enter(&node->n_oplock.ol_mutex);
347 
348 	/*
349 	 * If Type is LEVEL_ONE or LEVEL_BATCH:
350 	 * The operation MUST be failed with STATUS_OPLOCK_NOT_GRANTED
351 	 * under either of the following conditions:
352 	 *	Open.File.OpenList contains more than one Open
353 	 *	  whose Stream is the same as Open.Stream.
354 	 *	Open.Mode contains either FILE_SYNCHRONOUS_IO_ALERT or
355 	 *	  FILE_SYNCHRONOUS_IO_NONALERT.
356 	 * Request an exclusive oplock according to the algorithm in
357 	 * section 2.1.5.17.1, setting the algorithm's params as follows:
358 	 *	Pass in the current Open.
359 	 *	RequestedOplock = Type.
360 	 * The operation MUST at this point return any status code
361 	 * returned by the exclusive oplock request algorithm.
362 	 */
363 	if (type == LEVEL_ONE || type == LEVEL_BATCH) {
364 		if (node->n_open_count > 1) {
365 			status = NT_STATUS_OPLOCK_NOT_GRANTED;
366 			goto out;
367 		}
368 		/* XXX: Should be a flag on the ofile. */
369 		if (node->flags & NODE_FLAGS_WRITE_THROUGH) {
370 			status = NT_STATUS_OPLOCK_NOT_GRANTED;
371 			goto out;
372 		}
373 		*statep = type;
374 		status = smb_oplock_req_excl(ofile, statep);
375 		goto out;
376 	}
377 
378 	/*
379 	 * Else If Type is LEVEL_TWO:
380 	 * The operation MUST be failed with STATUS_OPLOCK_NOT_GRANTED under
381 	 *  either of the following conditions:
382 	 *	Open.Stream.ByteRangeLockList is not empty.
383 	 *	Open.Mode contains either FILE_SYNCHRONOUS_IO_ALERT or
384 	 *	  FILE_SYNCHRONOUS_IO_NONALERT.
385 	 * Request a shared oplock according to the algorithm in
386 	 * section 2.1.5.17.2, setting the algorithm's parameters as follows:
387 	 *	Pass in the current Open.
388 	 *	RequestedOplock = Type.
389 	 *	GrantingInAck = FALSE.
390 	 * The operation MUST at this point return any status code
391 	 * returned by the shared oplock request algorithm.
392 	 */
393 	if (type == LEVEL_TWO) {
394 		if (smb_lock_range_access(sr, node, 0, ~0, B_FALSE) != 0) {
395 			status = NT_STATUS_OPLOCK_NOT_GRANTED;
396 			goto out;
397 		}
398 		/* XXX: Should be a flag on the ofile. */
399 		if (node->flags & NODE_FLAGS_WRITE_THROUGH) {
400 			status = NT_STATUS_OPLOCK_NOT_GRANTED;
401 			goto out;
402 		}
403 		*statep = type;
404 		status = smb_oplock_req_shared(ofile, statep, B_FALSE);
405 		goto out;
406 	}
407 
408 	/*
409 	 * Else If Type is LEVEL_GRANULAR:
410 	 *   Sub-cases on RequestedOplockLevel (our "level")
411 	 *
412 	 * This is the last Type, so error on !granular and then
413 	 * deal with the cache levels using one less indent.
414 	 */
415 	if (type != LEVEL_GRANULAR) {
416 		status = NT_STATUS_INVALID_PARAMETER;
417 		goto out;
418 	}
419 
420 	switch (level) {
421 
422 	/*
423 	 * If RequestedOplockLevel is READ_CACHING or
424 	 *   (READ_CACHING|HANDLE_CACHING):
425 	 *	The operation MUST be failed with STATUS_OPLOCK_NOT_GRANTED
426 	 *	under either of the following conditions:
427 	 *		Open.Stream.ByteRangeLockList is not empty.
428 	 *		Open.Mode contains either FILE_SYNCHRONOUS_IO_ALERT or
429 	 *		  FILE_SYNCHRONOUS_IO_NONALERT.
430 	 *	Request a shared oplock according to the algorithm in
431 	 *	section 2.1.5.17.2, setting the parameters as follows:
432 	 *		Pass in the current Open.
433 	 *		RequestedOplock = RequestedOplockLevel.
434 	 *		GrantingInAck = FALSE.
435 	 *
436 	 *	The operation MUST at this point return any status code
437 	 *	  returned by the shared oplock request algorithm.
438 	 */
439 	case READ_CACHING:
440 	case (READ_CACHING|HANDLE_CACHING):
441 		if (smb_lock_range_access(sr, node, 0, ~0, B_FALSE) != 0) {
442 			status = NT_STATUS_OPLOCK_NOT_GRANTED;
443 			goto out;
444 		}
445 		/* XXX: Should be a flag on the ofile. */
446 		if (node->flags & NODE_FLAGS_WRITE_THROUGH) {
447 			status = NT_STATUS_OPLOCK_NOT_GRANTED;
448 			goto out;
449 		}
450 		*statep = level;
451 		status = smb_oplock_req_shared(ofile, statep, B_FALSE);
452 		break;
453 
454 	/*
455 	 * Else If RequestedOplockLevel is
456 	 * (READ_CACHING|WRITE_CACHING) or
457 	 * (READ_CACHING|WRITE_CACHING|HANDLE_CACHING):
458 	 * If Open.Mode contains either FILE_SYNCHRONOUS_IO_ALERT or
459 	 * FILE_SYNCHRONOUS_IO_NONALERT, the operation MUST be failed
460 	 * with STATUS_OPLOCK_NOT_GRANTED.
461 	 * Request an exclusive oplock according to the algorithm in
462 	 * section 2.1.5.17.1, setting the parameters as follows:
463 	 *	Pass in the current Open.
464 	 *	RequestedOplock = RequestedOplockLevel.
465 	 * The operation MUST at this point return any status code
466 	 * returned by the exclusive oplock request algorithm.
467 	 */
468 	case (READ_CACHING | WRITE_CACHING):
469 	case (READ_CACHING | WRITE_CACHING | HANDLE_CACHING):
470 		/* XXX: Should be a flag on the ofile. */
471 		if (node->flags & NODE_FLAGS_WRITE_THROUGH) {
472 			status = NT_STATUS_OPLOCK_NOT_GRANTED;
473 			goto out;
474 		}
475 		*statep = level;
476 		status = smb_oplock_req_excl(ofile, statep);
477 		break;
478 
479 	/*
480 	 * Else if RequestedOplockLevel is 0 (that is, no flags):
481 	 * The operation MUST return STATUS_SUCCESS at this point.
482 	 */
483 	case 0:
484 		*statep = 0;
485 		status = NT_STATUS_SUCCESS;
486 		break;
487 
488 	/*
489 	 * Else
490 	 *  The operation MUST be failed with STATUS_INVALID_PARAMETER.
491 	 */
492 	default:
493 		status = NT_STATUS_INVALID_PARAMETER;
494 		break;
495 	}
496 
497 	/* Give caller back the "Granular" bit. */
498 	if (status == NT_STATUS_SUCCESS) {
499 		*statep |= LEVEL_GRANULAR;
500 
501 		/*
502 		 * The oplock lease may have moved to this ofile. Update.
503 		 * Minor violation of layering here (leases vs oplocks)
504 		 * but we want this update coverd by the oplock mutex.
505 		 */
506 #ifndef	TESTJIG
507 		if (ofile->f_lease != NULL)
508 			ofile->f_lease->ls_oplock_ofile = ofile;
509 #endif
510 	}
511 
512 out:
513 	mutex_exit(&node->n_oplock.ol_mutex);
514 	smb_llist_exit(&node->n_ofile_list);
515 
516 	return (status);
517 }
518 
519 /*
520  * 2.1.5.17.1 Algorithm to Request an Exclusive Oplock
521  *
522  * The inputs for requesting an exclusive oplock are:
523  *	Open: The Open on which the oplock is being requested.
524  *	RequestedOplock: The oplock type being requested. One of:
525  *	  LEVEL_ONE, LEVEL_BATCH, CACHE_RW, CACHE_RWH
526  *
527  * On completion, the object store MUST return:
528  *	Status: An NTSTATUS code that specifies the result.
529  *	NewOplockLevel: The type of oplock that the requested oplock has been
530  *	  broken (reduced) to.  If a failure status is returned in Status,
531  *	  the value of this field is undefined.  Valid values are as follows:
532  *		LEVEL_NONE (that is, no oplock)
533  *		LEVEL_TWO
534  *		A combination of one or more of the following flags:
535  *			READ_CACHING
536  *			HANDLE_CACHING
537  *			WRITE_CACHING
538  *	AcknowledgeRequired: A Boolean value: TRUE if the server MUST
539  *	acknowledge the oplock break; FALSE if not, as specified in
540  *	section 2.1.5.18. If a failure status is returned in Status,
541  *	the value of this field is undefined.
542  *
543  * Note: Stores NewOplockLevel in *rop
544  */
545 static uint32_t
546 smb_oplock_req_excl(
547     smb_ofile_t *ofile,		/* in: the "Open" */
548     uint32_t *rop)		/* in: "RequestedOplock", out:NewOplockLevel */
549 {
550 	smb_node_t *node = ofile->f_node;
551 	smb_ofile_t *o;
552 	boolean_t GrantExcl = B_FALSE;
553 	uint32_t status = NT_STATUS_OPLOCK_NOT_GRANTED;
554 
555 	ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
556 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
557 
558 	/*
559 	 * Don't allow grants on closing ofiles.
560 	 */
561 	if (ofile->f_oplock.og_closing)
562 		return (status);
563 
564 	/*
565 	 * If Open.Stream.Oplock is empty:
566 	 *   Build a new Oplock object with fields initialized as follows:
567 	 *	Oplock.State set to NO_OPLOCK.
568 	 *	All other fields set to 0/empty.
569 	 *   Store the new Oplock object in Open.Stream.Oplock.
570 	 * EndIf
571 	 *
572 	 * Implementation specific:
573 	 * Open.Stream.Oplock maps to: node->n_oplock
574 	 */
575 	if (node->n_oplock.ol_state == 0) {
576 		node->n_oplock.ol_state = NO_OPLOCK;
577 	}
578 
579 	/*
580 	 * If Open.Stream.Oplock.State contains
581 	 * LEVEL_TWO_OPLOCK or NO_OPLOCK: ...
582 	 *
583 	 * Per ms, this is the "If" matching the unbalalanced
584 	 * "Else If" below (for which we requested clarification).
585 	 */
586 	if ((node->n_oplock.ol_state & (LEVEL_TWO | NO_OPLOCK)) != 0) {
587 
588 		/*
589 		 * If Open.Stream.Oplock.State contains LEVEL_TWO_OPLOCK and
590 		 * RequestedOplock contains one or more of READ_CACHING,
591 		 * HANDLE_CACHING, or WRITE_CACHING, the operation MUST be
592 		 * failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
593 		 */
594 		if ((node->n_oplock.ol_state & LEVEL_TWO) != 0 &&
595 		    (*rop & CACHE_RWH) != 0) {
596 			status = NT_STATUS_OPLOCK_NOT_GRANTED;
597 			goto out;
598 		}
599 
600 		/*
601 		 * [ from dochelp@ms ]
602 		 *
603 		 * By this point if there is a level II oplock present,
604 		 * the caller can only be requesting an old-style oplock
605 		 * because we rejected enhanced oplock requests above.
606 		 * If the caller is requesting an old-style oplock our
607 		 * caller already verfied that there is only one handle
608 		 * open to this stream, and we've already verified that
609 		 * this request is for a legacy oplock, meaning that there
610 		 * can be at most one level II oplock (and no R oplocks),
611 		 * and the level II oplock belongs to this handle.  Clear
612 		 * the level II oplock and grant the exclusive oplock.
613 		 */
614 
615 		/*
616 		 * If Open.Stream.Oplock.State is equal to LEVEL_TWO_OPLOCK:
617 		 * Remove the first Open ThisOpen from
618 		 *  Open.Stream.Oplock.IIOplocks (there is supposed to be
619 		 * exactly one present), and notify the server of an
620 		 * oplock break according to the algorithm in section
621 		 *  2.1.5.17.3, setting the algorithm's parameters as follows:
622 		 *	BreakingOplockOpen = ThisOpen.
623 		 *	NewOplockLevel = LEVEL_NONE.
624 		 *	AcknowledgeRequired = FALSE.
625 		 *	OplockCompletionStatus = STATUS_SUCCESS.
626 		 * (The operation does not end at this point; this call
627 		 *  to 2.1.5.17.3 completes some earlier call to 2.1.5.17.2.)
628 		 *
629 		 * Implementation specific:
630 		 *
631 		 * As explained above, the passed in ofile should be the
632 		 * only open file on this node.  Out of caution, we'll
633 		 * walk the ofile list as usual here, making sure there
634 		 * are no LevelII oplocks remaining, as those may not
635 		 * coexist with the exclusive oplock were're creating
636 		 * in this call.  Also, if the passed in ofile has a
637 		 * LevelII oplock, don't do an "ind break" up call on
638 		 * this ofile, as that would just cause an immediate
639 		 * "break to none" of the oplock we'll grant here.
640 		 * If there were other ofiles with LevelII oplocks,
641 		 * it would be appropriate to "ind break" those.
642 		 */
643 		if ((node->n_oplock.ol_state & LEVEL_TWO) != 0) {
644 			FOREACH_NODE_OFILE(node, o) {
645 				if (o->f_oplock.onlist_II == 0)
646 					continue;
647 				o->f_oplock.onlist_II = B_FALSE;
648 				node->n_oplock.cnt_II--;
649 				ASSERT(node->n_oplock.cnt_II >= 0);
650 				if (o == ofile)
651 					continue;
652 				DTRACE_PROBE1(unexpected, smb_ofile_t, o);
653 				smb_oplock_ind_break(o,
654 				    LEVEL_NONE, B_FALSE,
655 				    NT_STATUS_SUCCESS);
656 			}
657 		}
658 
659 		/*
660 		 * Note the spec. had an extra "EndIf" here.
661 		 * Confirmed by dochelp@ms
662 		 */
663 
664 		/*
665 		 * If Open.File.OpenList contains more than one Open whose
666 		 * Stream is the same as Open.Stream, and NO_OPLOCK is present
667 		 * in Open.Stream.Oplock.State, the operation MUST be failed
668 		 * with Status set to STATUS_OPLOCK_NOT_GRANTED.
669 		 *
670 		 * Implementation specific:
671 		 * Allow other opens if they have the same lease ours,
672 		 * so we can upgrade RH to RWH (for example). Therefore
673 		 * only count opens with a different TargetOplockKey.
674 		 * Also ignore "attribute-only" opens.
675 		 */
676 		if ((node->n_oplock.ol_state & NO_OPLOCK) != 0) {
677 			FOREACH_NODE_OFILE(node, o) {
678 				if (!smb_ofile_is_open(o))
679 					continue;
680 				if ((o->f_granted_access & FILE_DATA_ALL) == 0)
681 					continue;
682 				if (!CompareOplockKeys(ofile, o, 0)) {
683 					status = NT_STATUS_OPLOCK_NOT_GRANTED;
684 					goto out;
685 				}
686 			}
687 		}
688 
689 		/*
690 		 * If Open.Stream.IsDeleted is TRUE and RequestedOplock
691 		 * contains HANDLE_CACHING, the operation MUST be failed
692 		 * with Status set to STATUS_OPLOCK_NOT_GRANTED.
693 		 */
694 		if (((node->flags & NODE_FLAGS_DELETING) != 0) &&
695 		    (*rop & HANDLE_CACHING) != 0) {
696 			status = NT_STATUS_OPLOCK_NOT_GRANTED;
697 			goto out;
698 		}
699 
700 		/* Set GrantExclusiveOplock to TRUE. */
701 		GrantExcl = B_TRUE;
702 	}
703 
704 	/*
705 	 * "Else" If (Open.Stream.Oplock.State contains one or more of
706 	 * READ_CACHING, WRITE_CACHING, or HANDLE_CACHING) and
707 	 * (Open.Stream.Oplock.State contains none of (BREAK_ANY)) and
708 	 * (Open.Stream.Oplock.RHBreakQueue is empty):
709 	 */
710 	else if ((node->n_oplock.ol_state & CACHE_RWH) != 0 &&
711 	    (node->n_oplock.ol_state & BREAK_ANY) == 0 &&
712 	    node->n_oplock.cnt_RHBQ == 0) {
713 
714 		/*
715 		 * This is a granular oplock and it is not breaking.
716 		 */
717 
718 		/*
719 		 * If RequestedOplock contains none of READ_CACHING,
720 		 * WRITE_CACHING, or HANDLE_CACHING, the operation
721 		 * MUST be failed with Status set to
722 		 * STATUS_OPLOCK_NOT_GRANTED.
723 		 */
724 		if ((*rop & CACHE_RWH) == 0) {
725 			status = NT_STATUS_OPLOCK_NOT_GRANTED;
726 			goto out;
727 		}
728 
729 		/*
730 		 * If Open.Stream.IsDeleted (already checked above)
731 		 */
732 
733 		/*
734 		 * Switch (Open.Stream.Oplock.State):
735 		 */
736 		switch (node->n_oplock.ol_state) {
737 
738 		case CACHE_R:
739 			/*
740 			 * If RequestedOplock is neither
741 			 * (READ_CACHING|WRITE_CACHING) nor
742 			 * (READ_CACHING|WRITE_CACHING|HANDLE_CACHING),
743 			 * the operation MUST be failed with Status set
744 			 * to STATUS_OPLOCK_NOT_GRANTED.
745 			 */
746 			if (*rop != CACHE_RW && *rop != CACHE_RWH) {
747 				status = NT_STATUS_OPLOCK_NOT_GRANTED;
748 				goto out;
749 			}
750 
751 			/*
752 			 * For each Open ThisOpen in
753 			 *  Open.Stream.Oplock.ROplocks:
754 			 *	If ThisOpen.TargetOplockKey !=
755 			 *	Open.TargetOplockKey, the operation
756 			 *	MUST be failed with Status set to
757 			 *	STATUS_OPLOCK_NOT_GRANTED.
758 			 * EndFor
759 			 */
760 			FOREACH_NODE_OFILE(node, o) {
761 				if (o->f_oplock.onlist_R == 0)
762 					continue;
763 				if (!CompareOplockKeys(ofile, o, 0)) {
764 					status = NT_STATUS_OPLOCK_NOT_GRANTED;
765 					goto out;
766 				}
767 			}
768 
769 			/*
770 			 * For each Open o in Open.Stream.Oplock.ROplocks:
771 			 *	Remove o from Open.Stream.Oplock.ROplocks.
772 			 *	Notify the server of an oplock break
773 			 *	according to the algorithm in section
774 			 *	2.1.5.17.3, setting the algorithm's
775 			 *	parameters as follows:
776 			 *		BreakingOplockOpen = o.
777 			 *		NewOplockLevel = RequestedOplock.
778 			 *		AcknowledgeRequired = FALSE.
779 			 *		OplockCompletionStatus =
780 			 *		  STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE.
781 			 *	(The operation does not end at this point;
782 			 *	 this call to 2.1.5.17.3 completes some
783 			 *	 earlier call to 2.1.5.17.2.)
784 			 * EndFor
785 			 *
786 			 * Note: Upgrade to excl. on same lease.
787 			 * Won't send a break for this.
788 			 */
789 			FOREACH_NODE_OFILE(node, o) {
790 				if (o->f_oplock.onlist_R == 0)
791 					continue;
792 				o->f_oplock.onlist_R = B_FALSE;
793 				node->n_oplock.cnt_R--;
794 				ASSERT(node->n_oplock.cnt_R >= 0);
795 
796 				smb_oplock_ind_break(o, *rop,
797 				    B_FALSE, STATUS_NEW_HANDLE);
798 			}
799 			/*
800 			 * Set GrantExclusiveOplock to TRUE.
801 			 * EndCase // _R
802 			 */
803 			GrantExcl = B_TRUE;
804 			break;
805 
806 		case CACHE_RH:
807 			/*
808 			 * If RequestedOplock is not
809 			 * (READ_CACHING|WRITE_CACHING|HANDLE_CACHING)
810 			 * or Open.Stream.Oplock.RHBreakQueue is not empty,
811 			 * the operation MUST be failed with Status set to
812 			 * STATUS_OPLOCK_NOT_GRANTED.
813 			 * Note: Have RHBreakQueue==0 from above.
814 			 */
815 			if (*rop != CACHE_RWH) {
816 				status = NT_STATUS_OPLOCK_NOT_GRANTED;
817 				goto out;
818 			}
819 
820 			/*
821 			 * For each Open ThisOpen in
822 			 *  Open.Stream.Oplock.RHOplocks:
823 			 *	If ThisOpen.TargetOplockKey !=
824 			 *	Open.TargetOplockKey, the operation
825 			 *	MUST be failed with Status set to
826 			 *	STATUS_OPLOCK_NOT_GRANTED.
827 			 * EndFor
828 			 */
829 			FOREACH_NODE_OFILE(node, o) {
830 				if (o->f_oplock.onlist_RH == 0)
831 					continue;
832 				if (!CompareOplockKeys(ofile, o, 0)) {
833 					status = NT_STATUS_OPLOCK_NOT_GRANTED;
834 					goto out;
835 				}
836 			}
837 
838 			/*
839 			 * For each Open o in Open.Stream.Oplock.RHOplocks:
840 			 *	Remove o from Open.Stream.Oplock.RHOplocks.
841 			 *	Notify the server of an oplock break
842 			 *	according to the algorithm in section
843 			 *	2.1.5.17.3, setting the algorithm's
844 			 *	parameters as follows:
845 			 *		BreakingOplockOpen = o.
846 			 *		NewOplockLevel = RequestedOplock.
847 			 *		AcknowledgeRequired = FALSE.
848 			 *		OplockCompletionStatus =
849 			 *		  STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE.
850 			 *	(The operation does not end at this point;
851 			 *	 this call to 2.1.5.17.3 completes some
852 			 *	 earlier call to 2.1.5.17.2.)
853 			 * EndFor
854 			 *
855 			 * Note: Upgrade to excl. on same lease.
856 			 * Won't send a break for this.
857 			 */
858 			FOREACH_NODE_OFILE(node, o) {
859 				if (o->f_oplock.onlist_RH == 0)
860 					continue;
861 				o->f_oplock.onlist_RH = B_FALSE;
862 				node->n_oplock.cnt_RH--;
863 				ASSERT(node->n_oplock.cnt_RH >= 0);
864 
865 				smb_oplock_ind_break(o, *rop,
866 				    B_FALSE, STATUS_NEW_HANDLE);
867 			}
868 			/*
869 			 * Set GrantExclusiveOplock to TRUE.
870 			 * EndCase // _RH
871 			 */
872 			GrantExcl = B_TRUE;
873 			break;
874 
875 		case (CACHE_RWH | EXCLUSIVE):
876 			/*
877 			 * If RequestedOplock is not
878 			 * (READ_CACHING|WRITE_CACHING|HANDLE_CACHING),
879 			 * the operation MUST be failed with Status set to
880 			 * STATUS_OPLOCK_NOT_GRANTED.
881 			 */
882 			if (*rop != CACHE_RWH) {
883 				status = NT_STATUS_OPLOCK_NOT_GRANTED;
884 				goto out;
885 			}
886 			/* Deliberate FALL-THROUGH to next Case statement. */
887 			/* FALLTHROUGH */
888 
889 		case (CACHE_RW | EXCLUSIVE):
890 			/*
891 			 * If RequestedOplock is neither
892 			 * (READ_CACHING|WRITE_CACHING|HANDLE_CACHING) nor
893 			 * (READ_CACHING|WRITE_CACHING), the operation MUST be
894 			 * failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
895 			 */
896 			if (*rop != CACHE_RWH && *rop != CACHE_RW) {
897 				status = NT_STATUS_OPLOCK_NOT_GRANTED;
898 				goto out;
899 			}
900 
901 			o = node->n_oplock.excl_open;
902 			if (o == NULL) {
903 				ASSERT(0);
904 				GrantExcl = B_TRUE;
905 				break;
906 			}
907 
908 			/*
909 			 * If Open.TargetOplockKey !=
910 			 * Open.Stream.Oplock.ExclusiveOpen.TargetOplockKey,
911 			 * the operation MUST be failed with Status set to
912 			 * STATUS_OPLOCK_NOT_GRANTED.
913 			 */
914 			if (!CompareOplockKeys(ofile, o, 0)) {
915 				status = NT_STATUS_OPLOCK_NOT_GRANTED;
916 				goto out;
917 			}
918 
919 			/*
920 			 * Notify the server of an oplock break according to
921 			 * the algorithm in section 2.1.5.17.3, setting the
922 			 * algorithm's parameters as follows:
923 			 *	BreakingOplockOpen =
924 			 *	  Open.Stream.Oplock.ExclusiveOpen.
925 			 *	NewOplockLevel = RequestedOplock.
926 			 *	AcknowledgeRequired = FALSE.
927 			 *	OplockCompletionStatus =
928 			 *	  STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE.
929 			 * (The operation does not end at this point;
930 			 *  this call to 2.1.5.17.3 completes some
931 			 *  earlier call to 2.1.5.17.1.)
932 			 *
933 			 * Set Open.Stream.Oplock.ExclusiveOpen to NULL.
934 			 * Set GrantExclusiveOplock to TRUE.
935 			 *
936 			 * Note: We will keep this exclusive oplock,
937 			 * but move it to a new handle on this lease.
938 			 * Won't send a break for this.
939 			 */
940 			smb_oplock_ind_break(o, *rop,
941 			    B_FALSE, STATUS_NEW_HANDLE);
942 			node->n_oplock.excl_open = o = NULL;
943 			GrantExcl = B_TRUE;
944 			break;
945 
946 		default:
947 			/*
948 			 * The operation MUST be failed with Status set to
949 			 * STATUS_OPLOCK_NOT_GRANTED.
950 			 */
951 			status = NT_STATUS_OPLOCK_NOT_GRANTED;
952 			goto out;
953 
954 		} /* switch n_oplock.ol_state */
955 	} /* EndIf CACHE_RWH & !BREAK_ANY... */
956 	else {
957 		/*
958 		 * The operation MUST be failed with...
959 		 */
960 		status = NT_STATUS_OPLOCK_NOT_GRANTED;
961 		goto out;
962 	}
963 
964 	/*
965 	 * If GrantExclusiveOplock is TRUE:
966 	 *
967 	 * Set Open.Stream.Oplock.ExclusiveOpen = Open.
968 	 * Set Open.Stream.Oplock.State =
969 	 *   (RequestedOplock|EXCLUSIVE).
970 	 */
971 	if (GrantExcl) {
972 		node->n_oplock.excl_open = ofile;
973 		node->n_oplock.ol_state = *rop | EXCLUSIVE;
974 
975 		/*
976 		 * This operation MUST be made cancelable...
977 		 * This operation waits until the oplock is
978 		 * broken or canceled, as specified in
979 		 * section 2.1.5.17.3.
980 		 *
981 		 * When the operation specified in section
982 		 * 2.1.5.17.3 is called, its following input
983 		 * parameters are transferred to this routine
984 		 * and then returned by it:
985 		 *
986 		 * Status is set to OplockCompletionStatus
987 		 * NewOplockLevel, AcknowledgeRequired...
988 		 * from the operation specified in
989 		 * section 2.1.5.17.3.
990 		 */
991 		/* Keep *rop = ... from caller. */
992 		if ((node->n_oplock.ol_state & BREAK_ANY) != 0) {
993 			status = NT_STATUS_OPLOCK_BREAK_IN_PROGRESS;
994 			/* Caller does smb_oplock_wait_break() */
995 		} else {
996 			status = NT_STATUS_SUCCESS;
997 		}
998 	}
999 
1000 out:
1001 	if (status == NT_STATUS_OPLOCK_NOT_GRANTED)
1002 		*rop = LEVEL_NONE;
1003 
1004 	return (status);
1005 }
1006 
1007 /*
1008  * 2.1.5.17.2 Algorithm to Request a Shared Oplock
1009  *
1010  * The inputs for requesting a shared oplock are:
1011  *	Open: The Open on which the oplock is being requested.
1012  *	RequestedOplock: The oplock type being requested.
1013  *	GrantingInAck: A Boolean value, TRUE if this oplock is being
1014  *	  requested as part of an oplock break acknowledgement,
1015  *	  FALSE if not.
1016  *
1017  * On completion, the object store MUST return:
1018  *	Status: An NTSTATUS code that specifies the result.
1019  *	NewOplockLevel: The type of oplock that the requested oplock has been
1020  *	  broken (reduced) to.  If a failure status is returned in Status,
1021  *	  the value of this field is undefined.  Valid values are as follows:
1022  *		LEVEL_NONE (that is, no oplock)
1023  *		LEVEL_TWO
1024  *		A combination of one or more of the following flags:
1025  *			READ_CACHING
1026  *			HANDLE_CACHING
1027  *			WRITE_CACHING
1028  *	AcknowledgeRequired: A Boolean value: TRUE if the server MUST
1029  *	acknowledge the oplock break; FALSE if not, as specified in
1030  *	section 2.1.5.18. If a failure status is returned in Status,
1031  *	the value of this field is undefined.
1032  *
1033  * Note: Stores NewOplockLevel in *rop
1034  */
1035 static uint32_t
1036 smb_oplock_req_shared(
1037     smb_ofile_t *ofile,		/* in: the "Open" */
1038     uint32_t *rop,		/* in: "RequestedOplock", out:NewOplockLevel */
1039     boolean_t GrantingInAck)
1040 {
1041 	smb_node_t *node = ofile->f_node;
1042 	smb_ofile_t *o;
1043 	boolean_t OplockGranted = B_FALSE;
1044 	uint32_t status = NT_STATUS_OPLOCK_NOT_GRANTED;
1045 
1046 	ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
1047 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
1048 
1049 	/*
1050 	 * Don't allow grants on closing ofiles.
1051 	 */
1052 	if (ofile->f_oplock.og_closing)
1053 		return (status);
1054 
1055 	/*
1056 	 * If Open.Stream.Oplock is empty:
1057 	 *   Build a new Oplock object with fields initialized as follows:
1058 	 *	Oplock.State set to NO_OPLOCK.
1059 	 *	All other fields set to 0/empty.
1060 	 *   Store the new Oplock object in Open.Stream.Oplock.
1061 	 * EndIf
1062 	 *
1063 	 * Implementation specific:
1064 	 * Open.Stream.Oplock maps to: node->n_oplock
1065 	 */
1066 	if (node->n_oplock.ol_state == 0) {
1067 		node->n_oplock.ol_state = NO_OPLOCK;
1068 	}
1069 
1070 	/*
1071 	 * If (GrantingInAck is FALSE) and (Open.Stream.Oplock.State
1072 	 * contains one or more of BREAK_TO_TWO, BREAK_TO_NONE,
1073 	 * BREAK_TO_TWO_TO_NONE, BREAK_TO_READ_CACHING,
1074 	 * BREAK_TO_WRITE_CACHING, BREAK_TO_HANDLE_CACHING,
1075 	 * BREAK_TO_NO_CACHING, or EXCLUSIVE), then:
1076 	 *	The operation MUST be failed with Status set to
1077 	 *	STATUS_OPLOCK_NOT_GRANTED.
1078 	 * EndIf
1079 	 */
1080 	if (GrantingInAck == B_FALSE &&
1081 	    (node->n_oplock.ol_state & (BREAK_ANY | EXCLUSIVE)) != 0) {
1082 		status = NT_STATUS_OPLOCK_NOT_GRANTED;
1083 		goto out;
1084 	}
1085 
1086 	/* Switch (RequestedOplock): */
1087 	switch (*rop) {
1088 
1089 	case LEVEL_TWO:
1090 		/*
1091 		 * The operation MUST be failed with Status set to
1092 		 * STATUS_OPLOCK_NOT_GRANTED if Open.Stream.Oplock.State
1093 		 * is anything other than the following:
1094 		 *	NO_OPLOCK
1095 		 *	LEVEL_TWO_OPLOCK
1096 		 *	READ_CACHING
1097 		 *	(LEVEL_TWO_OPLOCK|READ_CACHING)
1098 		 */
1099 		switch (node->n_oplock.ol_state) {
1100 		default:
1101 			status = NT_STATUS_OPLOCK_NOT_GRANTED;
1102 			goto out;
1103 		case NO_OPLOCK:
1104 		case LEVEL_TWO:
1105 		case READ_CACHING:
1106 		case (LEVEL_TWO | READ_CACHING):
1107 			break;
1108 		}
1109 		/* Deliberate FALL-THROUGH to next Case statement. */
1110 		/* FALLTHROUGH */
1111 
1112 	case READ_CACHING:
1113 		/*
1114 		 * The operation MUST be failed with Status set to
1115 		 * STATUS_OPLOCK_NOT_GRANTED if GrantingInAck is FALSE
1116 		 * and Open.Stream.Oplock.State is anything other than...
1117 		 */
1118 		switch (node->n_oplock.ol_state) {
1119 		default:
1120 			if (GrantingInAck == B_FALSE) {
1121 				status = NT_STATUS_OPLOCK_NOT_GRANTED;
1122 				goto out;
1123 			}
1124 			break;
1125 		case NO_OPLOCK:
1126 		case LEVEL_TWO:
1127 		case READ_CACHING:
1128 		case (LEVEL_TWO | READ_CACHING):
1129 		case (READ_CACHING | HANDLE_CACHING):
1130 		case (READ_CACHING | HANDLE_CACHING | MIXED_R_AND_RH):
1131 		case (READ_CACHING | HANDLE_CACHING | BREAK_TO_READ_CACHING):
1132 		case (READ_CACHING | HANDLE_CACHING | BREAK_TO_NO_CACHING):
1133 			break;
1134 		}
1135 
1136 		if (GrantingInAck == B_FALSE) {
1137 			/*
1138 			 * If there is an Open on
1139 			 * Open.Stream.Oplock.RHOplocks
1140 			 * whose TargetOplockKey is equal to
1141 			 * Open.TargetOplockKey, the operation
1142 			 * MUST be failed with Status set to
1143 			 * STATUS_OPLOCK_NOT_GRANTED.
1144 			 *
1145 			 * If there is an Open on
1146 			 * Open.Stream.Oplock.RHBreakQueue
1147 			 * whose TargetOplockKey is equal to
1148 			 * Open.TargetOplockKey, the operation
1149 			 * MUST be failed with Status set to
1150 			 * STATUS_OPLOCK_NOT_GRANTED.
1151 			 *
1152 			 * Implement both in one list walk.
1153 			 */
1154 			FOREACH_NODE_OFILE(node, o) {
1155 				if ((o->f_oplock.onlist_RH ||
1156 				    o->f_oplock.onlist_RHBQ) &&
1157 				    CompareOplockKeys(ofile, o, 0)) {
1158 					status = NT_STATUS_OPLOCK_NOT_GRANTED;
1159 					goto out;
1160 				}
1161 			}
1162 
1163 			/*
1164 			 * If there is an Open ThisOpen on
1165 			 * Open.Stream.Oplock.ROplocks whose
1166 			 * TargetOplockKey is equal to Open.TargetOplockKey
1167 			 * (there is supposed to be at most one present):
1168 			 *	* Remove ThisOpen from Open...ROplocks.
1169 			 *	* Notify the server of an oplock break
1170 			 *	  according to the algorithm in section
1171 			 *	  2.1.5.17.3, setting the algorithm's
1172 			 *	  parameters as follows:
1173 			 *		* BreakingOplockOpen = ThisOpen
1174 			 *		* NewOplockLevel = READ_CACHING
1175 			 *		* AcknowledgeRequired = FALSE
1176 			 *		* OplockCompletionStatus =
1177 			 *		  STATUS_..._NEW_HANDLE
1178 			 * (The operation does not end at this point;
1179 			 *  this call to 2.1.5.17.3 completes some
1180 			 *  earlier call to 2.1.5.17.2.)
1181 			 * EndIf
1182 			 *
1183 			 * If this SMB2 lease already has an "R" handle,
1184 			 * we'll update that lease locally to point to
1185 			 * this new handle.
1186 			 */
1187 			FOREACH_NODE_OFILE(node, o) {
1188 				if (o->f_oplock.onlist_R == 0)
1189 					continue;
1190 				if (CompareOplockKeys(ofile, o, 0)) {
1191 					o->f_oplock.onlist_R = B_FALSE;
1192 					node->n_oplock.cnt_R--;
1193 					ASSERT(node->n_oplock.cnt_R >= 0);
1194 					smb_oplock_ind_break(o,
1195 					    CACHE_R, B_FALSE,
1196 					    STATUS_NEW_HANDLE);
1197 				}
1198 			}
1199 		} /* EndIf !GrantingInAck */
1200 
1201 		/*
1202 		 * If RequestedOplock equals LEVEL_TWO:
1203 		 *	Add Open to Open.Stream.Oplock.IIOplocks.
1204 		 * Else // RequestedOplock equals READ_CACHING:
1205 		 *	Add Open to Open.Stream.Oplock.ROplocks.
1206 		 * EndIf
1207 		 */
1208 		if (*rop == LEVEL_TWO) {
1209 			ofile->f_oplock.onlist_II = B_TRUE;
1210 			node->n_oplock.cnt_II++;
1211 		} else {
1212 			/* (*rop == READ_CACHING) */
1213 			if (ofile->f_oplock.onlist_R == B_FALSE) {
1214 				ofile->f_oplock.onlist_R = B_TRUE;
1215 				node->n_oplock.cnt_R++;
1216 			}
1217 		}
1218 
1219 		/*
1220 		 * Recompute Open.Stream.Oplock.State according to the
1221 		 * algorithm in section 2.1.4.13, passing Open.Stream.Oplock
1222 		 * as the ThisOplock parameter.
1223 		 * Set OplockGranted to TRUE.
1224 		 */
1225 		RecomputeOplockState(node);
1226 		OplockGranted = B_TRUE;
1227 		break;
1228 
1229 	case (READ_CACHING|HANDLE_CACHING):
1230 		/*
1231 		 * The operation MUST be failed with Status set to
1232 		 * STATUS_OPLOCK_NOT_GRANTED if GrantingInAck is FALSE
1233 		 * and Open.Stream.Oplock.State is anything other than...
1234 		 */
1235 		switch (node->n_oplock.ol_state) {
1236 		default:
1237 			if (GrantingInAck == B_FALSE) {
1238 				status = NT_STATUS_OPLOCK_NOT_GRANTED;
1239 				goto out;
1240 			}
1241 			break;
1242 		case NO_OPLOCK:
1243 		case READ_CACHING:
1244 		case (READ_CACHING | HANDLE_CACHING):
1245 		case (READ_CACHING | HANDLE_CACHING | MIXED_R_AND_RH):
1246 		case (READ_CACHING | HANDLE_CACHING | BREAK_TO_READ_CACHING):
1247 		case (READ_CACHING | HANDLE_CACHING | BREAK_TO_NO_CACHING):
1248 			break;
1249 		}
1250 
1251 		/*
1252 		 * If Open.Stream.IsDeleted is TRUE, the operation MUST be
1253 		 *  failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
1254 		 */
1255 		if ((node->flags & NODE_FLAGS_DELETING) != 0) {
1256 			status = NT_STATUS_OPLOCK_NOT_GRANTED;
1257 			goto out;
1258 		}
1259 
1260 		if (GrantingInAck == B_FALSE) {
1261 			/*
1262 			 * If there is an Open ThisOpen on
1263 			 * Open.Stream.Oplock.ROplocks whose
1264 			 * TargetOplockKey is equal to Open.TargetOplockKey
1265 			 * (there is supposed to be at most one present):
1266 			 *	* Remove ThisOpen from Open...ROplocks.
1267 			 *	* Notify the server of an oplock break
1268 			 *	  according to the algorithm in section
1269 			 *	  2.1.5.17.3, setting the algorithm's
1270 			 *	  parameters as follows:
1271 			 *		* BreakingOplockOpen = ThisOpen
1272 			 *		* NewOplockLevel = CACHE_RH
1273 			 *		* AcknowledgeRequired = FALSE
1274 			 *		* OplockCompletionStatus =
1275 			 *		  STATUS_..._NEW_HANDLE
1276 			 * (The operation does not end at this point;
1277 			 *  this call to 2.1.5.17.3 completes some
1278 			 *  earlier call to 2.1.5.17.2.)
1279 			 * EndIf
1280 			 *
1281 			 * If this SMB2 lease already has an "R" handle,
1282 			 * we'll update that lease locally to point to
1283 			 * this new handle (upgrade to "RH").
1284 			 */
1285 			FOREACH_NODE_OFILE(node, o) {
1286 				if (o->f_oplock.onlist_R == 0)
1287 					continue;
1288 				if (CompareOplockKeys(ofile, o, 0)) {
1289 					o->f_oplock.onlist_R = B_FALSE;
1290 					node->n_oplock.cnt_R--;
1291 					ASSERT(node->n_oplock.cnt_R >= 0);
1292 					smb_oplock_ind_break(o,
1293 					    CACHE_RH, B_FALSE,
1294 					    STATUS_NEW_HANDLE);
1295 				}
1296 			}
1297 
1298 			/*
1299 			 * If there is an Open ThisOpen on
1300 			 * Open.Stream.Oplock.RHOplocks whose
1301 			 * TargetOplockKey is equal to Open.TargetOplockKey
1302 			 * (there is supposed to be at most one present):
1303 			 *	XXX: Note, the spec. was missing a step:
1304 			 *	XXX: Remove the open from RHOplocks
1305 			 *	XXX: Confirm with MS dochelp
1306 			 *	* Notify the server of an oplock break
1307 			 *	  according to the algorithm in section
1308 			 *	  2.1.5.17.3, setting the algorithm's
1309 			 *	  parameters as follows:
1310 			 *		* BreakingOplockOpen = ThisOpen
1311 			 *		* NewOplockLevel =
1312 			 *		  (READ_CACHING|HANDLE_CACHING)
1313 			 *		* AcknowledgeRequired = FALSE
1314 			 *		* OplockCompletionStatus =
1315 			 *		  STATUS_..._NEW_HANDLE
1316 			 * (The operation does not end at this point;
1317 			 *  this call to 2.1.5.17.3 completes some
1318 			 *  earlier call to 2.1.5.17.2.)
1319 			 * EndIf
1320 			 *
1321 			 * If this SMB2 lease already has an "RH" handle,
1322 			 * we'll update that lease locally to point to
1323 			 * this new handle.
1324 			 */
1325 			FOREACH_NODE_OFILE(node, o) {
1326 				if (o->f_oplock.onlist_RH == 0)
1327 					continue;
1328 				if (CompareOplockKeys(ofile, o, 0)) {
1329 					o->f_oplock.onlist_RH = B_FALSE;
1330 					node->n_oplock.cnt_RH--;
1331 					ASSERT(node->n_oplock.cnt_RH >= 0);
1332 					smb_oplock_ind_break(o,
1333 					    CACHE_RH, B_FALSE,
1334 					    STATUS_NEW_HANDLE);
1335 				}
1336 			}
1337 		} /* EndIf !GrantingInAck */
1338 
1339 		/*
1340 		 * Add Open to Open.Stream.Oplock.RHOplocks.
1341 		 */
1342 		if (ofile->f_oplock.onlist_RH == B_FALSE) {
1343 			ofile->f_oplock.onlist_RH = B_TRUE;
1344 			node->n_oplock.cnt_RH++;
1345 		}
1346 
1347 		/*
1348 		 * Recompute Open.Stream.Oplock.State according to the
1349 		 * algorithm in section 2.1.4.13, passing Open.Stream.Oplock
1350 		 * as the ThisOplock parameter.
1351 		 * Set OplockGranted to TRUE.
1352 		 */
1353 		RecomputeOplockState(node);
1354 		OplockGranted = B_TRUE;
1355 		break;
1356 
1357 	default:
1358 		/* No other value of RequestedOplock is possible. */
1359 		ASSERT(0);
1360 		status = NT_STATUS_OPLOCK_NOT_GRANTED;
1361 		goto out;
1362 	}  /* EndSwitch (RequestedOplock) */
1363 
1364 	/*
1365 	 * If OplockGranted is TRUE:
1366 	 * This operation MUST be made cancelable by inserting it into
1367 	 *   CancelableOperations.CancelableOperationList.
1368 	 * The operation waits until the oplock is broken or canceled,
1369 	 * as specified in section 2.1.5.17.3.
1370 	 * When the operation specified in section 2.1.5.17.3 is called,
1371 	 * its following input parameters are transferred to this routine
1372 	 * and returned by it:
1373 	 *	Status is set to OplockCompletionStatus from the
1374 	 *	  operation specified in section 2.1.5.17.3.
1375 	 *	NewOplockLevel is set to NewOplockLevel from the
1376 	 *	  operation specified in section 2.1.5.17.3.
1377 	 *	AcknowledgeRequired is set to AcknowledgeRequired from
1378 	 *	  the operation specified in section 2.1.5.17.3.
1379 	 * EndIf
1380 	 */
1381 	if (OplockGranted) {
1382 		/* Note: *rop already set. */
1383 		if ((node->n_oplock.ol_state & BREAK_ANY) != 0) {
1384 			status = NT_STATUS_OPLOCK_BREAK_IN_PROGRESS;
1385 			/* Caller does smb_oplock_wait_break() */
1386 		} else {
1387 			status = NT_STATUS_SUCCESS;
1388 		}
1389 	}
1390 
1391 out:
1392 	if (status == NT_STATUS_OPLOCK_NOT_GRANTED)
1393 		*rop = LEVEL_NONE;
1394 
1395 	return (status);
1396 }
1397 
1398 /*
1399  * 2.1.5.17.3 Indicating an Oplock Break to the Server
1400  * See smb_srv_oplock.c
1401  */
1402 
1403 /*
1404  * 2.1.5.18 Server Acknowledges an Oplock Break
1405  *
1406  * The server provides:
1407  *	Open - The Open associated with the oplock that has broken.
1408  *	Type - As part of the acknowledgement, the server indicates a
1409  *	  new oplock it would like in place of the one that has broken.
1410  *	  Valid values are as follows:
1411  *		LEVEL_NONE
1412  *		LEVEL_TWO
1413  *		LEVEL_GRANULAR - If this oplock type is specified,
1414  *		  the server additionally provides:
1415  *	RequestedOplockLevel - A combination of zero or more of
1416  *	  the following flags:
1417  *		READ_CACHING
1418  *		HANDLE_CACHING
1419  *		WRITE_CACHING
1420  *
1421  * If the server requests a new oplock and it is granted, the request
1422  * does not complete until the oplock is broken; the operation waits for
1423  * this to happen. Processing of an oplock break is described in
1424  * section 2.1.5.17.3.  Whether the new oplock is granted or not, the
1425  * object store MUST return:
1426  *
1427  *	Status - An NTSTATUS code indicating the result of the operation.
1428  *
1429  * If the server requests a new oplock and it is granted, then when the
1430  * oplock breaks and the request finally completes, the object store MUST
1431  * additionally return:
1432  *	NewOplockLevel: The type of oplock the requested oplock has
1433  *	  been broken to. Valid values are as follows:
1434  *		LEVEL_NONE (that is, no oplock)
1435  *		LEVEL_TWO
1436  *		A combination of one or more of the following flags:
1437  *			READ_CACHING
1438  *			HANDLE_CACHING
1439  *			WRITE_CACHING
1440  *	AcknowledgeRequired: A Boolean value; TRUE if the server MUST
1441  *	  acknowledge the oplock break, FALSE if not, as specified in
1442  *	  section 2.1.5.17.2.
1443  *
1444  * Note: Stores NewOplockLevel in *rop
1445  */
1446 uint32_t
1447 smb_oplock_ack_break(
1448     smb_request_t *sr,
1449     smb_ofile_t *ofile,
1450     uint32_t *rop)
1451 {
1452 	smb_node_t *node = ofile->f_node;
1453 	uint32_t type = *rop & OPLOCK_LEVEL_TYPE_MASK;
1454 	uint32_t level = *rop & OPLOCK_LEVEL_CACHE_MASK;
1455 	uint32_t status = NT_STATUS_SUCCESS;
1456 	uint32_t BreakToLevel;
1457 	boolean_t NewOplockGranted = B_FALSE;
1458 	boolean_t ReturnBreakToNone = B_FALSE;
1459 	boolean_t FoundMatchingRHOplock = B_FALSE;
1460 	int other_keys;
1461 
1462 	smb_llist_enter(&node->n_ofile_list, RW_READER);
1463 	mutex_enter(&node->n_oplock.ol_mutex);
1464 
1465 	/*
1466 	 * If Open.Stream.Oplock is empty, the operation MUST be
1467 	 * failed with Status set to STATUS_INVALID_OPLOCK_PROTOCOL.
1468 	 */
1469 	if (node->n_oplock.ol_state == 0) {
1470 		status = NT_STATUS_INVALID_OPLOCK_PROTOCOL;
1471 		goto out;
1472 	}
1473 
1474 	if (type == LEVEL_NONE || type == LEVEL_TWO) {
1475 		/*
1476 		 * If Open.Stream.Oplock.ExclusiveOpen is not equal to Open,
1477 		 * the operation MUST be failed with Status set to
1478 		 * STATUS_INVALID_OPLOCK_PROTOCOL.
1479 		 */
1480 		if (node->n_oplock.excl_open != ofile) {
1481 			status = NT_STATUS_INVALID_OPLOCK_PROTOCOL;
1482 			goto out;
1483 		}
1484 
1485 		/*
1486 		 * If Type is LEVEL_TWO and Open.Stream.Oplock.State
1487 		 * contains BREAK_TO_TWO:
1488 		 *	Set Open.Stream.Oplock.State to LEVEL_TWO_OPLOCK.
1489 		 *	Set NewOplockGranted to TRUE.
1490 		 */
1491 		if (type == LEVEL_TWO &&
1492 		    (node->n_oplock.ol_state & BREAK_TO_TWO) != 0) {
1493 			node->n_oplock.ol_state = LEVEL_TWO;
1494 			NewOplockGranted = B_TRUE;
1495 		}
1496 
1497 		/*
1498 		 * Else If Open.Stream.Oplock.State contains
1499 		 * BREAK_TO_TWO or BREAK_TO_NONE:
1500 		 *	Set Open.Stream.Oplock.State to NO_OPLOCK.
1501 		 */
1502 		else if ((node->n_oplock.ol_state &
1503 		    (BREAK_TO_TWO | BREAK_TO_NONE)) != 0) {
1504 			node->n_oplock.ol_state = NO_OPLOCK;
1505 		}
1506 
1507 		/*
1508 		 * Else If Open.Stream.Oplock.State contains
1509 		 * BREAK_TO_TWO_TO_NONE:
1510 		 *	Set Open.Stream.Oplock.State to NO_OPLOCK.
1511 		 *	Set ReturnBreakToNone to TRUE.
1512 		 */
1513 		else if ((node->n_oplock.ol_state &
1514 		    BREAK_TO_TWO_TO_NONE) != 0) {
1515 			node->n_oplock.ol_state = NO_OPLOCK;
1516 			ReturnBreakToNone = B_TRUE;
1517 		}
1518 
1519 		/*
1520 		 * Else
1521 		 *	The operation MUST be failed with Status set to
1522 		 *	STATUS_INVALID_OPLOCK_PROTOCOL.
1523 		 */
1524 		else {
1525 			status = NT_STATUS_INVALID_OPLOCK_PROTOCOL;
1526 			goto out;
1527 		}
1528 
1529 		/*
1530 		 * For each Open WaitingOpen on Open.Stream.Oplock.WaitList:
1531 		 *	Indicate that the operation associated with
1532 		 *	  WaitingOpen can continue according to the
1533 		 *	  algorithm in section 2.1.4.12.1, setting
1534 		 *	  OpenToRelease = WaitingOpen.
1535 		 *	Remove WaitingOpen from Open.Stream.Oplock.WaitList.
1536 		 * EndFor
1537 		 */
1538 		if (node->n_oplock.waiters)
1539 			cv_broadcast(&node->n_oplock.WaitingOpenCV);
1540 
1541 		/*
1542 		 * Set Open.Stream.Oplock.ExclusiveOpen to NULL.
1543 		 */
1544 		node->n_oplock.excl_open = NULL;
1545 
1546 		if (NewOplockGranted) {
1547 			/*
1548 			 * The operation waits until the newly-granted
1549 			 * Level 2 oplock is broken, as specified in
1550 			 * section 2.1.5.17.3.
1551 			 *
1552 			 * Here we have just Ack'ed a break-to-II
1553 			 * so now get the level II oplock.  We also
1554 			 * checked for break-to-none above, so this
1555 			 * will not need to wait for oplock breaks.
1556 			 */
1557 			status = smb_oplock_req_shared(ofile, rop, B_TRUE);
1558 		}
1559 
1560 		else if (ReturnBreakToNone) {
1561 			/*
1562 			 * In this case the server was expecting the oplock
1563 			 * to break to Level 2, but because the oplock is
1564 			 * actually breaking to None (that is, no oplock),
1565 			 * the object store MUST indicate an oplock break
1566 			 * to the server according to the algorithm in
1567 			 * section 2.1.5.17.3, setting the algorithm's
1568 			 * parameters as follows:
1569 			 *	BreakingOplockOpen = Open.
1570 			 *	NewOplockLevel = LEVEL_NONE.
1571 			 *	AcknowledgeRequired = FALSE.
1572 			 *	OplockCompletionStatus = STATUS_SUCCESS.
1573 			 * (Because BreakingOplockOpen is equal to the
1574 			 * passed-in Open, the operation ends at this point.)
1575 			 *
1576 			 * It should be OK to return the reduced oplock
1577 			 * (*rop = LEVEL_NONE) here and avoid the need
1578 			 * to send another oplock break.  This is safe
1579 			 * because we already have an Ack of the break
1580 			 * to Level_II, and the additional break to none
1581 			 * would use AckRequired = FALSE.
1582 			 *
1583 			 * If we followed the spec here, we'd have:
1584 			 * smb_oplock_ind_break(ofile,
1585 			 *    LEVEL_NONE, B_FALSE,
1586 			 *    NT_STATUS_SUCCESS);
1587 			 * (Or smb_oplock_ind_break_in_ack...)
1588 			 */
1589 			*rop = LEVEL_NONE;	/* Reduced from L2 */
1590 		}
1591 		status = NT_STATUS_SUCCESS;
1592 		goto out;
1593 	} /* LEVEL_NONE or LEVEL_TWO */
1594 
1595 	if (type != LEVEL_GRANULAR) {
1596 		status = NT_STATUS_INVALID_OPLOCK_PROTOCOL;
1597 		goto out;
1598 	}
1599 
1600 	/* LEVEL_GRANULAR */
1601 
1602 	/*
1603 	 * Let BREAK_LEVEL_MASK = (BREAK_TO_READ_CACHING |
1604 	 *   BREAK_TO_WRITE_CACHING | BREAK_TO_HANDLE_CACHING |
1605 	 *   BREAK_TO_NO_CACHING),
1606 	 * R_AND_RH_GRANTED = (READ_CACHING | HANDLE_CACHING |
1607 	 *   MIXED_R_AND_RH),
1608 	 * RH_GRANTED = (READ_CACHING | HANDLE_CACHING)
1609 	 *
1610 	 * (See BREAK_LEVEL_MASK in smb_oplock.h)
1611 	 */
1612 #define	RH_GRANTED		(READ_CACHING|HANDLE_CACHING)
1613 #define	R_AND_RH_GRANTED	(RH_GRANTED|MIXED_R_AND_RH)
1614 
1615 	/*
1616 	 * If there are no BREAK_LEVEL_MASK flags set, this is invalid,
1617 	 * unless the state is R_AND_RH_GRANTED or RH_GRANTED, in which
1618 	 * case we'll need to see if the RHBreakQueue is empty.
1619 	 */
1620 
1621 	/*
1622 	 * If (Open.Stream.Oplock.State does not contain any flag in
1623 	 * BREAK_LEVEL_MASK and
1624 	 *  (Open.Stream.Oplock.State != R_AND_RH_GRANTED) and
1625 	 *   (Open.Stream.Oplock.State != RH_GRANTED)) or
1626 	 *   (((Open.Stream.Oplock.State == R_AND_RH_GRANTED) or
1627 	 *  (Open.Stream.Oplock.State == RH_GRANTED)) and
1628 	 *   Open.Stream.Oplock.RHBreakQueue is empty):
1629 	 *	The request MUST be failed with Status set to
1630 	 *	  STATUS_INVALID_OPLOCK_PROTOCOL.
1631 	 * EndIf
1632 	 */
1633 	if ((node->n_oplock.ol_state & BREAK_LEVEL_MASK) == 0) {
1634 		if ((node->n_oplock.ol_state != R_AND_RH_GRANTED) &&
1635 		    (node->n_oplock.ol_state != RH_GRANTED)) {
1636 			status = NT_STATUS_INVALID_OPLOCK_PROTOCOL;
1637 			goto out;
1638 		}
1639 		/* State is R_AND_RH_GRANTED or RH_GRANTED */
1640 		if (node->n_oplock.cnt_RHBQ == 0) {
1641 			status = NT_STATUS_INVALID_OPLOCK_PROTOCOL;
1642 			goto out;
1643 		}
1644 	}
1645 
1646 	/*
1647 	 * Compute the "Break To" cache level from the
1648 	 * BREAK_TO_... flags
1649 	 */
1650 	switch (node->n_oplock.ol_state & BREAK_LEVEL_MASK) {
1651 	case (BREAK_TO_READ_CACHING | BREAK_TO_WRITE_CACHING |
1652 	    BREAK_TO_HANDLE_CACHING):
1653 		BreakToLevel = CACHE_RWH;
1654 		break;
1655 	case (BREAK_TO_READ_CACHING | BREAK_TO_WRITE_CACHING):
1656 		BreakToLevel = CACHE_RW;
1657 		break;
1658 	case (BREAK_TO_READ_CACHING | BREAK_TO_HANDLE_CACHING):
1659 		BreakToLevel = CACHE_RH;
1660 		break;
1661 	case BREAK_TO_READ_CACHING:
1662 		BreakToLevel = READ_CACHING;
1663 		break;
1664 	case BREAK_TO_NO_CACHING:
1665 	default:
1666 		BreakToLevel = LEVEL_NONE;
1667 		break;
1668 	}
1669 
1670 	/* Switch Open.Stream.Oplock.State */
1671 	switch (node->n_oplock.ol_state) {
1672 
1673 	case (READ_CACHING|HANDLE_CACHING|MIXED_R_AND_RH):
1674 	case (READ_CACHING|HANDLE_CACHING):
1675 	case (READ_CACHING|HANDLE_CACHING|BREAK_TO_READ_CACHING):
1676 	case (READ_CACHING|HANDLE_CACHING|BREAK_TO_NO_CACHING):
1677 		/*
1678 		 * For each RHOpContext ThisContext in
1679 		 * Open.Stream.Oplock.RHBreakQueue:
1680 		 *	If ThisContext.Open equals Open:
1681 		 *		(see below)
1682 		 *
1683 		 * Implementation skips the list walk, because
1684 		 * we can get the ofile directly.
1685 		 */
1686 		if (ofile->f_oplock.onlist_RHBQ) {
1687 			smb_ofile_t *o;
1688 
1689 			/*
1690 			 * Set FoundMatchingRHOplock to TRUE.
1691 			 * If ThisContext.BreakingToRead is FALSE:
1692 			 *	If RequestedOplockLevel is not 0 and
1693 			 *	Open.Stream.Oplock.WaitList is not empty:
1694 			 *	    The object store MUST indicate an
1695 			 *	    oplock break to the server according to
1696 			 *	    the algorithm in section 2.1.5.17.3,
1697 			 *	    setting the algorithm's params as follows:
1698 			 *		BreakingOplockOpen = Open.
1699 			 *		NewOplockLevel = LEVEL_NONE.
1700 			 *		AcknowledgeRequired = TRUE.
1701 			 *		OplockCompletionStatus =
1702 			 *		  STATUS_CANNOT_GRANT_...
1703 			 *  (Because BreakingOplockOpen is equal to the
1704 			 *   passed Open, the operation ends at this point.)
1705 			 * EndIf
1706 			 */
1707 			FoundMatchingRHOplock = B_TRUE;
1708 			if (ofile->f_oplock.BreakingToRead == B_FALSE) {
1709 				if (level != 0 && node->n_oplock.waiters) {
1710 					/* The ofile stays on RHBQ */
1711 					smb_oplock_ind_break_in_ack(
1712 					    sr, ofile,
1713 					    LEVEL_NONE, B_TRUE);
1714 					status = NT_STATUS_SUCCESS;
1715 					goto out;
1716 				}
1717 			}
1718 
1719 			/*
1720 			 * Else // ThisContext.BreakingToRead is TRUE.
1721 			 *    If Open.Stream.Oplock.WaitList is not empty and
1722 			 *    (RequestedOplockLevel is CACHE_RW or CACHE_RWH:
1723 			 *	The object store MUST indicate an oplock
1724 			 *	break to the server according to the
1725 			 *	algorithm in section 2.1.5.17.3, setting
1726 			 *	the algorithm's parameters as follows:
1727 			 *		* BreakingOplockOpen = Open
1728 			 *		* NewOplockLevel = READ_CACHING
1729 			 *		* AcknowledgeRequired = TRUE
1730 			 *		* OplockCompletionStatus =
1731 			 *		  STATUS_CANNOT_GRANT...
1732 			 *	(Because BreakingOplockOpen is equal to the
1733 			 *	 passed-in Open, the operation ends at this
1734 			 *	 point.)
1735 			 *    EndIf
1736 			 * EndIf
1737 			 */
1738 			else { /* BreakingToRead is TRUE */
1739 				if (node->n_oplock.waiters &&
1740 				    (level == CACHE_RW ||
1741 				    level == CACHE_RWH)) {
1742 					/* The ofile stays on RHBQ */
1743 					smb_oplock_ind_break_in_ack(
1744 					    sr, ofile,
1745 					    CACHE_R, B_TRUE);
1746 					status = NT_STATUS_SUCCESS;
1747 					goto out;
1748 				}
1749 			}
1750 
1751 			/*
1752 			 * Remove ThisContext from Open...RHBreakQueue.
1753 			 */
1754 			ofile->f_oplock.onlist_RHBQ = B_FALSE;
1755 			node->n_oplock.cnt_RHBQ--;
1756 			ASSERT(node->n_oplock.cnt_RHBQ >= 0);
1757 
1758 			/*
1759 			 * The operation waiting for the Read-Handle
1760 			 * oplock to break can continue if there are
1761 			 * no more Read-Handle oplocks outstanding, or
1762 			 * if all the remaining Read-Handle oplocks
1763 			 * have the same oplock key as the waiting
1764 			 * operation.
1765 			 *
1766 			 * For each Open WaitingOpen on Open...WaitList:
1767 			 *
1768 			 *	* If (Open...RHBreakQueue is empty) or
1769 			 *	  (all RHOpContext.Open.TargetOplockKey values
1770 			 *	  on Open.Stream.Oplock.RHBreakQueue are
1771 			 *	  equal to WaitingOpen.TargetOplockKey):
1772 			 *		* Indicate that the operation assoc.
1773 			 *		  with WaitingOpen can continue
1774 			 *		  according to the algorithm in
1775 			 *		  section 2.1.4.12.1, setting
1776 			 *		  OpenToRelease = WaitingOpen.
1777 			 *		* Remove WaitingOpen from
1778 			 *		  Open.Stream.Oplock.WaitList.
1779 			 *	* EndIf
1780 			 * EndFor
1781 			 */
1782 			other_keys = 0;
1783 			FOREACH_NODE_OFILE(node, o) {
1784 				if (o->f_oplock.onlist_RHBQ == 0)
1785 					continue;
1786 				if (!CompareOplockKeys(ofile, o, 0))
1787 					other_keys++;
1788 			}
1789 			if (other_keys == 0)
1790 				cv_broadcast(&node->n_oplock.WaitingOpenCV);
1791 
1792 			/*
1793 			 * If RequestedOplockLevel is 0 (that is, no flags):
1794 			 *	* Recompute Open.Stream.Oplock.State
1795 			 *	  according to the algorithm in section
1796 			 *	  2.1.4.13, passing Open.Stream.Oplock as
1797 			 *	  the ThisOplock parameter.
1798 			 *	* The algorithm MUST return Status set to
1799 			 *	  STATUS_SUCCESS at this point.
1800 			 */
1801 			if (level == 0) {
1802 				RecomputeOplockState(node);
1803 				status = NT_STATUS_SUCCESS;
1804 				goto out;
1805 			}
1806 
1807 			/*
1808 			 * Else If RequestedOplockLevel does not contain
1809 			 * WRITE_CACHING:
1810 			 *	* The object store MUST request a shared oplock
1811 			 *	  according to the algorithm in section
1812 			 *	  2.1.5.17.2, setting the algorithm's
1813 			 *	  parameters as follows:
1814 			 *		* Open = current Open.
1815 			 *		* RequestedOplock =
1816 			 *		  RequestedOplockLevel.
1817 			 *		* GrantingInAck = TRUE.
1818 			 *	* The operation MUST at this point return any
1819 			 *	  status code returned by the shared oplock
1820 			 *	  request algorithm.
1821 			 */
1822 			else if ((level & WRITE_CACHING) == 0) {
1823 				*rop = level;
1824 				status = smb_oplock_req_shared(
1825 				    ofile, rop, B_TRUE);
1826 				goto out;
1827 			}
1828 
1829 			/*
1830 			 * Set Open.Stream.Oplock.ExclusiveOpen to
1831 			 *   ThisContext.Open.
1832 			 * Set Open.Stream.Oplock.State to
1833 			 *   (RequestedOplockLevel|EXCLUSIVE).
1834 			 * This operation MUST be made cancelable by
1835 			 *   inserting it into CancelableOperations...
1836 			 * This operation waits until the oplock is
1837 			 * broken or canceled, as specified in
1838 			 * section 2.1.5.17.3.
1839 			 *
1840 			 * Implementation note:
1841 			 *
1842 			 * Once we assing ol_state below, there
1843 			 * will be no BREAK_TO_... flags set,
1844 			 * so no need to wait for oplock breaks.
1845 			 */
1846 			node->n_oplock.excl_open = ofile;
1847 			node->n_oplock.ol_state = level | EXCLUSIVE;
1848 			status = NT_STATUS_SUCCESS;
1849 		} /* onlist_RHBQ */
1850 		if (FoundMatchingRHOplock == B_FALSE) {
1851 			/* The operation MUST be failed with Status... */
1852 			status = NT_STATUS_INVALID_OPLOCK_PROTOCOL;
1853 			goto out;
1854 		}
1855 		break;	/* case (READ_CACHING|HANDLE_CACHING...) */
1856 
1857 	case (READ_CACHING|WRITE_CACHING|EXCLUSIVE|BREAK_TO_READ_CACHING):
1858 	case (READ_CACHING|WRITE_CACHING|EXCLUSIVE|BREAK_TO_NO_CACHING):
1859 	case (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|EXCLUSIVE|
1860 	    BREAK_TO_READ_CACHING|BREAK_TO_WRITE_CACHING):
1861 	case (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|EXCLUSIVE|
1862 	    BREAK_TO_READ_CACHING|BREAK_TO_HANDLE_CACHING):
1863 	case (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|EXCLUSIVE|
1864 	    BREAK_TO_READ_CACHING):
1865 	case (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|EXCLUSIVE|
1866 	    BREAK_TO_NO_CACHING):
1867 		/*
1868 		 * If Open.Stream.Oplock.ExclusiveOpen != Open:
1869 		 *	* The operation MUST be failed with Status set to
1870 		 *	  STATUS_INVALID_OPLOCK_PROTOCOL.
1871 		 * EndIf
1872 		 */
1873 		if (node->n_oplock.excl_open != ofile) {
1874 			status = NT_STATUS_INVALID_OPLOCK_PROTOCOL;
1875 			goto out;
1876 		}
1877 
1878 		/*
1879 		 * If Open.Stream.Oplock.WaitList is not empty and
1880 		 * Open.Stream.Oplock.State does not contain HANDLE_CACHING
1881 		 * and RequestedOplockLevel is CACHE_RWH:
1882 		 *	The object store MUST indicate an oplock break to
1883 		 *	the server according to the algorithm in section
1884 		 *	2.1.5.17.3, setting the algorithm's params as follows:
1885 		 *	* BreakingOplockOpen = Open.
1886 		 *	* NewOplockLevel = BreakToLevel (see above)
1887 		 *	* AcknowledgeRequired = TRUE.
1888 		 *	* OplockCompletionStatus =
1889 		 *	  STATUS_CANNOT_GRANT_REQUESTED_OPLOCK.
1890 		 *   (Because BreakingOplockOpen is equal to the passed-in
1891 		 *    Open, the operation ends at this point.)
1892 		 */
1893 		if (node->n_oplock.waiters &&
1894 		    (node->n_oplock.ol_state & HANDLE_CACHING) == 0 &&
1895 		    level == CACHE_RWH) {
1896 			smb_oplock_ind_break_in_ack(
1897 			    sr, ofile,
1898 			    BreakToLevel, B_TRUE);
1899 			status = NT_STATUS_SUCCESS;
1900 			goto out;
1901 		}
1902 
1903 		/*
1904 		 * Else If Open.Stream.IsDeleted is TRUE and
1905 		 * RequestedOplockLevel contains HANDLE_CACHING:
1906 		 */
1907 		else if (((node->flags & NODE_FLAGS_DELETING) != 0) &&
1908 		    (level & HANDLE_CACHING) != 0) {
1909 
1910 			/*
1911 			 * The object store MUST indicate an oplock break to
1912 			 * the server according to the algorithm in section
1913 			 * 2.1.5.17.3, setting the algorithm's params as
1914 			 * follows:
1915 			 *	* BreakingOplockOpen = Open.
1916 			 *	* NewOplockLevel = RequestedOplockLevel
1917 			 *	  without HANDLE_CACHING (for example if
1918 			 *	  RequestedOplockLevel is
1919 			 *	  (READ_CACHING|HANDLE_CACHING), then
1920 			 *	   NewOplockLevel would be just READ_CACHING).
1921 			 *	* AcknowledgeRequired = TRUE.
1922 			 *	* OplockCompletionStatus =
1923 			 *	  STATUS_CANNOT_GRANT_REQUESTED_OPLOCK.
1924 			 * (Because BreakingOplockOpen is equal to the
1925 			 *  passed-in Open, the operation ends at this point.)
1926 			 */
1927 			level &= ~HANDLE_CACHING;
1928 			smb_oplock_ind_break_in_ack(
1929 			    sr, ofile,
1930 			    level, B_TRUE);
1931 			status = NT_STATUS_SUCCESS;
1932 			goto out;
1933 		}
1934 
1935 		/*
1936 		 * For each Open WaitingOpen on Open.Stream.Oplock.WaitList:
1937 		 *	* Indicate that the operation associated with
1938 		 *	  WaitingOpen can continue according to the algorithm
1939 		 *	  in section 2.1.4.12.1, setting OpenToRelease
1940 		 *	  = WaitingOpen.
1941 		 *	* Remove WaitingOpen from Open.Stream.Oplock.WaitList.
1942 		 * EndFor
1943 		 */
1944 		cv_broadcast(&node->n_oplock.WaitingOpenCV);
1945 
1946 		/*
1947 		 * If RequestedOplockLevel does not contain WRITE_CACHING:
1948 		 *	* Set Open.Stream.Oplock.ExclusiveOpen to NULL.
1949 		 * EndIf
1950 		 */
1951 		if ((level & WRITE_CACHING) == 0) {
1952 			node->n_oplock.excl_open = NULL;
1953 		}
1954 
1955 		/*
1956 		 * If RequestedOplockLevel is 0 (that is, no flags):
1957 		 *	* Set Open.Stream.Oplock.State to NO_OPLOCK.
1958 		 *	* The operation returns Status set to STATUS_SUCCESS
1959 		 *	  at this point.
1960 		 */
1961 		if (level == 0) {
1962 			node->n_oplock.ol_state = NO_OPLOCK;
1963 			status = NT_STATUS_SUCCESS;
1964 			goto out;
1965 		}
1966 
1967 		/*
1968 		 * Deal with possibly still pending breaks.
1969 		 * Two cases: R to none, RH to R or none.
1970 		 *
1971 		 * XXX: These two missing from [MS-FSA]
1972 		 */
1973 
1974 		/*
1975 		 * Breaking R to none?  This is like:
1976 		 * "If BreakCacheLevel contains READ_CACHING..."
1977 		 * from smb_oplock_break_cmn.
1978 		 */
1979 		if (level == CACHE_R && BreakToLevel == LEVEL_NONE) {
1980 			smb_oplock_ind_break_in_ack(
1981 			    sr, ofile,
1982 			    LEVEL_NONE, B_FALSE);
1983 			node->n_oplock.ol_state = NO_OPLOCK;
1984 			status = NT_STATUS_SUCCESS;
1985 			goto out;
1986 		}
1987 
1988 		/*
1989 		 * Breaking RH to R or RH to none?  This is like:
1990 		 * "If BreakCacheLevel equals HANDLE_CACHING..."
1991 		 * from smb_oplock_break_cmn.
1992 		 */
1993 		if (level == CACHE_RH &&
1994 		    (BreakToLevel == CACHE_R ||
1995 		    BreakToLevel == LEVEL_NONE)) {
1996 			smb_oplock_ind_break_in_ack(
1997 			    sr, ofile,
1998 			    BreakToLevel, B_TRUE);
1999 
2000 			ofile->f_oplock.BreakingToRead =
2001 			    (BreakToLevel & READ_CACHING) ? 1: 0;
2002 
2003 			ASSERT(!(ofile->f_oplock.onlist_RHBQ));
2004 			ofile->f_oplock.onlist_RHBQ = B_TRUE;
2005 			node->n_oplock.cnt_RHBQ++;
2006 
2007 			RecomputeOplockState(node);
2008 			status = NT_STATUS_SUCCESS;
2009 			goto out;
2010 		}
2011 
2012 		/*
2013 		 * Else If RequestedOplockLevel does not contain WRITE_CACHING:
2014 		 *	* The object store MUST request a shared oplock
2015 		 *	  according to the algorithm in section 2.1.5.17.2,
2016 		 *	  setting the algorithm's parameters as follows:
2017 		 *		* Pass in the current Open.
2018 		 *		* RequestedOplock = RequestedOplockLevel.
2019 		 *		* GrantingInAck = TRUE.
2020 		 *	* The operation MUST at this point return any status
2021 		 *	  returned by the shared oplock request algorithm.
2022 		 */
2023 		if ((level & WRITE_CACHING) == 0) {
2024 			*rop = level;
2025 			status = smb_oplock_req_shared(ofile, rop, B_TRUE);
2026 			goto out;
2027 		}
2028 
2029 		/*
2030 		 * Note that because this oplock is being set up as part of
2031 		 * an acknowledgement of an exclusive oplock break,
2032 		 * Open.Stream.Oplock.ExclusiveOpen was set
2033 		 * at the time of the original oplock request;
2034 		 * it contains Open.
2035 		 *	* Set Open.Stream.Oplock.State to
2036 		 *	  (RequestedOplockLevel|EXCLUSIVE).
2037 		 *	* This operation MUST be made cancelable...
2038 		 *	* This operation waits until the oplock is broken or
2039 		 *	  canceled, as specified in section 2.1.5.17.3.
2040 		 *
2041 		 * Implementation notes:
2042 		 *
2043 		 * This can only be a break from RWH to RW.
2044 		 * The assignment of ol_state below means there will be
2045 		 * no BREAK_TO_... bits set, and therefore no need for
2046 		 * "waits until the oplock is broken" as described in
2047 		 * the spec for this bit of code.  Therefore, this will
2048 		 * return SUCCESS instead of OPLOCK_BREAK_IN_PROGRESS.
2049 		 */
2050 		node->n_oplock.ol_state = level | EXCLUSIVE;
2051 		status = NT_STATUS_SUCCESS;
2052 		break;	/* case (READ_CACHING|WRITE_CACHING|...) */
2053 
2054 	default:
2055 		/* The operation MUST be failed with Status */
2056 		status = NT_STATUS_INVALID_OPLOCK_PROTOCOL;
2057 		break;
2058 
2059 	} /* Switch (oplock.state) */
2060 
2061 out:
2062 	if (status == NT_STATUS_INVALID_OPLOCK_PROTOCOL)
2063 		*rop = LEVEL_NONE;
2064 
2065 	if (status == NT_STATUS_SUCCESS &&
2066 	    type == LEVEL_GRANULAR &&
2067 	    *rop != LEVEL_NONE) {
2068 		*rop |= LEVEL_GRANULAR;
2069 		/* As above, leased oplock may have moved. */
2070 #ifndef	TESTJIG
2071 		if (ofile->f_lease != NULL)
2072 			ofile->f_lease->ls_oplock_ofile = ofile;
2073 #endif
2074 	}
2075 
2076 	/*
2077 	 * The spec. describes waiting for a break here,
2078 	 * but we let the caller do that (when needed) if
2079 	 * status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS
2080 	 */
2081 	mutex_exit(&node->n_oplock.ol_mutex);
2082 	smb_llist_exit(&node->n_ofile_list);
2083 
2084 	return (status);
2085 }
2086 
2087 /*
2088  * 2.1.4.12 Algorithm to Check for an Oplock Break
2089  *
2090  * The inputs for this algorithm are:
2091  *
2092  * Open: The Open being used in the request calling this algorithm.
2093  *
2094  * Oplock: The Oplock being checked.
2095  *
2096  * Operation: A code describing the operation being processed.
2097  *
2098  * OpParams: Parameters associated with the Operation code that are
2099  *   passed in from the calling request. For example, if Operation is
2100  *   OPEN, as specified in section 2.1.5.1, then OpParams will have the
2101  *   members DesiredAccess and CreateDisposition. Each of these is a
2102  *   parameter to the open request as specified in section 2.1.5.1.
2103  *   This parameter could be empty, depending on the Operation code.
2104  *
2105  * Flags: An optional parameter. If unspecified it is considered to
2106  *   contain 0. Valid nonzero values are:
2107  *	PARENT_OBJECT
2108  *
2109  * The algorithm uses the following local variables:
2110  *
2111  * Boolean values (initialized to FALSE):
2112  *   BreakToTwo, BreakToNone, NeedToWait
2113  *
2114  * BreakCacheLevel – MAY contain 0 or a combination of one or more of
2115  *   READ_CACHING, WRITE_CACHING, or HANDLE_CACHING, as specified in
2116  *   section 2.1.1.10. Initialized to 0.
2117  *   Note that there are only four legal nonzero combinations of flags
2118  *   for BreakCacheLevel:
2119  *	(READ_CACHING|WRITE_CACHING|HANDLE_CACHING)
2120  *	(READ_CACHING|WRITE_CACHING)
2121  *	WRITE_CACHING
2122  *	HANDLE_CACHING
2123  *
2124  * Algorithm: (all)
2125  * If Oplock is not empty and Oplock.State is not NO_OPLOCK:
2126  *	If Flags contains PARENT_OBJECT:
2127  *		If Operation is OPEN, CLOSE, FLUSH_DATA,
2128  *		  FS_CONTROL(set_encryption) or
2129  *		  SET_INFORMATION(Basic, Allocation, EoF,
2130  *		  Rename, Link, Shortname, VDL):
2131  *			Set BreakCacheLevel to (READ_CACHING|WRITE_CACHING).
2132  *		EndIf
2133  *	Else // Normal operation (not PARENT_OBJECT)
2134  *		Switch (Operation):
2135  *		Case OPEN, CLOSE, ...
2136  *		EndSwitch
2137  *	EndIf // not parent
2138  *	// Common section for all above
2139  *	If BreakToTwo is TRUE:
2140  *		...
2141  *	Else If BreakToNone
2142  *		...
2143  *	EndIf
2144  *	...
2145  * EndIf
2146  *
2147  * This implementation uses separate functions for each of:
2148  *	if (flags & PARENT)... else
2149  *	switch (Operation)...
2150  */
2151 
2152 
2153 /*
2154  * If Flags contains PARENT_OBJECT:
2155  * ...
2156  * Note that this function is unusual in that the node arg is
2157  * the PARENT directory node, and ofile is NOT on the ofile list
2158  * of that directory but one of the nodes under it.
2159  *
2160  * Note that until we implement directory leases, this is a no-op.
2161  */
2162 uint32_t
2163 smb_oplock_break_PARENT(smb_node_t *node, smb_ofile_t *ofile)
2164 {
2165 	uint32_t BreakCacheLevel;
2166 
2167 	/*
2168 	 * If Operation is OPEN, CLOSE, FLUSH_DATA,
2169 	 *  FS_CONTROL(set_encryption) or
2170 	 * SET_INFORMATION(Basic, Allocation, EoF,
2171 	 * Rename, Link, Shortname, VDL):
2172 	 *	 Set BreakCacheLevel to (READ_CACHING|WRITE_CACHING).
2173 	 * EndIf
2174 	 */
2175 	BreakCacheLevel = PARENT_OBJECT |
2176 	    (READ_CACHING|WRITE_CACHING);
2177 
2178 	return (smb_oplock_break_cmn(node, ofile, BreakCacheLevel));
2179 }
2180 
2181 /*
2182  * Helper for the cases where section 2.1.5.1 says:
2183  *
2184  * If Open.Stream.Oplock is not empty and Open.Stream.Oplock.State
2185  * contains BATCH_OPLOCK, the object store MUST check for an oplock
2186  * break according to the algorithm in section 2.1.4.12,
2187  * with input values as follows:
2188  *	Open equal to this operation's Open
2189  *	Oplock equal to Open.Stream.Oplock
2190  *	Operation equal to "OPEN"
2191  *	OpParams containing two members:
2192  *      (DesiredAccess, CreateDisposition)
2193  *
2194  * So basically, just call smb_oplock_break_OPEN(), but
2195  * only if there's a batch oplock.
2196  */
2197 uint32_t
2198 smb_oplock_break_BATCH(smb_node_t *node, smb_ofile_t *ofile,
2199     uint32_t DesiredAccess, uint32_t CreateDisposition)
2200 {
2201 	if ((node->n_oplock.ol_state & BATCH_OPLOCK) == 0)
2202 		return (0);
2203 
2204 	return (smb_oplock_break_OPEN(node, ofile,
2205 	    DesiredAccess, CreateDisposition));
2206 }
2207 
2208 /*
2209  * Case OPEN, as specified in section 2.1.5.1:
2210  *
2211  * Note: smb_ofile_open constructs a partially complete smb_ofile_t
2212  * for this call, which can be considerd a "proposed open".  This
2213  * open may or may not turn into a usable open depending on what
2214  * happens in the remainder of the ofile_open code path.
2215  */
2216 uint32_t
2217 smb_oplock_break_OPEN(smb_node_t *node, smb_ofile_t *ofile,
2218     uint32_t DesiredAccess, uint32_t CreateDisposition)
2219 {
2220 	uint32_t BreakCacheLevel = 0;
2221 	/* BreakToTwo, BreakToNone, NeedToWait */
2222 
2223 	/*
2224 	 * If OpParams.DesiredAccess contains no flags other than
2225 	 * FILE_READ_ATTRIBUTES, FILE_WRITE_ATTRIBUTES, or SYNCHRONIZE,
2226 	 *   the algorithm returns at this point.
2227 	 * EndIf
2228 	 */
2229 	if ((DesiredAccess & ~(FILE_READ_ATTRIBUTES |
2230 	    FILE_WRITE_ATTRIBUTES | SYNCHRONIZE | READ_CONTROL)) == 0)
2231 		return (0);
2232 
2233 	/*
2234 	 * If OpParams.CreateDisposition is FILE_SUPERSEDE,
2235 	 * FILE_OVERWRITE, or FILE_OVERWRITE_IF:
2236 	 *	Set BreakToNone to TRUE, set BreakCacheLevel to
2237 	 *	   (READ_CACHING|WRITE_CACHING).
2238 	 * Else
2239 	 *	Set BreakToTwo to TRUE,
2240 	 *	set BreakCacheLevel to WRITE_CACHING.
2241 	 * EndIf
2242 	 */
2243 	if (CreateDisposition == FILE_SUPERSEDE ||
2244 	    CreateDisposition == FILE_OVERWRITE ||
2245 	    CreateDisposition == FILE_OVERWRITE_IF) {
2246 		BreakCacheLevel = BREAK_TO_NONE |
2247 		    (READ_CACHING|WRITE_CACHING);
2248 	} else {
2249 		/*
2250 		 * CreateDispositons: OPEN, OPEN_IF
2251 		 */
2252 		BreakCacheLevel = BREAK_TO_TWO |
2253 		    WRITE_CACHING;
2254 	}
2255 
2256 	return (smb_oplock_break_cmn(node, ofile, BreakCacheLevel));
2257 }
2258 
2259 /*
2260  * Case OPEN_BREAK_H, as specified in section 2.1.5.1:
2261  *	Set BreakCacheLevel to HANDLE_CACHING.
2262  * EndCase
2263  */
2264 uint32_t
2265 smb_oplock_break_HANDLE(smb_node_t *node, smb_ofile_t *ofile)
2266 {
2267 	uint32_t BreakCacheLevel = HANDLE_CACHING;
2268 
2269 	return (smb_oplock_break_cmn(node, ofile, BreakCacheLevel));
2270 }
2271 
2272 /*
2273  * Case CLOSE, as specified in section 2.1.5.4:
2274  *
2275  * The MS-FSA spec. describes sending oplock break indications
2276  * (smb_oplock_ind_break ... NT_STATUS_OPLOCK_HANDLE_CLOSED)
2277  * for several cases where the ofile we're closing has some
2278  * oplock grants.  We modify these slightly and use them to
2279  * clear out the SMB-level oplock state.  We could probably
2280  * just skip most of these, as the caller knows this handle is
2281  * closing and could just discard the SMB-level oplock state.
2282  * For now, keeping this close to what the spec says.
2283  */
2284 void
2285 smb_oplock_break_CLOSE(smb_node_t *node, smb_ofile_t *ofile)
2286 {
2287 	smb_ofile_t *o;
2288 
2289 	ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
2290 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
2291 
2292 	if (ofile->f_oplock.og_closing)
2293 		return;
2294 	ofile->f_oplock.og_closing = B_TRUE;
2295 
2296 	/*
2297 	 * If Oplock.IIOplocks is not empty:
2298 	 *   For each Open ThisOpen in Oplock.IIOplocks:
2299 	 *	If ThisOpen == Open:
2300 	 *		Remove ThisOpen from Oplock.IIOplocks.
2301 	 *		Notify the server of an oplock break according to
2302 	 *		  the algorithm in section 2.1.5.17.3, setting the
2303 	 *		  algorithm's parameters as follows:
2304 	 *			BreakingOplockOpen = ThisOpen.
2305 	 *			NewOplockLevel = LEVEL_NONE.
2306 	 *			AcknowledgeRequired = FALSE.
2307 	 *			OplockCompletionStatus = STATUS_SUCCESS.
2308 	 *		(The operation does not end at this point;
2309 	 *		 this call to 2.1.5.17.3 completes some
2310 	 *		 earlier call to 2.1.5.17.2.)
2311 	 *	EndIf
2312 	 *   EndFor
2313 	 *   Recompute Oplock.State according to the algorithm in
2314 	 *     section 2.1.4.13, passing Oplock as the ThisOplock parameter.
2315 	 * EndIf
2316 	 */
2317 	if (node->n_oplock.cnt_II > 0) {
2318 		o = ofile; /* No need for list walk */
2319 		if (o->f_oplock.onlist_II) {
2320 			o->f_oplock.onlist_II = B_FALSE;
2321 			node->n_oplock.cnt_II--;
2322 			ASSERT(node->n_oplock.cnt_II >= 0);
2323 			/*
2324 			 * The spec. says to do:
2325 			 * smb_oplock_ind_break(o,
2326 			 *    LEVEL_NONE, B_FALSE,
2327 			 *    NT_STATUS_SUCCESS);
2328 			 *
2329 			 * We'll use STATUS_OPLOCK_HANDLE_CLOSED
2330 			 * like all the other ind_break calls in
2331 			 * this function, so the SMB-level will
2332 			 * just clear out its oplock state.
2333 			 */
2334 			smb_oplock_ind_break(o,
2335 			    LEVEL_NONE, B_FALSE,
2336 			    NT_STATUS_OPLOCK_HANDLE_CLOSED);
2337 		}
2338 		RecomputeOplockState(node);
2339 	}
2340 
2341 	/*
2342 	 * If Oplock.ROplocks is not empty:
2343 	 *   For each Open ThisOpen in Oplock.ROplocks:
2344 	 *	If ThisOpen == Open:
2345 	 *		Remove ThisOpen from Oplock.ROplocks.
2346 	 *		Notify the server of an oplock break according to
2347 	 *		  the algorithm in section 2.1.5.17.3, setting the
2348 	 *		  algorithm's parameters as follows:
2349 	 *			BreakingOplockOpen = ThisOpen.
2350 	 *			NewOplockLevel = LEVEL_NONE.
2351 	 *			AcknowledgeRequired = FALSE.
2352 	 *			OplockCompletionStatus =
2353 	 *			  STATUS_OPLOCK_HANDLE_CLOSED.
2354 	 *		(The operation does not end at this point;
2355 	 *		 this call to 2.1.5.17.3 completes some
2356 	 *		 earlier call to 2.1.5.17.2.)
2357 	 *	EndIf
2358 	 *   EndFor
2359 	 *   Recompute Oplock.State according to the algorithm in
2360 	 *     section 2.1.4.13, passing Oplock as the ThisOplock parameter.
2361 	 * EndIf
2362 	 */
2363 	if (node->n_oplock.cnt_R > 0) {
2364 		o = ofile; /* No need for list walk */
2365 		if (o->f_oplock.onlist_R) {
2366 			o->f_oplock.onlist_R = B_FALSE;
2367 			node->n_oplock.cnt_R--;
2368 			ASSERT(node->n_oplock.cnt_R >= 0);
2369 
2370 			smb_oplock_ind_break(o,
2371 			    LEVEL_NONE, B_FALSE,
2372 			    NT_STATUS_OPLOCK_HANDLE_CLOSED);
2373 		}
2374 		RecomputeOplockState(node);
2375 	}
2376 
2377 	/*
2378 	 * If Oplock.RHOplocks is not empty:
2379 	 *   For each Open ThisOpen in Oplock.RHOplocks:
2380 	 *	If ThisOpen == Open:
2381 	 *		Remove ThisOpen from Oplock.RHOplocks.
2382 	 *		Notify the server of an oplock break according to
2383 	 *		  the algorithm in section 2.1.5.17.3, setting the
2384 	 *		  algorithm's parameters as follows:
2385 	 *			BreakingOplockOpen = ThisOpen.
2386 	 *			NewOplockLevel = LEVEL_NONE.
2387 	 *			AcknowledgeRequired = FALSE.
2388 	 *			OplockCompletionStatus =
2389 	 *			   STATUS_OPLOCK_HANDLE_CLOSED.
2390 	 *		(The operation does not end at this point;
2391 	 *		 this call to 2.1.5.17.3 completes some
2392 	 *		 earlier call to 2.1.5.17.2.)
2393 	 *	EndIf
2394 	 *   EndFor
2395 	 *   Recompute Oplock.State according to the algorithm in
2396 	 *     section 2.1.4.13, passing Oplock as the ThisOplock parameter.
2397 	 * EndIf
2398 	 */
2399 	if (node->n_oplock.cnt_RH > 0) {
2400 		o = ofile; /* No need for list walk */
2401 		if (o->f_oplock.onlist_RH) {
2402 			o->f_oplock.onlist_RH = B_FALSE;
2403 			node->n_oplock.cnt_RH--;
2404 			ASSERT(node->n_oplock.cnt_RH >= 0);
2405 
2406 			smb_oplock_ind_break(o,
2407 			    LEVEL_NONE, B_FALSE,
2408 			    NT_STATUS_OPLOCK_HANDLE_CLOSED);
2409 		}
2410 		RecomputeOplockState(node);
2411 	}
2412 
2413 	/*
2414 	 * If Oplock.RHBreakQueue is not empty:
2415 	 *	For each RHOpContext ThisContext in Oplock.RHBreakQueue:
2416 	 *		If ThisContext.Open == Open:
2417 	 *			Remove ThisContext from Oplock.RHBreakQueue.
2418 	 *		EndIf
2419 	 *	EndFor
2420 	 *	Recompute Oplock.State according to the algorithm in
2421 	 *	  section 2.1.4.13, passing Oplock as the ThisOplock parameter.
2422 	 *	For each Open WaitingOpen on Oplock.WaitList:
2423 	 *		If Oplock.RHBreakQueue is empty:
2424 	 *		(or) If the value of every
2425 	 *		RHOpContext.Open.TargetOplockKey
2426 	 *		on Oplock.RHBreakQueue is equal to
2427 	 *		WaitingOpen .TargetOplockKey:
2428 	 *			Indicate that the op. assoc. with
2429 	 *			WaitingOpen can continue according to
2430 	 *			the algorithm in section 2.1.4.12.1,
2431 	 *			setting OpenToRelease = WaitingOpen.
2432 	 *			Remove WaitingOpen from Oplock.WaitList.
2433 	 *		EndIf
2434 	 *	EndFor
2435 	 * EndIf
2436 	 */
2437 	if (node->n_oplock.cnt_RHBQ > 0) {
2438 		o = ofile; /* No need for list walk */
2439 		if (o->f_oplock.onlist_RHBQ) {
2440 			o->f_oplock.onlist_RHBQ = B_FALSE;
2441 			node->n_oplock.cnt_RHBQ--;
2442 			ASSERT(node->n_oplock.cnt_RHBQ >= 0);
2443 		}
2444 		RecomputeOplockState(node);
2445 		/*
2446 		 * We don't keep a WaitingOpen list, so just
2447 		 * wake them all and let them look at the
2448 		 * updated Oplock.RHBreakQueue
2449 		 */
2450 		cv_broadcast(&node->n_oplock.WaitingOpenCV);
2451 	}
2452 
2453 	/*
2454 	 * If Open equals Open.Oplock.ExclusiveOpen
2455 	 *	If Oplock.State contains none of (BREAK_ANY):
2456 	 *		Notify the server of an oplock break according to
2457 	 *		  the algorithm in section 2.1.5.17.3, setting the
2458 	 *		  algorithm's parameters as follows:
2459 	 *			BreakingOplockOpen = Oplock.ExclusiveOpen.
2460 	 *			NewOplockLevel = LEVEL_NONE.
2461 	 *			AcknowledgeRequired = FALSE.
2462 	 *			OplockCompletionStatus equal to:
2463 	 *				STATUS_OPLOCK_HANDLE_CLOSED if
2464 	 *				  Oplock.State contains any of
2465 	 *				  READ_CACHING, WRITE_CACHING, or
2466 	 *				  HANDLE_CACHING.
2467 	 *				STATUS_SUCCESS otherwise.
2468 	 *		(The operation does not end at this point;
2469 	 *		 this call to 2.1.5.17.3 completes some
2470 	 *		 earlier call to 2.1.5.17.1.)
2471 	 *	EndIf
2472 	 *	Set Oplock.ExclusiveOpen to NULL.
2473 	 *	Set Oplock.State to NO_OPLOCK.
2474 	 *	For each Open WaitingOpen on Oplock.WaitList:
2475 	 *		Indicate that the operation associated with WaitingOpen
2476 	 *		  can continue according to the algorithm in section
2477 	 *		  2.1.4.12.1, setting OpenToRelease = WaitingOpen.
2478 	 *		Remove WaitingOpen from Oplock.WaitList.
2479 	 *	EndFor
2480 	 * EndIf
2481 	 *
2482 	 * Modify this slightly from what the spec. says and only
2483 	 * up-call the break with status STATUS_OPLOCK_HANDLE_CLOSED.
2484 	 * The STATUS_SUCCESS case would do nothing at the SMB level,
2485 	 * so we'll just skip that part.
2486 	 */
2487 	if (ofile == node->n_oplock.excl_open) {
2488 		uint32_t level = node->n_oplock.ol_state & CACHE_RWH;
2489 		if (level != 0 &&
2490 		    (node->n_oplock.ol_state & BREAK_ANY) == 0) {
2491 			smb_oplock_ind_break(ofile,
2492 			    LEVEL_NONE, B_FALSE,
2493 			    NT_STATUS_OPLOCK_HANDLE_CLOSED);
2494 		}
2495 		node->n_oplock.excl_open = NULL;
2496 		node->n_oplock.ol_state = NO_OPLOCK;
2497 		cv_broadcast(&node->n_oplock.WaitingOpenCV);
2498 	}
2499 
2500 	/*
2501 	 * The CLOSE sub-case of 2.1.5.4 (separate function here)
2502 	 * happens to always leave BreakCacheLevel=0 (see 2.1.5.4)
2503 	 * so there's never a need to call smb_oplock_break_cmn()
2504 	 * in this function.  If that changed and we were to have
2505 	 * BreakCacheLevel != 0 here, then we'd need to call:
2506 	 * smb_oplock_break_cmn(node, ofile, BreakCacheLevel);
2507 	 */
2508 
2509 	if ((node->n_oplock.ol_state & BREAK_ANY) == 0)
2510 		cv_broadcast(&node->n_oplock.WaitingOpenCV);
2511 
2512 }
2513 
2514 /*
2515  * Case READ, as specified in section 2.1.5.2:
2516  *	Set BreakToTwo to TRUE
2517  *	Set BreakCacheLevel to WRITE_CACHING.
2518  * EndCase
2519  */
2520 uint32_t
2521 smb_oplock_break_READ(smb_node_t *node, smb_ofile_t *ofile)
2522 {
2523 	uint32_t BreakCacheLevel = BREAK_TO_TWO | WRITE_CACHING;
2524 
2525 	return (smb_oplock_break_cmn(node, ofile, BreakCacheLevel));
2526 }
2527 
2528 /*
2529  * Case FLUSH_DATA, as specified in section 2.1.5.6:
2530  *	Set BreakToTwo to TRUE
2531  *	Set BreakCacheLevel to WRITE_CACHING.
2532  * EndCase
2533  * Callers just use smb_oplock_break_READ() -- same thing.
2534  */
2535 
2536 /*
2537  * Case LOCK_CONTROL, as specified in section 2.1.5.7:
2538  * Note: Spec does fall-through to WRITE here.
2539  *
2540  * Case WRITE, as specified in section 2.1.5.3:
2541  *	Set BreakToNone to TRUE
2542  *	Set BreakCacheLevel to (READ_CACHING|WRITE_CACHING).
2543  * EndCase
2544  */
2545 uint32_t
2546 smb_oplock_break_WRITE(smb_node_t *node, smb_ofile_t *ofile)
2547 {
2548 	uint32_t BreakCacheLevel = BREAK_TO_NONE |
2549 	    (READ_CACHING|WRITE_CACHING);
2550 
2551 	return (smb_oplock_break_cmn(node, ofile, BreakCacheLevel));
2552 }
2553 
2554 /*
2555  * Case SET_INFORMATION, as specified in section 2.1.5.14:
2556  * Switch (OpParams.FileInformationClass):
2557  *	Case FileEndOfFileInformation:
2558  *	Case FileAllocationInformation:
2559  *		Set BreakToNone to TRUE
2560  *		Set BreakCacheLevel to (READ_CACHING|WRITE_CACHING).
2561  *	EndCase
2562  *	Case FileRenameInformation:
2563  *	Case FileLinkInformation:
2564  *	Case FileShortNameInformation:
2565  *		Set BreakCacheLevel to HANDLE_CACHING.
2566  *		If Oplock.State contains BATCH_OPLOCK,
2567  *		  set BreakToNone to TRUE.
2568  *	EndCase
2569  *	Case FileDispositionInformation:
2570  *		If OpParams.DeleteFile is TRUE,
2571  *		Set BreakCacheLevel to HANDLE_CACHING.
2572  *	EndCase
2573  * EndSwitch
2574  */
2575 uint32_t
2576 smb_oplock_break_SETINFO(smb_node_t *node, smb_ofile_t *ofile,
2577     uint32_t InfoClass)
2578 {
2579 	uint32_t BreakCacheLevel = 0;
2580 
2581 	switch (InfoClass) {
2582 	case FileEndOfFileInformation:
2583 	case FileAllocationInformation:
2584 		BreakCacheLevel = BREAK_TO_NONE |
2585 		    (READ_CACHING|WRITE_CACHING);
2586 		break;
2587 
2588 	case FileRenameInformation:
2589 	case FileLinkInformation:
2590 	case FileShortNameInformation:
2591 		BreakCacheLevel = HANDLE_CACHING;
2592 		if (node->n_oplock.ol_state & BATCH_OPLOCK) {
2593 			BreakCacheLevel |= BREAK_TO_NONE;
2594 		}
2595 		break;
2596 	case FileDispositionInformation:
2597 		/* Only called if (OpParams.DeleteFile is TRUE) */
2598 		BreakCacheLevel = HANDLE_CACHING;
2599 		break;
2600 
2601 	}
2602 
2603 	return (smb_oplock_break_cmn(node, ofile, BreakCacheLevel));
2604 }
2605 
2606 /*
2607  * This one is not from the spec.  It appears that Windows will
2608  * open a handle for an SMB1 delete call (at least internally).
2609  * We don't open a handle for delete, but do want to break as if
2610  * we had done, so this breaks like a combination of:
2611  *	break_BATCH(... DELETE, FILE_OPEN_IF)
2612  *	break_HANDLE(...)
2613  */
2614 uint32_t
2615 smb_oplock_break_DELETE(smb_node_t *node, smb_ofile_t *ofile)
2616 {
2617 	uint32_t BreakCacheLevel = HANDLE_CACHING;
2618 
2619 	if ((node->n_oplock.ol_state & BATCH_OPLOCK) != 0)
2620 		BreakCacheLevel |= BREAK_TO_TWO;
2621 
2622 	return (smb_oplock_break_cmn(node, ofile, BreakCacheLevel));
2623 }
2624 
2625 /*
2626  * Case FS_CONTROL, as specified in section 2.1.5.9:
2627  *	If OpParams.ControlCode is FSCTL_SET_ZERO_DATA:
2628  *		Set BreakToNone to TRUE.
2629  *		Set BreakCacheLevel to (READ_CACHING|WRITE_CACHING).
2630  *	EndIf
2631  * EndCase
2632  * Callers just use smb_oplock_break_WRITE() -- same thing.
2633  */
2634 
2635 /*
2636  * Common section for all cases above
2637  * Note: When called via FEM: ofile == NULL
2638  */
2639 static uint32_t
2640 smb_oplock_break_cmn(smb_node_t *node,
2641     smb_ofile_t *ofile, uint32_t BreakCacheLevel)
2642 {
2643 	smb_oplock_t *nol = &node->n_oplock;
2644 	uint32_t CmpFlags, status;
2645 	boolean_t BreakToTwo, BreakToNone, NeedToWait;
2646 	smb_ofile_t *o = NULL;
2647 
2648 	CmpFlags = (BreakCacheLevel & PARENT_OBJECT);
2649 	BreakToTwo = (BreakCacheLevel & BREAK_TO_TWO) != 0;
2650 	BreakToNone = (BreakCacheLevel & BREAK_TO_NONE) != 0;
2651 	BreakCacheLevel &= (READ_CACHING | WRITE_CACHING | HANDLE_CACHING);
2652 	NeedToWait = B_FALSE;
2653 	status = NT_STATUS_SUCCESS;
2654 
2655 	smb_llist_enter(&node->n_ofile_list, RW_READER);
2656 	mutex_enter(&node->n_oplock.ol_mutex);
2657 
2658 	if (node->n_oplock.ol_state == 0 ||
2659 	    node->n_oplock.ol_state == NO_OPLOCK)
2660 		goto out;
2661 
2662 	if (BreakToTwo) {
2663 		/*
2664 		 * If (Oplock.State != LEVEL_TWO_OPLOCK) and
2665 		 *    ((Oplock.ExclusiveOpen is empty) or
2666 		 *     (Oplock.ExclusiveOpen.TargetOplockKey !=
2667 		 *      Open.TargetOplockKey)):
2668 		 */
2669 		if ((nol->ol_state != LEVEL_TWO_OPLOCK) &&
2670 		    (((o = nol->excl_open) == NULL) ||
2671 		    !CompareOplockKeys(ofile, o, CmpFlags))) {
2672 
2673 			/*
2674 			 * If (Oplock.State contains EXCLUSIVE) and
2675 			 *  (Oplock.State contains none of READ_CACHING,
2676 			 *   WRITE_CACHING, or HANDLE_CACHING):
2677 			 */
2678 			if ((nol->ol_state & EXCLUSIVE) != 0 &&
2679 			    (nol->ol_state & CACHE_RWH) == 0) {
2680 				/*
2681 				 * If Oplock.State contains none of:
2682 				 *	BREAK_TO_NONE,
2683 				 *	BREAK_TO_TWO,
2684 				 *	BREAK_TO_TWO_TO_NONE,
2685 				 *	BREAK_TO_READ_CACHING,
2686 				 *	BREAK_TO_WRITE_CACHING,
2687 				 *	BREAK_TO_HANDLE_CACHING,
2688 				 *	BREAK_TO_NO_CACHING:
2689 				 */
2690 				if ((nol->ol_state & BREAK_ANY) == 0) {
2691 
2692 					/*
2693 					 * Oplock.State MUST contain either
2694 					 * LEVEL_ONE_OPLOCK or BATCH_OPLOCK.
2695 					 * Set BREAK_TO_TWO in Oplock.State.
2696 					 */
2697 					ASSERT((nol->ol_state &
2698 					    (LEVEL_ONE | LEVEL_BATCH)) != 0);
2699 					nol->ol_state |= BREAK_TO_TWO;
2700 
2701 					/*
2702 					 * Notify the server of an oplock break
2703 					 * according to the algorithm in section
2704 					 * 2.1.5.17.3, setting the algorithm's
2705 					 * parameters as follows:
2706 					 *	BreakingOplockOpen =
2707 					 *	  Oplock.ExclusiveOpen.
2708 					 *	NewOplockLevel = LEVEL_TWO.
2709 					 *	AcknowledgeRequired = TRUE.
2710 					 *	Compl_Status = STATUS_SUCCESS.
2711 					 * (The operation does not end at this
2712 					 * point; this call to 2.1.5.17.3
2713 					 * completes some earlier call to
2714 					 * 2.1.5.17.1.)
2715 					 */
2716 					smb_oplock_ind_break(o,
2717 					    LEVEL_TWO, B_TRUE,
2718 					    NT_STATUS_SUCCESS);
2719 				}
2720 
2721 				/*
2722 				 * The operation that called this algorithm
2723 				 *  MUST be made cancelable by ...
2724 				 * The operation that called this algorithm
2725 				 *  waits until the oplock break is
2726 				 *  acknowledged, as specified in section
2727 				 *  2.1.5.18, or the operation is canceled.
2728 				 */
2729 				status = NT_STATUS_OPLOCK_BREAK_IN_PROGRESS;
2730 				/* Caller does smb_oplock_wait_break() */
2731 			}
2732 		}
2733 	} else if (BreakToNone) {
2734 		/*
2735 		 * If (Oplock.State == LEVEL_TWO_OPLOCK) or
2736 		 *  (Oplock.ExclusiveOpen is empty) or
2737 		 *  (Oplock.ExclusiveOpen.TargetOplockKey !=
2738 		 *   Open.TargetOplockKey):
2739 		 */
2740 		if (nol->ol_state == LEVEL_TWO_OPLOCK ||
2741 		    (((o = nol->excl_open) == NULL) ||
2742 		    !CompareOplockKeys(ofile, o, CmpFlags))) {
2743 
2744 			/*
2745 			 * If (Oplock.State != NO_OPLOCK) and
2746 			 * (Oplock.State contains neither
2747 			 *  WRITE_CACHING nor HANDLE_CACHING):
2748 			 */
2749 			if (nol->ol_state != NO_OPLOCK &&
2750 			    (nol->ol_state &
2751 			    (WRITE_CACHING | HANDLE_CACHING)) == 0) {
2752 
2753 				/*
2754 				 * If Oplock.State contains none of:
2755 				 *	LEVEL_TWO_OPLOCK,
2756 				 *	BREAK_TO_NONE,
2757 				 *	BREAK_TO_TWO,
2758 				 *	BREAK_TO_TWO_TO_NONE,
2759 				 *	BREAK_TO_READ_CACHING,
2760 				 *	BREAK_TO_WRITE_CACHING,
2761 				 *	BREAK_TO_HANDLE_CACHING, or
2762 				 *	BREAK_TO_NO_CACHING:
2763 				 */
2764 				if ((nol->ol_state &
2765 				    (LEVEL_TWO_OPLOCK | BREAK_ANY)) == 0) {
2766 
2767 					/*
2768 					 * There could be a READ_CACHING-only
2769 					 * oplock here. Those are broken later.
2770 					 *
2771 					 * If Oplock.State contains READ_CACHING
2772 					 *  go to the LeaveBreakToNone label.
2773 					 * Set BREAK_TO_NONE in Oplock.State.
2774 					 */
2775 					if ((nol->ol_state & READ_CACHING) != 0)
2776 						goto LeaveBreakToNone;
2777 					nol->ol_state |= BREAK_TO_NONE;
2778 
2779 					/*
2780 					 * Notify the server of an oplock break
2781 					 * according to the algorithm in section
2782 					 * 2.1.5.17.3, setting the algorithm's
2783 					 * parameters as follows:
2784 					 *	BreakingOplockOpen =
2785 					 *	  Oplock.ExclusiveOpen.
2786 					 *	NewOplockLevel = LEVEL_NONE.
2787 					 *	AcknowledgeRequired = TRUE.
2788 					 *	Commpl_Status = STATUS_SUCCESS.
2789 					 * (The operation does not end at this
2790 					 * point; this call to 2.1.5.17.3
2791 					 * completes some earlier call to
2792 					 * 2.1.5.17.1.)
2793 					 */
2794 					smb_oplock_ind_break(o,
2795 					    LEVEL_NONE, B_TRUE,
2796 					    NT_STATUS_SUCCESS);
2797 				}
2798 
2799 				/*
2800 				 * Else If Oplock.State equals LEVEL_TWO_OPLOCK
2801 				 *  or (LEVEL_TWO_OPLOCK|READ_CACHING):
2802 				 */
2803 				else if (nol->ol_state == LEVEL_TWO ||
2804 				    nol->ol_state == (LEVEL_TWO|READ_CACHING)) {
2805 
2806 					/*
2807 					 * For each Open O in Oplock.IIOplocks:
2808 					 *   Remove O from Oplock.IIOplocks.
2809 					 *   Notify the server of an oplock
2810 					 *    break according to the algorithm
2811 					 *    in section 2.1.5.17.3, setting the
2812 					 *    algorithm's parameters as follows:
2813 					 *	BreakingOplockOpen = ThisOpen.
2814 					 *	NewOplockLevel = LEVEL_NONE.
2815 					 *	AcknowledgeRequired = FALSE.
2816 					 *	Compl_Status = STATUS_SUCCESS.
2817 					 *    (The operation does not end at
2818 					 *    this point; this call to
2819 					 *    2.1.5.17.3 completes some
2820 					 *    earlier call to 2.1.5.17.2.)
2821 					 * EndFor
2822 					 */
2823 					FOREACH_NODE_OFILE(node, o) {
2824 						if (o->f_oplock.onlist_II == 0)
2825 							continue;
2826 						o->f_oplock.onlist_II = B_FALSE;
2827 						nol->cnt_II--;
2828 						ASSERT(nol->cnt_II >= 0);
2829 
2830 						smb_oplock_ind_break(o,
2831 						    LEVEL_NONE, B_FALSE,
2832 						    NT_STATUS_SUCCESS);
2833 					}
2834 					/*
2835 					 * If Oplock.State equals
2836 					 *  (LEVEL_TWO_OPLOCK|READ_CACHING):
2837 					 *	Set Oplock.State = READ_CACHING.
2838 					 * Else
2839 					 *	Set Oplock.State = NO_OPLOCK.
2840 					 * EndIf
2841 					 * Go to the LeaveBreakToNone label.
2842 					 */
2843 					if (nol->ol_state ==
2844 					    (LEVEL_TWO_OPLOCK | READ_CACHING)) {
2845 						nol->ol_state = READ_CACHING;
2846 					} else {
2847 						nol->ol_state = NO_OPLOCK;
2848 					}
2849 					goto LeaveBreakToNone;
2850 				}
2851 
2852 				/*
2853 				 * Else If Oplock.State contains BREAK_TO_TWO:
2854 				 *	Clear BREAK_TO_TWO from Oplock.State.
2855 				 *	Set BREAK_TO_TWO_TO_NONE in Oplock.State
2856 				 * EndIf
2857 				 */
2858 				else if (nol->ol_state & BREAK_TO_TWO) {
2859 					nol->ol_state &= ~BREAK_TO_TWO;
2860 					nol->ol_state |= BREAK_TO_TWO_TO_NONE;
2861 				}
2862 
2863 				/*
2864 				 * If Oplock.ExclusiveOpen is not empty,
2865 				 *  and Oplock.Excl_Open.TargetOplockKey
2866 				 *  equals Open.TargetOplockKey,
2867 				 *	 go to the LeaveBreakToNone label.
2868 				 */
2869 				if (o != NULL &&
2870 				    CompareOplockKeys(ofile, o, CmpFlags))
2871 					goto LeaveBreakToNone;
2872 
2873 				/*
2874 				 * The operation that called this algorithm
2875 				 *  MUST be made cancelable by ...
2876 				 * The operation that called this algorithm
2877 				 * waits until the opl. break is acknowledged,
2878 				 * as specified in section 2.1.5.18, or the
2879 				 * operation is canceled.
2880 				 */
2881 				status = NT_STATUS_OPLOCK_BREAK_IN_PROGRESS;
2882 				/* Caller does smb_oplock_wait_break() */
2883 			}
2884 		}
2885 	}
2886 
2887 LeaveBreakToNone:
2888 
2889 	/*
2890 	 * if (BreakCacheLevel != 0) and		(pp 37)
2891 	 * If Oplock.State contains any flags that are in BreakCacheLevel:
2892 	 * (Body of that "If" was here to just above the out label.)
2893 	 */
2894 	if ((nol->ol_state & BreakCacheLevel) == 0)
2895 		goto out;
2896 
2897 	/*
2898 	 * If Oplock.ExclusiveOpen is not empty, call the
2899 	 * algorithm in section 2.1.4.12.2, passing
2900 	 *	Open as the OperationOpen parameter,
2901 	 *	Oplock.ExclusiveOpen as the OplockOpen parameter,
2902 	 *	and Flags as the Flagsparameter.
2903 	 * If the algorithm returns TRUE:
2904 	 *	The algorithm returns at this point.
2905 	 */
2906 	if ((o = nol->excl_open) != NULL &&
2907 	    CompareOplockKeys(ofile, o, CmpFlags) == B_TRUE) {
2908 		status = NT_STATUS_SUCCESS;
2909 		goto out;
2910 	}
2911 
2912 	/*
2913 	 * Switch (Oplock.State):
2914 	 */
2915 	switch (nol->ol_state) {
2916 
2917 	case (READ_CACHING|HANDLE_CACHING|MIXED_R_AND_RH):
2918 	case READ_CACHING:
2919 	case (LEVEL_TWO_OPLOCK|READ_CACHING):
2920 		/*
2921 		 * If BreakCacheLevel contains READ_CACHING:
2922 		 */
2923 		if ((BreakCacheLevel & READ_CACHING) != 0) {
2924 			/*
2925 			 * For each Open ThisOpen in Oplock.ROplocks:
2926 			 *   Call the algorithm in section 2.1.4.12.2, pass:
2927 			 *	Open as the OperationOpen parameter,
2928 			 *	ThisOpen as the OplockOpen parameter,
2929 			 *	and Flags as the Flagsparameter.
2930 			 *   If the algorithm returns FALSE:
2931 			 *	Remove ThisOpen from Oplock.ROplocks.
2932 			 *	Notify the server of an oplock break
2933 			 *	  according to the algorithm in
2934 			 *	  section 2.1.5.17.3, setting the
2935 			 *	  algorithm's parameters as follows:
2936 			 *		BreakingOplockOpen = ThisOpen.
2937 			 *		NewOplockLevel = LEVEL_NONE.
2938 			 *		AcknowledgeRequired = FALSE.
2939 			 *		Compl_Status = STATUS_SUCCESS.
2940 			 *	(The operation does not end at this point;
2941 			 *	 this call to 2.1.5.17.3 completes some
2942 			 *	 earlier call to 2.1.5.17.2.)
2943 			 *	EndIf
2944 			 * EndFor
2945 			 */
2946 			FOREACH_NODE_OFILE(node, o) {
2947 				if (o->f_oplock.onlist_R == 0)
2948 					continue;
2949 				if (!CompareOplockKeys(ofile, o, CmpFlags)) {
2950 					o->f_oplock.onlist_R = B_FALSE;
2951 					nol->cnt_R--;
2952 					ASSERT(nol->cnt_R >= 0);
2953 
2954 					smb_oplock_ind_break(o,
2955 					    LEVEL_NONE, B_FALSE,
2956 					    NT_STATUS_SUCCESS);
2957 				}
2958 			}
2959 		}
2960 		/*
2961 		 * If Oplock.State equals
2962 		 *  (READ_CACHING|HANDLE_CACHING|MIXED_R_AND_RH):
2963 		 *	// Do nothing; FALL THROUGH to next Case statement.
2964 		 * Else
2965 		 *	Recompute Oplock.State according to the
2966 		 *	algorithm in section 2.1.4.13, passing
2967 		 *	Oplock as the ThisOplock parameter.
2968 		 * EndIf
2969 		 */
2970 		if (nol->ol_state ==
2971 		    (READ_CACHING|HANDLE_CACHING|MIXED_R_AND_RH))
2972 			goto case_cache_rh;
2973 
2974 		RecomputeOplockState(node);
2975 		break;
2976 	/* EndCase	XXX Note: spec. swapped this with prev. Endif. */
2977 
2978 	case_cache_rh:
2979 	case (READ_CACHING|HANDLE_CACHING):
2980 
2981 		/*
2982 		 * If BreakCacheLevel equals HANDLE_CACHING:
2983 		 */
2984 		if (BreakCacheLevel == HANDLE_CACHING) {
2985 
2986 			/*
2987 			 * For each Open ThisOpen in Oplock.RHOplocks:
2988 			 *	If ThisOpen.OplockKey != Open.OplockKey:
2989 			 */
2990 			FOREACH_NODE_OFILE(node, o) {
2991 				if (o->f_oplock.onlist_RH == 0)
2992 					continue;
2993 				if (!CompareOplockKeys(ofile, o, CmpFlags)) {
2994 
2995 					/*
2996 					 * Remove ThisOpen from
2997 					 *  Oplock.RHOplocks.
2998 					 */
2999 					o->f_oplock.onlist_RH = B_FALSE;
3000 					nol->cnt_RH--;
3001 					ASSERT(nol->cnt_RH >= 0);
3002 
3003 					/*
3004 					 * Notify the server of an oplock break
3005 					 *   according to the algorithm in
3006 					 *   section 2.1.5.17.3, setting the
3007 					 *   algorithm's parameters as follows:
3008 					 *	BreakingOplockOpen = ThisOpen.
3009 					 *	NewOplockLevel = READ_CACHING.
3010 					 *	AcknowledgeRequired = TRUE.
3011 					 *	Compl_Status = STATUS_SUCCESS.
3012 					 * (The operation does not end at this
3013 					 *  point; this call to 2.1.5.17.3
3014 					 *  completes some earlier call to
3015 					 *  2.1.5.17.2.)
3016 					 */
3017 					smb_oplock_ind_break(o,
3018 					    READ_CACHING, B_TRUE,
3019 					    NT_STATUS_SUCCESS);
3020 
3021 					/*
3022 					 * Initialize a new RHOpContext object,
3023 					 *   setting its fields as follows:
3024 					 *	RHOpCtx.Open = ThisOpen.
3025 					 *	RHOpCtx.BreakingToRead = TRUE.
3026 					 * Add the new RHOpContext object to
3027 					 *    Oplock.RHBreakQueue.
3028 					 * Set NeedToWait to TRUE.
3029 					 */
3030 					o->f_oplock.BreakingToRead = B_TRUE;
3031 					ASSERT(!(o->f_oplock.onlist_RHBQ));
3032 					o->f_oplock.onlist_RHBQ = B_TRUE;
3033 					nol->cnt_RHBQ++;
3034 
3035 					NeedToWait = B_TRUE;
3036 				}
3037 			}
3038 		}
3039 
3040 		/*
3041 		 * Else If BreakCacheLevel contains both
3042 		 *   READ_CACHING and WRITE_CACHING:
3043 		 */
3044 		else if ((BreakCacheLevel & (READ_CACHING | WRITE_CACHING)) ==
3045 		    (READ_CACHING | WRITE_CACHING)) {
3046 
3047 			/*
3048 			 * For each RHOpContext ThisContext in
3049 			 * Oplock.RHBreakQueue:
3050 			 *	Call the algorithm in section 2.1.4.12.2,
3051 			 *	  passing Open as the OperationOpen parameter,
3052 			 *	  ThisContext.Open as the OplockOpen parameter,
3053 			 *	  and Flags as the Flags parameter.
3054 			 *	If the algorithm returns FALSE:
3055 			 *		Set ThisContext.BreakingToRead to FALSE.
3056 			 *		If BreakCacheLevel & HANDLE_CACHING:
3057 			 *			Set NeedToWait to TRUE.
3058 			 *		EndIf
3059 			 *	EndIf
3060 			 * EndFor
3061 			 */
3062 			FOREACH_NODE_OFILE(node, o) {
3063 				if (o->f_oplock.onlist_RHBQ == 0)
3064 					continue;
3065 				if (!CompareOplockKeys(ofile, o, CmpFlags)) {
3066 					o->f_oplock.BreakingToRead = B_FALSE;
3067 					if (BreakCacheLevel & HANDLE_CACHING)
3068 						NeedToWait = B_TRUE;
3069 				}
3070 			}
3071 
3072 			/*
3073 			 * For each Open ThisOpen in Oplock.RHOplocks:
3074 			 *	Call the algorithm in section 2.1.4.12.2,
3075 			 *	  passing Open as the OperationOpen parameter,
3076 			 *	  ThisOpen as the OplockOpen parameter, and
3077 			 *	  Flags as the Flagsparameter.
3078 			 *	If the algorithm  returns FALSE:
3079 			 *		Remove ThisOpen from Oplock.RHOplocks.
3080 			 *		Notify the server of an oplock break
3081 			 *		  according to the algorithm in
3082 			 *		  section 2.1.5.17.3, setting the
3083 			 *		  algorithm's parameters as follows:
3084 			 *			BreakingOplockOpen = ThisOpen.
3085 			 *			NewOplockLevel = LEVEL_NONE.
3086 			 *			AcknowledgeRequired = TRUE.
3087 			 *			Compl_Status = STATUS_SUCCESS.
3088 			 *		(The operation does not end at this
3089 			 *		 point; this call to 2.1.5.17.3
3090 			 *		 completes some earlier call to
3091 			 *		 2.1.5.17.2.)
3092 			 *		Initialize a new RHOpContext object,
3093 			 *		  setting its fields as follows:
3094 			 *			RHOpCtx.Open = ThisOpen.
3095 			 *			RHOpCtx.BreakingToRead = FALSE
3096 			 *		Add the new RHOpContext object to
3097 			 *		  Oplock.RHBreakQueue.
3098 			 *		If BreakCacheLevel contains
3099 			 *		  HANDLE_CACHING:
3100 			 *			Set NeedToWait to TRUE.
3101 			 *		EndIf
3102 			 *	EndIf
3103 			 * EndFor
3104 			 */
3105 			FOREACH_NODE_OFILE(node, o) {
3106 				if (o->f_oplock.onlist_RH == 0)
3107 					continue;
3108 				if (!CompareOplockKeys(ofile, o, CmpFlags)) {
3109 					o->f_oplock.onlist_RH = B_FALSE;
3110 					nol->cnt_RH--;
3111 					ASSERT(nol->cnt_RH >= 0);
3112 
3113 					smb_oplock_ind_break(o,
3114 					    LEVEL_NONE, B_TRUE,
3115 					    NT_STATUS_SUCCESS);
3116 
3117 					o->f_oplock.BreakingToRead = B_FALSE;
3118 					ASSERT(!(o->f_oplock.onlist_RHBQ));
3119 					o->f_oplock.onlist_RHBQ = B_TRUE;
3120 					nol->cnt_RHBQ++;
3121 
3122 					if (BreakCacheLevel & HANDLE_CACHING)
3123 						NeedToWait = B_TRUE;
3124 				}
3125 			}
3126 		}
3127 
3128 // If the oplock is explicitly losing HANDLE_CACHING, RHBreakQueue is
3129 // not empty, and the algorithm has not yet decided to wait, this operation
3130 // might have to wait if there is an oplock on RHBreakQueue with a
3131 // non-matching key. This is done because even if this operation didn't
3132 // cause a break of a currently-granted Read-Handle caching oplock, it
3133 // might have done so had a currently-breaking oplock still been granted.
3134 
3135 		/*
3136 		 * If (NeedToWait is FALSE) and
3137 		 *   (Oplock.RHBreakQueue is empty) and   (XXX: Not empty)
3138 		 *   (BreakCacheLevel contains HANDLE_CACHING):
3139 		 *	For each RHOpContext ThisContex in Oplock.RHBreakQueue:
3140 		 *		If ThisContext.Open.OplockKey != Open.OplockKey:
3141 		 *			Set NeedToWait to TRUE.
3142 		 *			Break out of the For loop.
3143 		 *		EndIf
3144 		 *	EndFor
3145 		 * EndIf
3146 		 * Recompute Oplock.State according to the algorithm in
3147 		 *   section 2.1.4.13, passing Oplock as ThisOplock.
3148 		 */
3149 		if (NeedToWait == B_FALSE &&
3150 		    (BreakCacheLevel & HANDLE_CACHING) != 0) {
3151 			FOREACH_NODE_OFILE(node, o) {
3152 				if (o->f_oplock.onlist_RHBQ == 0)
3153 					continue;
3154 				if (!CompareOplockKeys(ofile, o, CmpFlags)) {
3155 					NeedToWait = B_TRUE;
3156 					break;
3157 				}
3158 			}
3159 		}
3160 		RecomputeOplockState(node);
3161 		break;
3162 
3163 	case (READ_CACHING|HANDLE_CACHING|BREAK_TO_READ_CACHING):
3164 		/*
3165 		 * If BreakCacheLevel contains READ_CACHING:
3166 		 */
3167 		if ((BreakCacheLevel & READ_CACHING) != 0) {
3168 			/*
3169 			 * For each RHOpContext ThisContext in
3170 			 *  Oplock.RHBreakQueue:
3171 			 *	Call the algorithm in section 2.1.4.12.2,
3172 			 *	  passing Open = OperationOpen parameter,
3173 			 *	  ThisContext.Open = OplockOpen parameter,
3174 			 *	  and Flags as the Flags parameter.
3175 			 *	If the algorithm returns FALSE:
3176 			 *		Set ThisCtx.BreakingToRead = FALSE.
3177 			 *	EndIf
3178 			 *	Recompute Oplock.State according to the
3179 			 *	  algorithm in section 2.1.4.13, passing
3180 			 *	  Oplock as the ThisOplock parameter.
3181 			 * EndFor
3182 			 */
3183 			FOREACH_NODE_OFILE(node, o) {
3184 				if (o->f_oplock.onlist_RHBQ == 0)
3185 					continue;
3186 				if (!CompareOplockKeys(ofile, o, CmpFlags)) {
3187 					o->f_oplock.BreakingToRead = B_FALSE;
3188 				}
3189 			}
3190 			RecomputeOplockState(node);
3191 		}
3192 		/* FALLTHROUGH */
3193 
3194 	case (READ_CACHING|HANDLE_CACHING|BREAK_TO_NO_CACHING):
3195 		/*
3196 		 * If BreakCacheLevel contains HANDLE_CACHING:
3197 		 *	For each RHOpContext ThisContext in Oplock.RHBreakQueue:
3198 		 *		If ThisContext.Open.OplockKey != Open.OplockKey:
3199 		 *			Set NeedToWait to TRUE.
3200 		 *			Break out of the For loop.
3201 		 *		EndIf
3202 		 *	EndFor
3203 		 * EndIf
3204 		 */
3205 		if ((BreakCacheLevel & HANDLE_CACHING) != 0) {
3206 			FOREACH_NODE_OFILE(node, o) {
3207 				if (o->f_oplock.onlist_RHBQ == 0)
3208 					continue;
3209 				if (!CompareOplockKeys(ofile, o, CmpFlags)) {
3210 					NeedToWait = B_TRUE;
3211 					break;
3212 				}
3213 			}
3214 		}
3215 		break;
3216 
3217 	case (READ_CACHING|WRITE_CACHING|EXCLUSIVE):
3218 		/*
3219 		 * If BreakCacheLevel contains both
3220 		 *  READ_CACHING and WRITE_CACHING:
3221 		 *	Notify the server of an oplock break according to
3222 		 *	  the algorithm in section 2.1.5.17.3, setting the
3223 		 *	  algorithm's parameters as follows:
3224 		 *		BreakingOplockOpen = Oplock.ExclusiveOpen.
3225 		 *		NewOplockLevel = LEVEL_NONE.
3226 		 *		AcknowledgeRequired = TRUE.
3227 		 *		OplockCompletionStatus = STATUS_SUCCESS.
3228 		 *	(The operation does not end at this point;
3229 		 *	 this call to 2.1.5.17.3 completes some
3230 		 *	 earlier call to 2.1.5.17.1.)
3231 		 *	Set Oplock.State to (READ_CACHING|WRITE_CACHING| \
3232 		 *			EXCLUSIVE|BREAK_TO_NO_CACHING).
3233 		 *	Set NeedToWait to TRUE.
3234 		 */
3235 		if ((BreakCacheLevel & (READ_CACHING | WRITE_CACHING)) ==
3236 		    (READ_CACHING | WRITE_CACHING)) {
3237 			o = nol->excl_open;
3238 			ASSERT(o != NULL);
3239 			smb_oplock_ind_break(o,
3240 			    LEVEL_NONE, B_TRUE,
3241 			    NT_STATUS_SUCCESS);
3242 
3243 			nol->ol_state =
3244 			    (READ_CACHING|WRITE_CACHING|
3245 			    EXCLUSIVE|BREAK_TO_NO_CACHING);
3246 			NeedToWait = B_TRUE;
3247 		}
3248 
3249 		/*
3250 		 * Else If BreakCacheLevel contains WRITE_CACHING:
3251 		 *	Notify the server of an oplock break according to
3252 		 *	  the algorithm in section 2.1.5.17.3, setting the
3253 		 *	  algorithm's parameters as follows:
3254 		 *		BreakingOplockOpen = Oplock.ExclusiveOpen.
3255 		 *		NewOplockLevel = READ_CACHING.
3256 		 *		AcknowledgeRequired = TRUE.
3257 		 *		OplockCompletionStatus = STATUS_SUCCESS.
3258 		 *	(The operation does not end at this point;
3259 		 *	 this call to 2.1.5.17.3 completes some
3260 		 *	 earlier call to 2.1.5.17.1.)
3261 		 *	Set Oplock.State to (READ_CACHING|WRITE_CACHING|
3262 		 *			 EXCLUSIVE|BREAK_TO_READ_CACHING).
3263 		 *	Set NeedToWait to TRUE.
3264 		 * EndIf
3265 		 */
3266 		else if ((BreakCacheLevel & WRITE_CACHING) != 0) {
3267 			o = nol->excl_open;
3268 			ASSERT(o != NULL);
3269 			smb_oplock_ind_break(o,
3270 			    READ_CACHING, B_TRUE,
3271 			    NT_STATUS_SUCCESS);
3272 
3273 			nol->ol_state =
3274 			    (READ_CACHING|WRITE_CACHING|
3275 			    EXCLUSIVE|BREAK_TO_READ_CACHING);
3276 			NeedToWait = B_TRUE;
3277 		}
3278 		break;
3279 
3280 	case (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|EXCLUSIVE):
3281 		/*
3282 		 * If BreakCacheLevel equals WRITE_CACHING:
3283 		 *	Notify the server of an oplock break according to
3284 		 *	  the algorithm in section 2.1.5.17.3, setting the
3285 		 *	  algorithm's parameters as follows:
3286 		 *		BreakingOplockOpen = Oplock.ExclusiveOpen.
3287 		 *		NewOplockLevel = (READ_CACHING|HANDLE_CACHING).
3288 		 *		AcknowledgeRequired = TRUE.
3289 		 *		OplockCompletionStatus = STATUS_SUCCESS.
3290 		 *	(The operation does not end at this point;
3291 		 *	 this call to 2.1.5.17.3 completes some
3292 		 *	 earlier call to 2.1.5.17.1.)
3293 		 *	Set Oplock.State to (READ_CACHING|WRITE_CACHING|
3294 		 *			HANDLE_CACHING|EXCLUSIVE|
3295 		 *			BREAK_TO_READ_CACHING|
3296 		 *			BREAK_TO_HANDLE_CACHING).
3297 		 *	Set NeedToWait to TRUE.
3298 		 */
3299 		if (BreakCacheLevel == WRITE_CACHING) {
3300 			o = nol->excl_open;
3301 			ASSERT(o != NULL);
3302 			smb_oplock_ind_break(o,
3303 			    CACHE_RH, B_TRUE,
3304 			    NT_STATUS_SUCCESS);
3305 
3306 			nol->ol_state =
3307 			    (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|
3308 			    EXCLUSIVE|BREAK_TO_READ_CACHING|
3309 			    BREAK_TO_HANDLE_CACHING);
3310 			NeedToWait = B_TRUE;
3311 		}
3312 
3313 		/*
3314 		 * Else If BreakCacheLevel equals HANDLE_CACHING:
3315 		 *	Notify the server of an oplock break according to
3316 		 *	  the algorithm in section 2.1.5.17.3, setting the
3317 		 *	  algorithm's parameters as follows:
3318 		 *		BreakingOplockOpen = Oplock.ExclusiveOpen.
3319 		 *		NewOplockLevel = (READ_CACHING|WRITE_CACHING).
3320 		 *		AcknowledgeRequired = TRUE.
3321 		 *		OplockCompletionStatus = STATUS_SUCCESS.
3322 		 *	(The operation does not end at this point;
3323 		 *	 this call to 2.1.5.17.3 completes some
3324 		 *	 earlier call to 2.1.5.17.1.)
3325 		 *	Set Oplock.State to (READ_CACHING|WRITE_CACHING|
3326 		 *			HANDLE_CACHING|EXCLUSIVE|
3327 		 *			BREAK_TO_READ_CACHING|
3328 		 *			BREAK_TO_WRITE_CACHING).
3329 		 *	Set NeedToWait to TRUE.
3330 		 */
3331 		else if (BreakCacheLevel == HANDLE_CACHING) {
3332 			o = nol->excl_open;
3333 			ASSERT(o != NULL);
3334 			smb_oplock_ind_break(o,
3335 			    CACHE_RW, B_TRUE,
3336 			    NT_STATUS_SUCCESS);
3337 
3338 			nol->ol_state =
3339 			    (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|
3340 			    EXCLUSIVE|BREAK_TO_READ_CACHING|
3341 			    BREAK_TO_WRITE_CACHING);
3342 			NeedToWait = B_TRUE;
3343 		}
3344 
3345 		/*
3346 		 * Else If BreakCacheLevel contains both
3347 		 *  READ_CACHING and WRITE_CACHING:
3348 		 *	Notify the server of an oplock break according to
3349 		 *	  the algorithm in section 2.1.5.17.3, setting the
3350 		 *	  algorithm's parameters as follows:
3351 		 *		BreakingOplockOpen = Oplock.ExclusiveOpen.
3352 		 *		NewOplockLevel = LEVEL_NONE.
3353 		 *		AcknowledgeRequired = TRUE.
3354 		 *		OplockCompletionStatus = STATUS_SUCCESS.
3355 		 *	(The operation does not end at this point;
3356 		 *	 this call to 2.1.5.17.3 completes some
3357 		 *	 earlier call to 2.1.5.17.1.)
3358 		 *	Set Oplock.State to (READ_CACHING|WRITE_CACHING|
3359 		 *			HANDLE_CACHING|EXCLUSIVE|
3360 		 *			BREAK_TO_NO_CACHING).
3361 		 *	Set NeedToWait to TRUE.
3362 		 * EndIf
3363 		 */
3364 		else if ((BreakCacheLevel & (READ_CACHING | WRITE_CACHING)) ==
3365 		    (READ_CACHING | WRITE_CACHING)) {
3366 			o = nol->excl_open;
3367 			ASSERT(o != NULL);
3368 			smb_oplock_ind_break(o,
3369 			    LEVEL_NONE, B_TRUE,
3370 			    NT_STATUS_SUCCESS);
3371 
3372 			nol->ol_state =
3373 			    (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|
3374 			    EXCLUSIVE|BREAK_TO_NO_CACHING);
3375 			NeedToWait = B_TRUE;
3376 		}
3377 		break;
3378 
3379 	case (READ_CACHING|WRITE_CACHING|EXCLUSIVE|BREAK_TO_READ_CACHING):
3380 		/*
3381 		 * If BreakCacheLevel contains READ_CACHING:
3382 		 *	Set Oplock.State to (READ_CACHING|WRITE_CACHING|
3383 		 *			EXCLUSIVE|BREAK_TO_NO_CACHING).
3384 		 * EndIf
3385 		 * If BreakCacheLevel contains either
3386 		 *  READ_CACHING or WRITE_CACHING:
3387 		 *	Set NeedToWait to TRUE.
3388 		 * EndIf
3389 		 */
3390 		if ((BreakCacheLevel & READ_CACHING) != 0) {
3391 			nol->ol_state =
3392 			    (READ_CACHING|WRITE_CACHING|
3393 			    EXCLUSIVE|BREAK_TO_NO_CACHING);
3394 		}
3395 		if ((BreakCacheLevel & (READ_CACHING | WRITE_CACHING)) != 0) {
3396 			NeedToWait = B_TRUE;
3397 		}
3398 		break;
3399 
3400 	case (READ_CACHING|WRITE_CACHING|EXCLUSIVE|BREAK_TO_NO_CACHING):
3401 		/*
3402 		 * If BreakCacheLevel contains either
3403 		 *  READ_CACHING or WRITE_CACHING:
3404 		 *	Set NeedToWait to TRUE.
3405 		 * EndIf
3406 		 */
3407 		if ((BreakCacheLevel & (READ_CACHING | WRITE_CACHING)) != 0) {
3408 			NeedToWait = B_TRUE;
3409 		}
3410 		break;
3411 
3412 	case (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|EXCLUSIVE|
3413 	    BREAK_TO_READ_CACHING|BREAK_TO_WRITE_CACHING):
3414 		/*
3415 		 * If BreakCacheLevel == WRITE_CACHING:
3416 		 *	Set Oplock.State to (READ_CACHING|WRITE_CACHING|
3417 		 *	    HANDLE_CACHING|EXCLUSIVE|BREAK_TO_READ_CACHING).
3418 		 * Else If BreakCacheLevel contains both
3419 		 *  READ_CACHING and WRITE_CACHING:
3420 		 *	Set Oplock.State to (READ_CACHING|WRITE_CACHING|
3421 		 *	    HANDLE_CACHING|EXCLUSIVE|BREAK_TO_NO_CACHING).
3422 		 * EndIf
3423 		 * Set NeedToWait to TRUE.
3424 		 */
3425 		if (BreakCacheLevel == WRITE_CACHING) {
3426 			nol->ol_state = (READ_CACHING|WRITE_CACHING|
3427 			    HANDLE_CACHING|EXCLUSIVE|BREAK_TO_READ_CACHING);
3428 		}
3429 		else if ((BreakCacheLevel & (READ_CACHING | WRITE_CACHING)) ==
3430 		    (READ_CACHING | WRITE_CACHING)) {
3431 			nol->ol_state = (READ_CACHING|WRITE_CACHING|
3432 			    HANDLE_CACHING|EXCLUSIVE|BREAK_TO_NO_CACHING);
3433 		}
3434 		NeedToWait = B_TRUE;
3435 		break;
3436 
3437 	case (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|EXCLUSIVE|
3438 	    BREAK_TO_READ_CACHING|BREAK_TO_HANDLE_CACHING):
3439 		/*
3440 		 * If BreakCacheLevel == HANDLE_CACHING:
3441 		 *	Set Oplock.State to (READ_CACHING|WRITE_CACHING|
3442 		 *			HANDLE_CACHING|EXCLUSIVE|
3443 		 *			BREAK_TO_READ_CACHING).
3444 		 * Else If BreakCacheLevel contains READ_CACHING:
3445 		 *	Set Oplock.State to (READ_CACHING|WRITE_CACHING|
3446 		 *			HANDLE_CACHING|EXCLUSIVE|
3447 		 *			BREAK_TO_NO_CACHING).
3448 		 * EndIf
3449 		 * Set NeedToWait to TRUE.
3450 		 */
3451 		if (BreakCacheLevel == HANDLE_CACHING) {
3452 			nol->ol_state =
3453 			    (READ_CACHING|WRITE_CACHING|
3454 			    HANDLE_CACHING|EXCLUSIVE|
3455 			    BREAK_TO_READ_CACHING);
3456 		}
3457 		else if ((BreakCacheLevel & READ_CACHING) != 0) {
3458 			nol->ol_state =
3459 			    (READ_CACHING|WRITE_CACHING|
3460 			    HANDLE_CACHING|EXCLUSIVE|
3461 			    BREAK_TO_NO_CACHING);
3462 		}
3463 		NeedToWait = B_TRUE;
3464 		break;
3465 
3466 	case (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|EXCLUSIVE|
3467 	    BREAK_TO_READ_CACHING):
3468 		/*
3469 		 * If BreakCacheLevel contains READ_CACHING,
3470 		 *	Set Oplock.State to (READ_CACHING|WRITE_CACHING|
3471 		 *			HANDLE_CACHING|EXCLUSIVE|
3472 		 *			BREAK_TO_NO_CACHING).
3473 		 * EndIf
3474 		 * Set NeedToWait to TRUE.
3475 		 */
3476 		if ((BreakCacheLevel & READ_CACHING) != 0) {
3477 			nol->ol_state =
3478 			    (READ_CACHING|WRITE_CACHING|
3479 			    HANDLE_CACHING|EXCLUSIVE|
3480 			    BREAK_TO_NO_CACHING);
3481 		}
3482 		NeedToWait = B_TRUE;
3483 		break;
3484 
3485 	case (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|EXCLUSIVE|
3486 	    BREAK_TO_NO_CACHING):
3487 		NeedToWait = B_TRUE;
3488 		break;
3489 
3490 	} /* Switch */
3491 
3492 	if (NeedToWait) {
3493 		/*
3494 		 * The operation that called this algorithm MUST be
3495 		 *   made cancelable by inserting it into
3496 		 *   CancelableOperations.CancelableOperationList.
3497 		 * The operation that called this algorithm waits until
3498 		 *   the oplock break is acknowledged, as specified in
3499 		 *   section 2.1.5.18, or the operation is canceled.
3500 		 */
3501 		status = NT_STATUS_OPLOCK_BREAK_IN_PROGRESS;
3502 		/* Caller does smb_oplock_wait_break() */
3503 	}
3504 
3505 out:
3506 	mutex_exit(&node->n_oplock.ol_mutex);
3507 	smb_llist_exit(&node->n_ofile_list);
3508 
3509 	return (status);
3510 }
3511 
3512 /*
3513  * smb_oplock_move()
3514  *
3515  * Helper function for smb2_lease_ofile_close, where we're closing the
3516  * ofile that has the oplock for a given lease, and need to move that
3517  * oplock to another handle with the same lease.
3518  *
3519  * This is not described in [MS-FSA], so presumably Windows does this
3520  * by keeping oplock objects separate from the open files (no action
3521  * needed in the FSA layer).  We keep the oplock state as part of the
3522  * ofile, so we need to relocate the oplock state in this case.
3523  *
3524  * Note that in here, we're moving state for both the FSA level and
3525  * the SMB level (which is unusual) but this is the easiest way to
3526  * make sure we move the state without any other effects.
3527  */
3528 void
3529 smb_oplock_move(smb_node_t *node,
3530     smb_ofile_t *fr_ofile, smb_ofile_t *to_ofile)
3531 {
3532 	/*
3533 	 * These are the two common states for an ofile with
3534 	 * a lease that's not the one holding the oplock.
3535 	 * Log if it's not either of these.
3536 	 */
3537 	static const smb_oplock_grant_t og0 = { 0 };
3538 	static const smb_oplock_grant_t og8 = {
3539 	    .og_state = OPLOCK_LEVEL_GRANULAR, 0 };
3540 	smb_oplock_grant_t og_tmp;
3541 
3542 	ASSERT(fr_ofile->f_node == node);
3543 	ASSERT(to_ofile->f_node == node);
3544 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
3545 
3546 	/*
3547 	 * The ofile to which we're moving the oplock
3548 	 * should NOT have any oplock state.  However,
3549 	 * as long as we just swap state between the
3550 	 * two oplocks, we won't invalidate any of
3551 	 * the node's "onlist" counts etc.
3552 	 */
3553 	if (bcmp(&to_ofile->f_oplock, &og0, sizeof (og0)) != 0 &&
3554 	    bcmp(&to_ofile->f_oplock, &og8, sizeof (og8)) != 0) {
3555 #ifdef	DEBUG
3556 		cmn_err(CE_NOTE, "smb_oplock_move: not empty?");
3557 #endif
3558 		DTRACE_PROBE2(dst__not__empty,
3559 		    smb_node_t, node, smb_ofile_t, to_ofile);
3560 	}
3561 
3562 	og_tmp = to_ofile->f_oplock;
3563 	to_ofile->f_oplock = fr_ofile->f_oplock;
3564 	fr_ofile->f_oplock = og_tmp;
3565 
3566 	if (node->n_oplock.excl_open == fr_ofile)
3567 		node->n_oplock.excl_open = to_ofile;
3568 
3569 }
3570