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