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