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