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