xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_lease.c (revision 5d8538b6af5408057619ad300b4f998a8cf99572)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2021 Tintri by DDN, Inc.  All rights reserved.
14  * Copyright 2022 RackTop Systems, Inc.
15  */
16 
17 /*
18  * Dispatch function for SMB2_OPLOCK_BREAK
19  */
20 
21 #include <smbsrv/smb2_kproto.h>
22 #include <smbsrv/smb_oplock.h>
23 
24 /* StructSize for the two "break" message formats. */
25 #define	SSZ_OPLOCK	24
26 #define	SSZ_LEASE_ACK	36
27 #define	SSZ_LEASE_BRK	44
28 
29 #define	NODE_FLAGS_DELETING	(NODE_FLAGS_DELETE_ON_CLOSE |\
30 				NODE_FLAGS_DELETE_COMMITTED)
31 
32 static const char lease_zero[UUID_LEN] = { 0 };
33 
34 static kmem_cache_t	*smb_lease_cache = NULL;
35 
36 void
37 smb2_lease_init()
38 {
39 	if (smb_lease_cache != NULL)
40 		return;
41 
42 	smb_lease_cache = kmem_cache_create("smb_lease_cache",
43 	    sizeof (smb_lease_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
44 }
45 
46 void
47 smb2_lease_fini()
48 {
49 	if (smb_lease_cache != NULL) {
50 		kmem_cache_destroy(smb_lease_cache);
51 		smb_lease_cache = NULL;
52 	}
53 }
54 
55 static void
56 smb2_lease_hold(smb_lease_t *ls)
57 {
58 	mutex_enter(&ls->ls_mutex);
59 	ls->ls_refcnt++;
60 	mutex_exit(&ls->ls_mutex);
61 }
62 
63 static void
64 lease_destroy(smb_lease_t *ls)
65 {
66 	smb_node_release(ls->ls_node);
67 	mutex_destroy(&ls->ls_mutex);
68 	kmem_cache_free(smb_lease_cache, ls);
69 }
70 
71 void
72 smb2_lease_rele(smb_lease_t *ls)
73 {
74 	smb_llist_t *bucket;
75 	boolean_t destroy = B_FALSE;
76 
77 	mutex_enter(&ls->ls_mutex);
78 	ls->ls_refcnt--;
79 	if (ls->ls_refcnt != 0) {
80 		mutex_exit(&ls->ls_mutex);
81 		return;
82 	}
83 	mutex_exit(&ls->ls_mutex);
84 
85 	/*
86 	 * Get the list lock, then re-check the refcnt
87 	 * and if it's still zero, unlink & destroy.
88 	 */
89 	bucket = ls->ls_bucket;
90 	smb_llist_enter(bucket, RW_WRITER);
91 
92 	mutex_enter(&ls->ls_mutex);
93 	if (ls->ls_refcnt == 0) {
94 		smb_llist_remove(bucket, ls);
95 		destroy = B_TRUE;
96 	}
97 	mutex_exit(&ls->ls_mutex);
98 
99 	smb_llist_exit(bucket);
100 
101 	if (destroy) {
102 		lease_destroy(ls);
103 	}
104 }
105 
106 /*
107  * Compute a hash from a uuid
108  * Based on mod_hash_bystr()
109  */
110 static uint_t
111 smb_hash_uuid(const uint8_t *uuid)
112 {
113 	char *k = (char *)uuid;
114 	uint_t hash = 0;
115 	uint_t g;
116 	int i;
117 
118 	ASSERT(k);
119 	for (i = 0; i < UUID_LEN; i++) {
120 		hash = (hash << 4) + k[i];
121 		if ((g = (hash & 0xf0000000)) != 0) {
122 			hash ^= (g >> 24);
123 			hash ^= g;
124 		}
125 	}
126 	return (hash);
127 }
128 
129 /*
130  * Add or update a lease table entry for a new ofile.
131  * (in the per-session lease table)
132  * See [MS-SMB2] 3.3.5.9.8
133  * Handling the SMB2_CREATE_REQUEST_LEASE Create Context
134  */
135 uint32_t
136 smb2_lease_create(smb_request_t *sr, uint8_t *clnt)
137 {
138 	smb_arg_open_t *op = &sr->arg.open;
139 	uint8_t *key = op->lease_key;
140 	smb_ofile_t *of = sr->fid_ofile;
141 	smb_hash_t *ht = sr->sr_server->sv_lease_ht;
142 	smb_llist_t *bucket;
143 	smb_lease_t *lease;
144 	smb_lease_t *newlease;
145 	size_t hashkey;
146 	uint32_t status = NT_STATUS_INVALID_PARAMETER;
147 
148 	if (bcmp(key, lease_zero, UUID_LEN) == 0)
149 		return (status);
150 
151 	/*
152 	 * Find or create, and add a ref for the new ofile.
153 	 */
154 	hashkey = smb_hash_uuid(key);
155 	hashkey &= (ht->num_buckets - 1);
156 	bucket = &ht->buckets[hashkey].b_list;
157 
158 	newlease = kmem_cache_alloc(smb_lease_cache, KM_SLEEP);
159 	bzero(newlease, sizeof (smb_lease_t));
160 	mutex_init(&newlease->ls_mutex, NULL, MUTEX_DEFAULT, NULL);
161 	newlease->ls_bucket = bucket;
162 	newlease->ls_node = of->f_node;
163 	smb_node_ref(newlease->ls_node);
164 	newlease->ls_refcnt = 1;
165 	newlease->ls_epoch = op->lease_epoch;
166 	newlease->ls_version = op->lease_version;
167 	bcopy(key, newlease->ls_key, UUID_LEN);
168 	bcopy(clnt, newlease->ls_clnt, UUID_LEN);
169 
170 	smb_llist_enter(bucket, RW_WRITER);
171 	for (lease = smb_llist_head(bucket); lease != NULL;
172 	    lease = smb_llist_next(bucket, lease)) {
173 		/*
174 		 * Looking for this lease ID, on a node
175 		 * that's not being deleted.
176 		 */
177 		if (bcmp(lease->ls_key, key, UUID_LEN) == 0 &&
178 		    bcmp(lease->ls_clnt, clnt, UUID_LEN) == 0 &&
179 		    (lease->ls_node->flags & NODE_FLAGS_DELETING) == 0)
180 			break;
181 	}
182 	if (lease != NULL) {
183 		/*
184 		 * Found existing lease.  Make sure it refers to
185 		 * the same node...
186 		 */
187 		if (lease->ls_node == of->f_node) {
188 			smb2_lease_hold(lease);
189 		} else {
190 			/* Same lease ID, different node! */
191 #ifdef DEBUG
192 			cmn_err(CE_NOTE, "new lease on node %p (%s) "
193 			    "conflicts with existing node %p (%s)",
194 			    (void *) of->f_node,
195 			    of->f_node->od_name,
196 			    (void *) lease->ls_node,
197 			    lease->ls_node->od_name);
198 #endif
199 			DTRACE_PROBE2(dup_lease, smb_request_t *, sr,
200 			    smb_lease_t *, lease);
201 			lease = NULL; /* error */
202 		}
203 	} else {
204 		lease = newlease;
205 		smb_llist_insert_head(bucket, lease);
206 		newlease = NULL; /* don't free */
207 	}
208 	smb_llist_exit(bucket);
209 
210 	if (newlease != NULL) {
211 		lease_destroy(newlease);
212 	}
213 
214 	if (lease != NULL) {
215 		of->f_lease = lease;
216 		status = NT_STATUS_SUCCESS;
217 	}
218 
219 	return (status);
220 }
221 
222 /*
223  * Find the lease for a given: client_uuid, lease_key
224  * Returns the lease with a new ref.
225  */
226 static smb_lease_t *
227 lease_lookup(smb_request_t *sr, uint8_t *lease_key)
228 {
229 	smb_server_t *sv = sr->sr_server;
230 	uint8_t *clnt_uuid = sr->session->clnt_uuid;
231 	smb_hash_t *ht = sv->sv_lease_ht;
232 	smb_llist_t *bucket;
233 	smb_lease_t *lease;
234 	size_t hashkey;
235 
236 	hashkey = smb_hash_uuid(lease_key);
237 	hashkey &= (ht->num_buckets - 1);
238 	bucket = &ht->buckets[hashkey].b_list;
239 
240 	smb_llist_enter(bucket, RW_READER);
241 	lease = smb_llist_head(bucket);
242 	while (lease != NULL) {
243 		if (bcmp(lease->ls_key, lease_key, UUID_LEN) == 0 &&
244 		    bcmp(lease->ls_clnt, clnt_uuid, UUID_LEN) == 0) {
245 			smb2_lease_hold(lease);
246 			break;
247 		}
248 		lease = smb_llist_next(bucket, lease);
249 	}
250 	smb_llist_exit(bucket);
251 
252 	return (lease);
253 }
254 
255 /*
256  * Find the oplock smb_ofile_t for the specified lease.
257  * If no such ofile, NT_STATUS_UNSUCCESSFUL.
258  * On success, ofile (held) in sr->fid_ofile.
259  */
260 static uint32_t
261 lease_find_oplock(smb_request_t *sr, smb_lease_t *lease)
262 {
263 	smb_node_t	*node = lease->ls_node;
264 	smb_ofile_t	*o;
265 	uint32_t	status = NT_STATUS_UNSUCCESSFUL;
266 
267 	ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
268 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
269 	ASSERT(sr->fid_ofile == NULL);
270 
271 	FOREACH_NODE_OFILE(node, o) {
272 		if (o->f_lease != lease)
273 			continue;
274 		if (o != lease->ls_oplock_ofile)
275 			continue;
276 		/*
277 		 * Found the ofile holding the oplock
278 		 * This hold released in smb_request_free
279 		 */
280 		if (smb_ofile_hold_olbrk(o)) {
281 			sr->fid_ofile = o;
282 			status = NT_STATUS_SUCCESS;
283 			break;
284 		}
285 	}
286 
287 	return (status);
288 }
289 
290 /*
291  * This is called by smb2_oplock_break_ack when the struct size
292  * indicates this is a lease break (SZ_LEASE).  See:
293  * [MS-SMB2] 3.3.5.22.2 Processing a Lease Acknowledgment
294  * This is an "Ack" from the client.
295  */
296 smb_sdrc_t
297 smb2_lease_break_ack(smb_request_t *sr)
298 {
299 	smb_arg_olbrk_t	*olbrk = &sr->arg.olbrk;
300 	smb_lease_t *lease;
301 	smb_node_t  *node;
302 	smb_ofile_t *ofile;
303 	uint32_t LeaseState;
304 	uint32_t status;
305 	int rc = 0;
306 
307 	if (sr->session->dialect < SMB_VERS_2_1)
308 		return (SDRC_ERROR);
309 
310 	/*
311 	 * Decode an SMB2 Lease Acknowldgement
312 	 * [MS-SMB2] 2.2.24.2
313 	 * Note: Struct size decoded by caller.
314 	 */
315 	rc = smb_mbc_decodef(
316 	    &sr->smb_data, "6.#cl8.",
317 	    /* reserved		  6. */
318 	    UUID_LEN,		/* # */
319 	    olbrk->LeaseKey,	/* c */
320 	    &olbrk->NewLevel);	/* l */
321 	    /* duration		  8. */
322 	if (rc != 0)
323 		return (SDRC_ERROR);
324 	LeaseState = olbrk->NewLevel;
325 
326 	/*
327 	 * Find the lease via the given key.
328 	 */
329 	lease = lease_lookup(sr, olbrk->LeaseKey);
330 	if (lease == NULL) {
331 		/*
332 		 * It's unusual to skip the dtrace start/done
333 		 * probes like this, but trying to run them
334 		 * with no lease->node would be complex and
335 		 * would not show anything particularly useful.
336 		 * Do the start probe after we find the ofile.
337 		 */
338 		status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
339 		smb2sr_put_error(sr, status);
340 		return (SDRC_SUCCESS);
341 	}
342 	// Note: lease ref; smb_lease_rele() below.
343 	node = lease->ls_node;
344 
345 	/*
346 	 * Find the leased oplock.  Hold locks so it can't move
347 	 * until we're done with ACK-break processing.
348 	 */
349 	smb_llist_enter(&node->n_ofile_list, RW_READER);
350 	mutex_enter(&node->n_oplock.ol_mutex);
351 
352 	status = lease_find_oplock(sr, lease);
353 	/* Normally have sr->fid_ofile now. */
354 
355 	DTRACE_SMB2_START(op__OplockBreak, smb_request_t *, sr);
356 
357 	if (status != 0) {
358 		/* Leased oplock not found.  Must have closed. */
359 		goto errout;
360 	}
361 
362 	/* Success, so have sr->fid_ofile */
363 	ofile = sr->fid_ofile;
364 
365 	if (lease->ls_breaking == B_FALSE) {
366 		/*
367 		 * This ACK is either unsolicited or too late,
368 		 * eg. we timed out the ACK and did it locally.
369 		 */
370 		status = NT_STATUS_UNSUCCESSFUL;
371 		goto errout;
372 	}
373 
374 	/*
375 	 * If the new LeaseState has any bits in excess of
376 	 * the lease state we sent in the break, error...
377 	 */
378 	if ((LeaseState & ~(lease->ls_breakto)) != 0) {
379 		status = NT_STATUS_REQUEST_NOT_ACCEPTED;
380 		goto errout;
381 	}
382 
383 	/*
384 	 * Process the lease break ack.
385 	 *
386 	 * Clear breaking flags before we ack,
387 	 * because ack might set those.
388 	 * Signal both CVs, out of paranoia.
389 	 */
390 	ofile->f_oplock.og_breaking = B_FALSE;
391 	cv_broadcast(&ofile->f_oplock.og_ack_cv);
392 	lease->ls_breaking = B_FALSE;
393 	cv_broadcast(&lease->ls_ack_cv);
394 
395 	LeaseState |= OPLOCK_LEVEL_GRANULAR;
396 	status = smb_oplock_ack_break(sr, ofile, &LeaseState);
397 
398 	ofile->f_oplock.og_state = LeaseState;
399 	lease->ls_state = LeaseState;
400 	/* ls_epoch does not change here */
401 
402 	if (ofile->dh_persist)
403 		smb2_dh_update_oplock(sr, ofile);
404 
405 errout:
406 	sr->smb2_status = status;
407 	DTRACE_SMB2_DONE(op__OplockBreak, smb_request_t *, sr);
408 
409 	mutex_exit(&node->n_oplock.ol_mutex);
410 	smb_llist_exit(&node->n_ofile_list);
411 
412 	smb2_lease_rele(lease);
413 
414 	if (status) {
415 		smb2sr_put_error(sr, status);
416 		return (SDRC_SUCCESS);
417 	}
418 
419 	/*
420 	 * Encode an SMB2 Lease Ack. response
421 	 * [MS-SMB2] 2.2.25.2
422 	 */
423 	LeaseState &= OPLOCK_LEVEL_CACHE_MASK;
424 	(void) smb_mbc_encodef(
425 	    &sr->reply, "w6.#cl8.",
426 	    SSZ_LEASE_ACK,	/* w */
427 	    /* reserved		  6. */
428 	    UUID_LEN,		/* # */
429 	    olbrk->LeaseKey,	/* c */
430 	    LeaseState);	/* l */
431 	    /* duration		  8. */
432 
433 	return (SDRC_SUCCESS);
434 
435 }
436 
437 /*
438  * Compose an SMB2 Lease Break Notification packet, including
439  * the SMB2 header and everything, in sr->reply.
440  * The caller will send it and free the request.
441  *
442  * [MS-SMB2] 2.2.23.2 Lease Break Notification
443  */
444 static void
445 smb2_lease_break_notification(smb_request_t *sr,
446     uint32_t OldLevel, uint32_t NewLevel,
447     uint16_t Epoch, boolean_t AckReq)
448 {
449 	smb_lease_t *ls = sr->fid_ofile->f_lease;
450 	uint16_t Flags = 0;
451 
452 	/*
453 	 * Convert internal lease info to SMB2
454 	 */
455 	if (AckReq)
456 		Flags = SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED;
457 	if (ls->ls_version < 2)
458 		Epoch = 0;
459 	OldLevel &= OPLOCK_LEVEL_CACHE_MASK;
460 	NewLevel &= OPLOCK_LEVEL_CACHE_MASK;
461 
462 	/*
463 	 * SMB2 Header
464 	 */
465 	sr->smb2_cmd_code = SMB2_OPLOCK_BREAK;
466 	sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR;
467 	sr->smb_tid = 0;
468 	sr->smb_pid = 0;
469 	sr->smb2_ssnid = 0;
470 	sr->smb2_messageid = UINT64_MAX;
471 	(void) smb2_encode_header(sr, B_FALSE);
472 
473 	/*
474 	 * SMB2 Oplock Break, variable part
475 	 *
476 	 * [MS-SMB2] says the current lease state preceeds the
477 	 * new lease state, but that looks like an error...
478 	 */
479 	(void) smb_mbc_encodef(
480 	    &sr->reply, "wwl#cll4.4.4.",
481 	    SSZ_LEASE_BRK,		/* w */
482 	    Epoch,			/* w */
483 	    Flags,			/* l */
484 	    SMB_LEASE_KEY_SZ,		/* # */
485 	    ls->ls_key,			/* c */
486 	    OldLevel,		/* cur.st  l */
487 	    NewLevel);		/* new.st  l */
488 	    /* reserved (4.4.4.) */
489 }
490 
491 /*
492  * Do our best to send a lease break message to the client.
493  * When we get to multi-channel, this is supposed to try
494  * every channel before giving up.  For now, try every
495  * connected session with an ofile sharing this lease.
496  *
497  * If this ofile has a valid session, try that first.
498  * Otherwise look on the node list for other ofiles with
499  * the same lease and a connected session.
500  */
501 static int
502 lease_send_any_cn(smb_request_t *sr)
503 {
504 	smb_ofile_t	*o;
505 	smb_ofile_t	*ofile = sr->fid_ofile;
506 	smb_lease_t	*lease = ofile->f_lease;
507 	smb_node_t	*node = ofile->f_node;
508 	int		rc = ENOTCONN;
509 
510 	/*
511 	 * If the passed oplock ofile has a session,
512 	 * this IF expression will be true.
513 	 */
514 	if (sr->session == ofile->f_session) {
515 		rc = smb_session_send(sr->session, 0, &sr->reply);
516 		if (rc == 0)
517 			return (rc);
518 	}
519 
520 	smb_llist_enter(&node->n_ofile_list, RW_READER);
521 	FOREACH_NODE_OFILE(node, o) {
522 		if (o->f_lease != lease)
523 			continue;
524 		if (smb_ofile_hold(o)) {
525 			/* Has a session. */
526 			rc = smb_session_send(o->f_session, 0, &sr->reply);
527 			smb_llist_post(&node->n_ofile_list, o,
528 			    smb_ofile_release_LL);
529 		}
530 		if (rc == 0)
531 			break;
532 	}
533 	smb_llist_exit(&node->n_ofile_list);
534 
535 	return (rc);
536 }
537 
538 /*
539  * See smb_llist_post on node->n_ofile_list below.
540  * Can't call smb_ofile_close with that list entered.
541  */
542 static void
543 lease_ofile_close_rele(void *arg)
544 {
545 	smb_ofile_t *of = (smb_ofile_t *)arg;
546 
547 	smb_ofile_close(of, 0);
548 	smb_ofile_release(of);
549 }
550 
551 /*
552  * [MS-SMB2] 3.3.4.7 Object Store Indicates a Lease Break
553  * If no connection, for each Open in Lease.LeaseOpens,
554  * the server MUST close the Open as specified in sec...
555  * for the following cases:
556  * - Open.IsDurable, Open.IsResilient, and
557  *   Open.IsPersistent are all FALSE.
558  * - Open.IsDurable is TRUE and Lease.BreakToLeaseState
559  *   does not contain SMB2_LEASE_HANDLE_CACHING and
560  */
561 static void
562 lease_close_notconn(smb_request_t *sr, uint32_t NewLevel)
563 {
564 	smb_ofile_t	*o;
565 	smb_ofile_t	*ofile = sr->fid_ofile;
566 	smb_lease_t	*lease = ofile->f_lease;
567 	smb_node_t	*node = ofile->f_node;
568 
569 	smb_llist_enter(&node->n_ofile_list, RW_READER);
570 	FOREACH_NODE_OFILE(node, o) {
571 		if (o->f_lease != lease)
572 			continue;
573 		if (o->f_oplock_closing)
574 			continue;
575 		if (o->dh_persist)
576 			continue;
577 		if (o->dh_vers == SMB2_RESILIENT)
578 			continue;
579 		if (o->dh_vers == SMB2_NOT_DURABLE ||
580 		    (NewLevel & OPLOCK_LEVEL_CACHE_HANDLE) == 0) {
581 			if (smb_ofile_hold_olbrk(o)) {
582 				smb_llist_post(&node->n_ofile_list, o,
583 				    lease_ofile_close_rele);
584 			}
585 		}
586 	}
587 	smb_llist_exit(&node->n_ofile_list);
588 }
589 
590 /*
591  * Send a lease break over the wire, or if we can't,
592  * then process the lease break locally.
593  *
594  * [MS-SMB2] 3.3.4.7 Object Store Indicates a Lease Break
595  *
596  * This is mostly similar to smb2_oplock_send_break()
597  * See top comment there about the design.
598  *
599  * Differences beween a lease break and oplock break:
600  *
601  * Leases are an SMB-level mechanism whereby multiple open
602  * SMB file handles can share an oplock.  All SMB handles
603  * on the lease enjoy the same caching rights.  Down at the
604  * file-system level, just one oplock holds the cache rights
605  * for a lease, but (this is the tricky part) that oplock can
606  * MOVE among the SMB file handles sharing the lease. Such
607  * oplock moves can happen when a handle is closed (if that
608  * handle is the one with the oplock) or when a new open on
609  * the lease causes an upgrade of the caching rights.
610  *
611  * We have to deal here with lease movement because this call
612  * happens asynchronously after the smb_oplock_ind_break call,
613  * meaning that the oplock for the lease may have moved by the
614  * time this runs.  In addition, the ofile holding the oplock
615  * might not be the best one to use to send a lease break.
616  * If the oplock is held by a handle that's "orphaned" and
617  * there are other handles on the lease with active sessions,
618  * we want to send the lease break on an active session.
619  *
620  * Also note: NewLevel (as provided by smb_oplock_ind_break etc.)
621  * does NOT include the GRANULAR flag.  This level is expected to
622  * keep track of how each oplock was acquired (by lease or not)
623  * and put the GRANULAR flag back in when appropriate.
624  */
625 void
626 smb2_lease_send_break(smb_request_t *sr)
627 {
628 	smb_ofile_t	*old_ofile;
629 	smb_ofile_t	*ofile = sr->fid_ofile;
630 	smb_node_t	*node = ofile->f_node;
631 	smb_lease_t	*lease = ofile->f_lease;
632 	smb_arg_olbrk_t	*olbrk = &sr->arg.olbrk;
633 	boolean_t	AckReq = olbrk->AckRequired;
634 	uint32_t	OldLevel = olbrk->OldLevel;
635 	uint32_t	NewLevel = olbrk->NewLevel;
636 	uint32_t	status;
637 	int		rc;
638 
639 	NewLevel |= OPLOCK_LEVEL_GRANULAR;
640 
641 	/*
642 	 * Build the break message in sr->reply.
643 	 * It's free'd in smb_request_free().
644 	 * Always an SMB2 lease here.
645 	 */
646 	sr->reply.max_bytes = MLEN;
647 	smb2_lease_break_notification(sr,
648 	    OldLevel, NewLevel, lease->ls_epoch, AckReq);
649 
650 	/*
651 	 * Try to send the break message to the client,
652 	 * on any connection with this lease.
653 	 */
654 	rc = lease_send_any_cn(sr);
655 	if (rc != 0) {
656 		/*
657 		 * We were unable to send the oplock break request,
658 		 * presumably because the connection is gone.
659 		 * Close uninteresting handles.
660 		 */
661 		lease_close_notconn(sr, NewLevel);
662 		/* Note: some handles may remain on the lease. */
663 		if (!AckReq)
664 			return;
665 		/* Do local Ack below. */
666 	} else {
667 		/*
668 		 * OK, we were able to send the break message.
669 		 * If no ack. required, we're done.
670 		 */
671 		if (!AckReq)
672 			return;
673 
674 		/*
675 		 * We're expecting an ACK.  Wait in this thread
676 		 * so we can log clients that don't respond.
677 		 * Note: this can also fail for other reasons
678 		 * such as client disconnect or server shutdown.
679 		 */
680 		status = smb_oplock_wait_ack(sr, NewLevel);
681 		if (status == 0)
682 			return;
683 
684 		DTRACE_PROBE2(wait__ack__failed, smb_request_t *, sr,
685 		    uint32_t, status);
686 
687 		/*
688 		 * Will do local ack below.  Note, after timeout,
689 		 * do a break to none or "no caching" regardless
690 		 * of what the passed in cache level was.
691 		 * That means: clear all except GRANULAR.
692 		 */
693 		NewLevel = OPLOCK_LEVEL_GRANULAR;
694 	}
695 
696 	/*
697 	 * Do the ack locally.
698 	 *
699 	 * Find the ofile with the leased oplock
700 	 * (may have moved before we took locks)
701 	 */
702 	smb_llist_enter(&node->n_ofile_list, RW_READER);
703 	mutex_enter(&node->n_oplock.ol_mutex);
704 
705 	old_ofile = ofile;
706 	sr->fid_ofile = NULL;
707 	status = lease_find_oplock(sr, lease);
708 	if (status != 0) {
709 		/* put back old_ofile */
710 		sr->fid_ofile = old_ofile;
711 		goto unlock_out;
712 	}
713 	smb_llist_post(&node->n_ofile_list, old_ofile,
714 	    smb_ofile_release_LL);
715 
716 	ofile = sr->fid_ofile;
717 
718 	/*
719 	 * Now continue like the non-lease code
720 	 */
721 	ofile->f_oplock.og_breaking = B_FALSE;
722 	lease->ls_breaking = B_FALSE;
723 	cv_broadcast(&lease->ls_ack_cv);
724 
725 	status = smb_oplock_ack_break(sr, ofile, &NewLevel);
726 
727 	ofile->f_oplock.og_state = NewLevel;
728 	lease->ls_state = NewLevel;
729 	/* ls_epoch does not change here */
730 
731 	if (ofile->dh_persist)
732 		smb2_dh_update_oplock(sr, ofile);
733 
734 unlock_out:
735 	mutex_exit(&node->n_oplock.ol_mutex);
736 	smb_llist_exit(&node->n_ofile_list);
737 
738 #ifdef	DEBUG
739 	if (status != 0) {
740 		cmn_err(CE_NOTE, "clnt %s local oplock ack, status=0x%x",
741 		    sr->session->ip_addr_str, status);
742 	}
743 #endif
744 }
745 
746 /*
747  * Client has an open handle and requests a lease.
748  * Convert SMB2 lease request info in to internal form,
749  * call common oplock code, convert result to SMB2.
750  *
751  * If necessary, "go async" here (at the end).
752  */
753 void
754 smb2_lease_acquire(smb_request_t *sr)
755 {
756 	smb_arg_open_t *op = &sr->arg.open;
757 	smb_ofile_t *ofile = sr->fid_ofile;
758 	smb_lease_t *lease = ofile->f_lease;
759 	smb_node_t *node = ofile->f_node;
760 	uint32_t status = NT_STATUS_OPLOCK_NOT_GRANTED;
761 	uint32_t have, want; /* lease flags */
762 	boolean_t NewGrant = B_FALSE;
763 
764 	/* Only disk trees get oplocks. */
765 	ASSERT((sr->tid_tree->t_res_type & STYPE_MASK) == STYPE_DISKTREE);
766 
767 	/*
768 	 * Only plain files (for now).
769 	 * Later, test SMB2_CAP_DIRECTORY_LEASING
770 	 */
771 	if (!smb_node_is_file(ofile->f_node)) {
772 		op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
773 		return;
774 	}
775 
776 	if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_OPLOCKS)) {
777 		op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
778 		return;
779 	}
780 
781 	/*
782 	 * SMB2: Convert to internal form.
783 	 * Caller should have setup the lease.
784 	 */
785 	ASSERT(op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE);
786 	ASSERT(lease != NULL);
787 	if (lease == NULL) {
788 		op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
789 		return;
790 	}
791 	op->op_oplock_state = OPLOCK_LEVEL_GRANULAR |
792 	    (op->lease_state & CACHE_RWH);
793 
794 	/*
795 	 * Tree options may force shared oplocks,
796 	 * in which case we reduce the request.
797 	 */
798 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_FORCE_L2_OPLOCK)) {
799 		op->op_oplock_state &= ~WRITE_CACHING;
800 	}
801 
802 	/*
803 	 * Using the "Locks Held" (LH) variant of smb_oplock_request
804 	 * below so things won't change underfoot.
805 	 */
806 	smb_llist_enter(&node->n_ofile_list, RW_READER);
807 	mutex_enter(&node->n_oplock.ol_mutex);
808 
809 	/*
810 	 * MS-SMB2 3.3.5.9.8 and 3.3.5.9.11 Lease (V2) create contexts
811 	 *
812 	 * If the caching state requested in LeaseState of the (create ctx)
813 	 * is not a superset of Lease.LeaseState or if Lease.Breaking is TRUE,
814 	 * the server MUST NOT promote Lease.LeaseState. If the lease state
815 	 * requested is a superset of Lease.LeaseState and Lease.Breaking is
816 	 * FALSE, the server MUST request promotion of the lease state from
817 	 * the underlying object store to the new caching state.
818 	 */
819 	have = lease->ls_state & CACHE_RWH;
820 	want = op->op_oplock_state & CACHE_RWH;
821 	if ((have & ~want) != 0 || lease->ls_breaking) {
822 		op->op_oplock_state = have |
823 		    OPLOCK_LEVEL_GRANULAR;
824 		goto done;
825 	}
826 
827 	/*
828 	 * Handle oplock requests in three parts:
829 	 *	a: Requests with WRITE_CACHING
830 	 *	b: Requests with HANDLE_CACHING
831 	 *	c: Requests with READ_CACHING
832 	 * reducing the request before b and c.
833 	 *
834 	 * In each: first check if the lease grants the
835 	 * (possibly reduced) request, in which case we
836 	 * leave the lease unchanged and return what's
837 	 * granted by the lease.  Otherwise, try to get
838 	 * the oplock, and if the succeeds, wait for any
839 	 * breaks, update the lease, and return.
840 	 */
841 
842 	/*
843 	 * Try exclusive (request is RW or RWH)
844 	 */
845 	if ((op->op_oplock_state & WRITE_CACHING) != 0) {
846 		/* Alread checked (want & ~have) */
847 
848 		status = smb_oplock_request_LH(sr, ofile,
849 		    &op->op_oplock_state);
850 		if (status == NT_STATUS_SUCCESS ||
851 		    status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
852 			NewGrant = B_TRUE;
853 			goto done;
854 		}
855 
856 		/*
857 		 * We did not get the exclusive oplock.
858 		 *
859 		 * There are odd rules about lease upgrade.
860 		 * If the existing lease grants R and the
861 		 * client fails to upgrade it to "RWH"
862 		 * (presumably due to handle conflicts)
863 		 * then just return the existing lease,
864 		 * even though upgrade to RH would work.
865 		 */
866 		if (have != 0) {
867 			op->op_oplock_state = have |
868 			    OPLOCK_LEVEL_GRANULAR;
869 			goto done;
870 		}
871 
872 		/*
873 		 * Keep trying without write.
874 		 * Need to re-init op_oplock_state
875 		 */
876 		op->op_oplock_state = OPLOCK_LEVEL_GRANULAR |
877 		    (op->lease_state & CACHE_RH);
878 	}
879 
880 	/*
881 	 * Try shared ("RH")
882 	 */
883 	if ((op->op_oplock_state & HANDLE_CACHING) != 0) {
884 		want = op->op_oplock_state & CACHE_RWH;
885 		if ((want & ~have) == 0)
886 			goto done;
887 
888 		status = smb_oplock_request_LH(sr, ofile,
889 		    &op->op_oplock_state);
890 		if (status == NT_STATUS_SUCCESS ||
891 		    status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
892 			NewGrant = B_TRUE;
893 			goto done;
894 		}
895 
896 		/*
897 		 * We did not get "RH", probably because
898 		 * ther were (old style) Level II oplocks.
899 		 * Continue, try for just read.
900 		 * Again, re-init op_oplock_state
901 		 */
902 		op->op_oplock_state = OPLOCK_LEVEL_GRANULAR |
903 		    (op->lease_state & CACHE_R);
904 	}
905 
906 	/*
907 	 * Try shared ("R")
908 	 */
909 	if ((op->op_oplock_state & READ_CACHING) != 0) {
910 		want = op->op_oplock_state & CACHE_RWH;
911 		if ((want & ~have) == 0)
912 			goto done;
913 
914 		status = smb_oplock_request_LH(sr, ofile,
915 		    &op->op_oplock_state);
916 		if (status == NT_STATUS_SUCCESS ||
917 		    status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
918 			NewGrant = B_TRUE;
919 			goto done;
920 		}
921 
922 		/*
923 		 * We did not get "R".
924 		 * Fall into "none".
925 		 */
926 	}
927 
928 	/*
929 	 * None of the above were able to get an oplock.
930 	 * The lease has no caching rights, and we didn't
931 	 * add any in this request.  Return it as-is.
932 	 */
933 	op->op_oplock_state = OPLOCK_LEVEL_GRANULAR;
934 
935 done:
936 	/*
937 	 * Only success cases get here
938 	 */
939 
940 	/*
941 	 * Keep track of what we got (ofile->f_oplock.og_state etc)
942 	 * so we'll know what we had when sending a break later.
943 	 * Also keep a copy of some things in the lease.
944 	 *
945 	 * Not using og_dialect here, as ofile->f_lease tells us
946 	 * this has to be using granular oplocks.
947 	 */
948 	if (NewGrant) {
949 		ofile->f_oplock.og_state   = op->op_oplock_state;
950 		ofile->f_oplock.og_breakto = op->op_oplock_state;
951 		ofile->f_oplock.og_breaking = B_FALSE;
952 
953 		lease->ls_oplock_ofile = ofile;
954 		lease->ls_state   = ofile->f_oplock.og_state;
955 		lease->ls_breakto = ofile->f_oplock.og_breakto;
956 		lease->ls_breaking = B_FALSE;
957 		lease->ls_epoch++;
958 
959 		if (ofile->dh_persist) {
960 			smb2_dh_update_oplock(sr, ofile);
961 		}
962 	}
963 
964 	/*
965 	 * Convert internal oplock state to SMB2
966 	 */
967 	op->op_oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
968 	op->lease_state = lease->ls_state & CACHE_RWH;
969 	op->lease_flags = (lease->ls_breaking != 0) ?
970 	    SMB2_LEASE_FLAG_BREAK_IN_PROGRESS : 0;
971 	op->lease_epoch = lease->ls_epoch;
972 	op->lease_version = lease->ls_version;
973 
974 	/*
975 	 * End of lock-held region
976 	 */
977 	mutex_exit(&node->n_oplock.ol_mutex);
978 	smb_llist_exit(&node->n_ofile_list);
979 
980 	/*
981 	 * After a new oplock grant, the status return
982 	 * may indicate we need to wait for breaks.
983 	 */
984 	if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
985 		(void) smb2sr_go_async(sr);
986 		(void) smb_oplock_wait_break(sr, ofile->f_node, 0);
987 	}
988 }
989 
990 /*
991  * This ofile has a lease and is about to close.
992  * Called by smb_ofile_close when there's a lease.
993  *
994  * Note that a client may close an ofile in response to an
995  * oplock break or lease break intead of doing an Ack break,
996  * so this must wake anything that might be waiting on an ack
997  * when the last close of a lease happens.
998  *
999  * With leases, just one ofile on a lease owns the oplock.
1000  * If an ofile with a lease is closed and it's the one that
1001  * owns the oplock, try to move the oplock to another ofile
1002  * on the same lease.
1003  *
1004  * Would prefer that we could just use smb_ofile_hold_olbrk
1005  * to select a suitable destination for the move, but this
1006  * is called while holding the owning tree ofile list etc
1007  * which can cause deadlock as described in illumos 13850
1008  * when smb_ofile_hold_olbrk has to wait.  XXX todo
1009  */
1010 void
1011 smb2_lease_ofile_close(smb_ofile_t *ofile)
1012 {
1013 	smb_node_t *node = ofile->f_node;
1014 	smb_lease_t *lease = ofile->f_lease;
1015 	smb_ofile_t *o;
1016 
1017 	ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
1018 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
1019 
1020 #ifdef	DEBUG
1021 	FOREACH_NODE_OFILE(node, o) {
1022 		DTRACE_PROBE1(each_ofile, smb_ofile_t *, o);
1023 	}
1024 #endif
1025 
1026 	/*
1027 	 * If this ofile was not the oplock owner for this lease,
1028 	 * we can leave things as they are.
1029 	 */
1030 	if (lease->ls_oplock_ofile != ofile)
1031 		return;
1032 
1033 	/*
1034 	 * Find another ofile to which we can move the oplock.
1035 	 * First try for one that's open.  Usually find one.
1036 	 */
1037 	FOREACH_NODE_OFILE(node, o) {
1038 		if (o == ofile)
1039 			continue;
1040 		if (o->f_lease != lease)
1041 			continue;
1042 		if (o->f_oplock_closing)
1043 			continue;
1044 
1045 		mutex_enter(&o->f_mutex);
1046 		if (o->f_state == SMB_OFILE_STATE_OPEN) {
1047 			smb_oplock_move(node, ofile, o);
1048 			lease->ls_oplock_ofile = o;
1049 			mutex_exit(&o->f_mutex);
1050 			return;
1051 		}
1052 		mutex_exit(&o->f_mutex);
1053 	}
1054 
1055 	/*
1056 	 * Now try for one that's orphaned etc.
1057 	 */
1058 	FOREACH_NODE_OFILE(node, o) {
1059 		if (o == ofile)
1060 			continue;
1061 		if (o->f_lease != lease)
1062 			continue;
1063 		if (o->f_oplock_closing)
1064 			continue;
1065 
1066 		/*
1067 		 * Allow most states as seen in smb_ofile_hold_olbrk
1068 		 * without waiting for "_reconnect" or "_saving".
1069 		 * Skip "_expired" because that's about to close.
1070 		 * This is OK because just swapping the oplock state
1071 		 * between two ofiles does not interfere with the
1072 		 * dh_save or reconnect code paths.
1073 		 */
1074 		mutex_enter(&o->f_mutex);
1075 		switch (o->f_state) {
1076 		case SMB_OFILE_STATE_OPEN:
1077 		case SMB_OFILE_STATE_SAVE_DH:
1078 		case SMB_OFILE_STATE_SAVING:
1079 		case SMB_OFILE_STATE_ORPHANED:
1080 		case SMB_OFILE_STATE_RECONNECT:
1081 			smb_oplock_move(node, ofile, o);
1082 			lease->ls_oplock_ofile = o;
1083 			mutex_exit(&o->f_mutex);
1084 			return;
1085 		}
1086 		mutex_exit(&o->f_mutex);
1087 	}
1088 
1089 	/*
1090 	 * Normal for last close on a lease.
1091 	 * Wakeup ACK waiters too.
1092 	 */
1093 	lease->ls_state = 0;
1094 	lease->ls_breakto = 0;
1095 	lease->ls_breaking = B_FALSE;
1096 	cv_broadcast(&lease->ls_ack_cv);
1097 
1098 	lease->ls_oplock_ofile = NULL;
1099 }
1100