xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_lock.c (revision 8d94f651a44d41a7147253bb5dad1a53941e8f50)
1a90cf9f2SGordon Ross /*
2a90cf9f2SGordon Ross  * This file and its contents are supplied under the terms of the
3a90cf9f2SGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
4a90cf9f2SGordon Ross  * You may only use this file in accordance with the terms of version
5a90cf9f2SGordon Ross  * 1.0 of the CDDL.
6a90cf9f2SGordon Ross  *
7a90cf9f2SGordon Ross  * A full copy of the text of the CDDL should have accompanied this
8a90cf9f2SGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
9a90cf9f2SGordon Ross  * http://www.illumos.org/license/CDDL.
10a90cf9f2SGordon Ross  */
11a90cf9f2SGordon Ross 
12a90cf9f2SGordon Ross /*
13148d1a41SMatt Barden  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
14a90cf9f2SGordon Ross  */
15a90cf9f2SGordon Ross 
16a90cf9f2SGordon Ross /*
17a90cf9f2SGordon Ross  * Dispatch function for SMB2_LOCK
18a90cf9f2SGordon Ross  */
19a90cf9f2SGordon Ross 
20a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h>
21a90cf9f2SGordon Ross 
226f58980aSGordon Ross /*
236f58980aSGordon Ross  * [MS-SMB2] 2.2.26 LockSequenceIndex, LockSequenceNumber.
246f58980aSGordon Ross  */
256f58980aSGordon Ross #define	SMB2_LSN_SHIFT	4
266f58980aSGordon Ross #define	SMB2_LSN_MASK	0xf
276f58980aSGordon Ross 
280897f7fbSGordon Ross typedef struct SMB2_LOCK_ELEMENT {
29a90cf9f2SGordon Ross 	uint64_t Offset;
30a90cf9f2SGordon Ross 	uint64_t Length;
31a90cf9f2SGordon Ross 	uint32_t Flags;
32a90cf9f2SGordon Ross 	uint32_t reserved;
330897f7fbSGordon Ross } lock_elem_t;
34a90cf9f2SGordon Ross 
350897f7fbSGordon Ross static uint32_t smb2_unlock(smb_request_t *);
360897f7fbSGordon Ross static uint32_t smb2_locks(smb_request_t *);
37148d1a41SMatt Barden static uint32_t smb2_lock_blocking(smb_request_t *);
38a90cf9f2SGordon Ross 
396f58980aSGordon Ross static boolean_t smb2_lock_chk_lockseq(smb_ofile_t *, uint32_t);
406f58980aSGordon Ross static void smb2_lock_set_lockseq(smb_ofile_t *, uint32_t);
416f58980aSGordon Ross 
42a90cf9f2SGordon Ross /*
43a90cf9f2SGordon Ross  * This is a somewhat arbitrary sanity limit on the length of the
44a90cf9f2SGordon Ross  * SMB2_LOCK_ELEMENT array.  It usually has length one or two.
45a90cf9f2SGordon Ross  */
46a90cf9f2SGordon Ross int smb2_lock_max_elem = 1024;
47a90cf9f2SGordon Ross 
48a90cf9f2SGordon Ross smb_sdrc_t
smb2_lock(smb_request_t * sr)49a90cf9f2SGordon Ross smb2_lock(smb_request_t *sr)
50a90cf9f2SGordon Ross {
510897f7fbSGordon Ross 	lock_elem_t *lvec, *lk;
52a90cf9f2SGordon Ross 	smb2fid_t smb2fid;
53a90cf9f2SGordon Ross 	uint32_t LockSequence;
54a90cf9f2SGordon Ross 	uint32_t status;
55a90cf9f2SGordon Ross 	uint16_t StructSize;
56a90cf9f2SGordon Ross 	uint16_t LockCount;
57a90cf9f2SGordon Ross 	uint16_t i;
580897f7fbSGordon Ross 	int rc;
59a90cf9f2SGordon Ross 
60a90cf9f2SGordon Ross 	/*
6193bc28dbSGordon Ross 	 * Decode SMB2 Lock request
62a90cf9f2SGordon Ross 	 */
63a90cf9f2SGordon Ross 	rc = smb_mbc_decodef(
64a90cf9f2SGordon Ross 	    &sr->smb_data, "wwlqq",
65a90cf9f2SGordon Ross 	    &StructSize,		/* w */
66a90cf9f2SGordon Ross 	    &LockCount,			/* w */
67a90cf9f2SGordon Ross 	    &LockSequence,		/* l */
68a90cf9f2SGordon Ross 	    &smb2fid.persistent,	/* q */
69a90cf9f2SGordon Ross 	    &smb2fid.temporal);		/* q */
70a90cf9f2SGordon Ross 	if (rc || StructSize != 48)
71a90cf9f2SGordon Ross 		return (SDRC_ERROR);
72a90cf9f2SGordon Ross 
7393bc28dbSGordon Ross 	/*
7493bc28dbSGordon Ross 	 * Want FID lookup before the start probe.
7593bc28dbSGordon Ross 	 */
76a90cf9f2SGordon Ross 	status = smb2sr_lookup_fid(sr, &smb2fid);
7793bc28dbSGordon Ross 	DTRACE_SMB2_START(op__Lock, smb_request_t *, sr);
7893bc28dbSGordon Ross 
79a90cf9f2SGordon Ross 	if (status)
8093bc28dbSGordon Ross 		goto errout; /* Bad FID */
81a90cf9f2SGordon Ross 	if (sr->fid_ofile->f_node == NULL || LockCount == 0) {
82a90cf9f2SGordon Ross 		status = NT_STATUS_INVALID_PARAMETER;
83a90cf9f2SGordon Ross 		goto errout;
84a90cf9f2SGordon Ross 	}
85a90cf9f2SGordon Ross 	if (LockCount > smb2_lock_max_elem) {
86a90cf9f2SGordon Ross 		status = NT_STATUS_INSUFFICIENT_RESOURCES;
87a90cf9f2SGordon Ross 		goto errout;
88a90cf9f2SGordon Ross 	}
89a90cf9f2SGordon Ross 
90a90cf9f2SGordon Ross 	/*
916f58980aSGordon Ross 	 * Check the LockSequence to determine whether a previous
926f58980aSGordon Ross 	 * lock request succeeded, but the client disconnected
936f58980aSGordon Ross 	 * (retaining a durable or resilient handle).  If so, this
946f58980aSGordon Ross 	 * is a lock "replay".  We'll find the lock sequence here
956f58980aSGordon Ross 	 * and return success without processing the lock again.
966f58980aSGordon Ross 	 */
976f58980aSGordon Ross 	if (sr->session->dialect < SMB_VERS_2_1)
986f58980aSGordon Ross 		LockSequence = 0;
996f58980aSGordon Ross 	if ((sr->session->dialect == SMB_VERS_2_1) &&
1006f58980aSGordon Ross 	    sr->fid_ofile->dh_vers != SMB2_RESILIENT)
1016f58980aSGordon Ross 		LockSequence = 0;
1026f58980aSGordon Ross 	/* dialect 3.0 or later can always use LockSequence */
1036f58980aSGordon Ross 
1046f58980aSGordon Ross 	if (LockSequence != 0 &&
1056f58980aSGordon Ross 	    smb2_lock_chk_lockseq(sr->fid_ofile, LockSequence)) {
1066f58980aSGordon Ross 		status = NT_STATUS_SUCCESS;
107148d1a41SMatt Barden 		goto errout;
1086f58980aSGordon Ross 	}
1096f58980aSGordon Ross 
1106f58980aSGordon Ross 	/*
1110897f7fbSGordon Ross 	 * Parse the array of SMB2_LOCK_ELEMENT structs.
1120897f7fbSGordon Ross 	 * This array is free'd in smb_srm_fini.
113a90cf9f2SGordon Ross 	 */
1140897f7fbSGordon Ross 	lvec = smb_srm_zalloc(sr, LockCount * sizeof (*lvec));
115a90cf9f2SGordon Ross 	for (i = 0; i < LockCount; i++) {
1160897f7fbSGordon Ross 		lk = &lvec[i];
117a90cf9f2SGordon Ross 		rc = smb_mbc_decodef(
118a90cf9f2SGordon Ross 		    &sr->smb_data, "qqll",
1190897f7fbSGordon Ross 		    &lk->Offset,	/* q */
1200897f7fbSGordon Ross 		    &lk->Length,	/* q */
1210897f7fbSGordon Ross 		    &lk->Flags,		/* l */
1220897f7fbSGordon Ross 		    &lk->reserved);	/* l */
123a90cf9f2SGordon Ross 		if (rc) {
124a90cf9f2SGordon Ross 			status = NT_STATUS_INVALID_PARAMETER;
125a90cf9f2SGordon Ross 			goto errout;
126a90cf9f2SGordon Ross 		}
1270897f7fbSGordon Ross 	}
128a90cf9f2SGordon Ross 
129a90cf9f2SGordon Ross 	/*
1300897f7fbSGordon Ross 	 * [MS-SMB2] 3.3.5.14
1310897f7fbSGordon Ross 	 * If the flags of the [first element of] the Locks array
1320897f7fbSGordon Ross 	 * [has] SMB2_LOCKFLAG_UNLOCK set, the server MUST process
1330897f7fbSGordon Ross 	 * the lock array as a series of unlocks. Otherwise, it
1340897f7fbSGordon Ross 	 * MUST process the lock array as a series of lock requests.
135a90cf9f2SGordon Ross 	 */
1360897f7fbSGordon Ross 	sr->arg.lock.lvec = lvec;
1370897f7fbSGordon Ross 	sr->arg.lock.lcnt = LockCount;
1380897f7fbSGordon Ross 	sr->arg.lock.lseq = LockSequence;
1390897f7fbSGordon Ross 	if (lvec[0].Flags & SMB2_LOCKFLAG_UNLOCK) {
1400897f7fbSGordon Ross 		status = smb2_unlock(sr);
1410897f7fbSGordon Ross 	} else {
1420897f7fbSGordon Ross 		status = smb2_locks(sr);
143a90cf9f2SGordon Ross 	}
14493bc28dbSGordon Ross 
145*8d94f651SGordon Ross 	if (sr->fid_ofile->dh_persist) {
146*8d94f651SGordon Ross 		smb2_dh_update_locks(sr, sr->fid_ofile);
147*8d94f651SGordon Ross 	}
148*8d94f651SGordon Ross 
14993bc28dbSGordon Ross errout:
15093bc28dbSGordon Ross 	sr->smb2_status = status;
15193bc28dbSGordon Ross 	DTRACE_SMB2_DONE(op__Lock, smb_request_t *, sr);
15293bc28dbSGordon Ross 
15393bc28dbSGordon Ross 	if (status) {
15493bc28dbSGordon Ross 		smb2sr_put_error(sr, status);
15593bc28dbSGordon Ross 		return (SDRC_SUCCESS);
15693bc28dbSGordon Ross 	}
157a90cf9f2SGordon Ross 
158a90cf9f2SGordon Ross 	/*
159148d1a41SMatt Barden 	 * Encode SMB2 Lock reply
160a90cf9f2SGordon Ross 	 */
161a90cf9f2SGordon Ross 	(void) smb_mbc_encodef(
162a90cf9f2SGordon Ross 	    &sr->reply, "w..",
1630897f7fbSGordon Ross 	    4); /* StructSize	w */
164a90cf9f2SGordon Ross 	    /* reserved		.. */
165a90cf9f2SGordon Ross 	return (SDRC_SUCCESS);
166a90cf9f2SGordon Ross }
167a90cf9f2SGordon Ross 
1680897f7fbSGordon Ross /*
1690897f7fbSGordon Ross  * Process what should be an array of unlock requests.
1700897f7fbSGordon Ross  */
1710897f7fbSGordon Ross static uint32_t
smb2_unlock(smb_request_t * sr)1720897f7fbSGordon Ross smb2_unlock(smb_request_t *sr)
1730897f7fbSGordon Ross {
1740897f7fbSGordon Ross 	lock_elem_t *lk;
1750897f7fbSGordon Ross 	lock_elem_t *lvec = sr->arg.lock.lvec;
1760897f7fbSGordon Ross 	uint32_t LockCount = sr->arg.lock.lcnt;
1770897f7fbSGordon Ross 	uint32_t LockSequence = sr->arg.lock.lseq;
1780897f7fbSGordon Ross 	uint32_t status = 0;
1790897f7fbSGordon Ross 	uint32_t pid = 0;	/* SMB2 ignores lock PIDs. */
1800897f7fbSGordon Ross 	int i;
1810897f7fbSGordon Ross 
1820897f7fbSGordon Ross 	for (i = 0; i < LockCount; i++) {
1830897f7fbSGordon Ross 		lk = &lvec[i];
1840897f7fbSGordon Ross 
1850897f7fbSGordon Ross 		if (lk->Flags != SMB2_LOCKFLAG_UNLOCK) {
1860897f7fbSGordon Ross 			status = NT_STATUS_INVALID_PARAMETER;
1870897f7fbSGordon Ross 			break;
1880897f7fbSGordon Ross 		}
1890897f7fbSGordon Ross 
1900897f7fbSGordon Ross 		status = smb_unlock_range(sr, lk->Offset, lk->Length, pid);
1910897f7fbSGordon Ross 		if (status != 0)
1920897f7fbSGordon Ross 			break;
1930897f7fbSGordon Ross 	}
1946f58980aSGordon Ross 	if (status == 0 && LockSequence != 0) {
1956f58980aSGordon Ross 		smb2_lock_set_lockseq(sr->fid_ofile, LockSequence);
1966f58980aSGordon Ross 	}
1970897f7fbSGordon Ross 
1980897f7fbSGordon Ross 	return (status);
1990897f7fbSGordon Ross }
2000897f7fbSGordon Ross 
2010897f7fbSGordon Ross /*
2020897f7fbSGordon Ross  * Process what should be an array of lock requests.
2030897f7fbSGordon Ross  */
2040897f7fbSGordon Ross static uint32_t
smb2_locks(smb_request_t * sr)2050897f7fbSGordon Ross smb2_locks(smb_request_t *sr)
2060897f7fbSGordon Ross {
2070897f7fbSGordon Ross 	lock_elem_t *lk;
2080897f7fbSGordon Ross 	lock_elem_t *lvec = sr->arg.lock.lvec;
2090897f7fbSGordon Ross 	uint32_t LockCount = sr->arg.lock.lcnt;
2106f58980aSGordon Ross 	uint32_t LockSequence = sr->arg.lock.lseq;
2110897f7fbSGordon Ross 	uint32_t i;
2120897f7fbSGordon Ross 	uint32_t ltype;
2130897f7fbSGordon Ross 	uint32_t pid = 0;	/* SMB2 ignores lock PIDs */
2140897f7fbSGordon Ross 	uint32_t timeout = 0;
2150897f7fbSGordon Ross 	uint32_t status = 0;
2160897f7fbSGordon Ross 
2170897f7fbSGordon Ross 	for (i = 0; i < LockCount; i++) {
2180897f7fbSGordon Ross 		lk = &lvec[i];
2190897f7fbSGordon Ross 
2200897f7fbSGordon Ross 		switch (lk->Flags) {
2210897f7fbSGordon Ross 
2220897f7fbSGordon Ross 		case SMB2_LOCKFLAG_SHARED_LOCK:
2230897f7fbSGordon Ross 		case SMB2_LOCKFLAG_EXCLUSIVE_LOCK:
2240897f7fbSGordon Ross 			/*
2250897f7fbSGordon Ross 			 * Blocking locks have special rules:
2260897f7fbSGordon Ross 			 * Must be exactly one element, else
2270897f7fbSGordon Ross 			 * invalid parameter.
2280897f7fbSGordon Ross 			 */
2290897f7fbSGordon Ross 			if (i == 0 && LockCount == 1) {
230148d1a41SMatt Barden 				status = smb2_lock_blocking(sr);
2310897f7fbSGordon Ross 				return (status);
2320897f7fbSGordon Ross 			}
2330897f7fbSGordon Ross 			/* FALLTHROUGH */
2340897f7fbSGordon Ross 		case SMB2_LOCKFLAG_UNLOCK:
2350897f7fbSGordon Ross 		default:
2360897f7fbSGordon Ross 			status = NT_STATUS_INVALID_PARAMETER;
2370897f7fbSGordon Ross 			goto end_loop;
2380897f7fbSGordon Ross 
2390897f7fbSGordon Ross 		/* BEGIN CSTYLED */
2400897f7fbSGordon Ross 		case SMB2_LOCKFLAG_SHARED_LOCK |
2410897f7fbSGordon Ross 		     SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
2420897f7fbSGordon Ross 		/* END CSTYLED */
2430897f7fbSGordon Ross 			ltype = SMB_LOCK_TYPE_READONLY;
2440897f7fbSGordon Ross 			break;
2450897f7fbSGordon Ross 
2460897f7fbSGordon Ross 		/* BEGIN CSTYLED */
2470897f7fbSGordon Ross 		case SMB2_LOCKFLAG_EXCLUSIVE_LOCK |
2480897f7fbSGordon Ross 		     SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
2490897f7fbSGordon Ross 		/* END CSTYLED */
2500897f7fbSGordon Ross 			ltype = SMB_LOCK_TYPE_READWRITE;
2510897f7fbSGordon Ross 			break;
2520897f7fbSGordon Ross 		}
2530897f7fbSGordon Ross 
2540897f7fbSGordon Ross 		status = smb_lock_range(sr, lk->Offset, lk->Length, pid,
2550897f7fbSGordon Ross 		    ltype, timeout);
2560897f7fbSGordon Ross 		if (status != 0) {
2570897f7fbSGordon Ross 			goto end_loop;
2580897f7fbSGordon Ross 		}
2590897f7fbSGordon Ross 	}
2600897f7fbSGordon Ross 
2610897f7fbSGordon Ross end_loop:
2620897f7fbSGordon Ross 	if (status != 0) {
2630897f7fbSGordon Ross 		/*
2640897f7fbSGordon Ross 		 * Oh... we have to rollback.
2650897f7fbSGordon Ross 		 */
2660897f7fbSGordon Ross 		while (i > 0) {
2670897f7fbSGordon Ross 			--i;
2680897f7fbSGordon Ross 			lk = &lvec[i];
2690897f7fbSGordon Ross 			(void) smb_unlock_range(sr,
2700897f7fbSGordon Ross 			    lk->Offset, lk->Length, pid);
2710897f7fbSGordon Ross 		}
2720897f7fbSGordon Ross 	}
2736f58980aSGordon Ross 	if (status == 0 && LockSequence != 0)
2746f58980aSGordon Ross 		smb2_lock_set_lockseq(sr->fid_ofile, LockSequence);
2750897f7fbSGordon Ross 
2760897f7fbSGordon Ross 	return (status);
2770897f7fbSGordon Ross }
2780897f7fbSGordon Ross 
2790897f7fbSGordon Ross /*
280148d1a41SMatt Barden  * Handler for blocking lock requests, which may "go async".
2810897f7fbSGordon Ross  * Always exactly one lock request here.
2820897f7fbSGordon Ross  */
283148d1a41SMatt Barden static uint32_t
smb2_lock_blocking(smb_request_t * sr)284148d1a41SMatt Barden smb2_lock_blocking(smb_request_t *sr)
285a90cf9f2SGordon Ross {
2860897f7fbSGordon Ross 	lock_elem_t *lk = sr->arg.lock.lvec;
2870897f7fbSGordon Ross 	uint32_t LockCount = sr->arg.lock.lcnt;
2886f58980aSGordon Ross 	uint32_t LockSequence = sr->arg.lock.lseq;
289a90cf9f2SGordon Ross 	uint32_t status;
2900897f7fbSGordon Ross 	uint32_t ltype;
2910897f7fbSGordon Ross 	uint32_t pid = 0;	/* SMB2 ignores lock PIDs */
2920897f7fbSGordon Ross 	uint32_t timeout = UINT_MAX;
293a90cf9f2SGordon Ross 
2940897f7fbSGordon Ross 	ASSERT(sr->fid_ofile->f_node != NULL);
2950897f7fbSGordon Ross 	ASSERT(LockCount == 1);
296a90cf9f2SGordon Ross 
2970897f7fbSGordon Ross 	switch (lk->Flags) {
2980897f7fbSGordon Ross 	case SMB2_LOCKFLAG_SHARED_LOCK:
2990897f7fbSGordon Ross 		ltype = SMB_LOCK_TYPE_READONLY;
3000897f7fbSGordon Ross 		break;
3010897f7fbSGordon Ross 
3020897f7fbSGordon Ross 	case SMB2_LOCKFLAG_EXCLUSIVE_LOCK:
3030897f7fbSGordon Ross 		ltype = SMB_LOCK_TYPE_READWRITE;
3040897f7fbSGordon Ross 		break;
3050897f7fbSGordon Ross 
3060897f7fbSGordon Ross 	default:
3070897f7fbSGordon Ross 		ASSERT(0);
308148d1a41SMatt Barden 		return (NT_STATUS_INTERNAL_ERROR);
309a90cf9f2SGordon Ross 	}
310a90cf9f2SGordon Ross 
311a90cf9f2SGordon Ross 	/*
312148d1a41SMatt Barden 	 * Try the lock first with timeout=0 as we can often
313148d1a41SMatt Barden 	 * get a lock without going async and avoid an extra
314148d1a41SMatt Barden 	 * round trip with the client.  Also, only go async
315148d1a41SMatt Barden 	 * for status returns that mean we will block.
316a90cf9f2SGordon Ross 	 */
317148d1a41SMatt Barden 	status = smb_lock_range(sr, lk->Offset, lk->Length, pid, ltype, 0);
318148d1a41SMatt Barden 	if (status == NT_STATUS_LOCK_NOT_GRANTED ||
319148d1a41SMatt Barden 	    status == NT_STATUS_FILE_LOCK_CONFLICT) {
320148d1a41SMatt Barden 		status = smb2sr_go_async(sr);
321148d1a41SMatt Barden 		if (status != 0)
322148d1a41SMatt Barden 			return (status);
323148d1a41SMatt Barden 		status = smb_lock_range(sr, lk->Offset, lk->Length,
324148d1a41SMatt Barden 		    pid, ltype, timeout);
325148d1a41SMatt Barden 	}
326148d1a41SMatt Barden 
327148d1a41SMatt Barden 	if (status == 0 && LockSequence != 0)
328148d1a41SMatt Barden 		smb2_lock_set_lockseq(sr->fid_ofile, LockSequence);
329148d1a41SMatt Barden 
330148d1a41SMatt Barden 	return (status);
331a90cf9f2SGordon Ross }
3326f58980aSGordon Ross 
3336f58980aSGordon Ross /*
3346f58980aSGordon Ross  * Check whether we've stored a given LockSequence
3356f58980aSGordon Ross  *
3366f58980aSGordon Ross  * [MS-SMB2] 3.3.5.14
3376f58980aSGordon Ross  *
3386f58980aSGordon Ross  * The server verifies the LockSequence by performing the following steps:
3396f58980aSGordon Ross  *
3406f58980aSGordon Ross  * 1. The server MUST use LockSequenceIndex as an index into the
3416f58980aSGordon Ross  * Open.LockSequenceArray in order to locate the sequence number entry.
3426f58980aSGordon Ross  * If the index exceeds the maximum extent of the Open.LockSequenceArray,
3436f58980aSGordon Ross  * or LockSequenceIndex is 0, or if the sequence number entry is empty,
3446f58980aSGordon Ross  * the server MUST skip step 2 and continue lock/unlock processing.
3456f58980aSGordon Ross  *
3466f58980aSGordon Ross  * 2. The server MUST compare LockSequenceNumber to the SequenceNumber of
3476f58980aSGordon Ross  * the entry located in step 1. If the sequence numbers are equal, the
3486f58980aSGordon Ross  * server MUST complete the lock/unlock request with success. Otherwise,
3496f58980aSGordon Ross  * the server MUST reset the entry value to empty and continue lock/unlock
3506f58980aSGordon Ross  * processing.
3516f58980aSGordon Ross  */
3526f58980aSGordon Ross boolean_t
smb2_lock_chk_lockseq(smb_ofile_t * ofile,uint32_t lockseq)3536f58980aSGordon Ross smb2_lock_chk_lockseq(smb_ofile_t *ofile, uint32_t lockseq)
3546f58980aSGordon Ross {
3556f58980aSGordon Ross 	uint32_t lsi;
3566f58980aSGordon Ross 	uint8_t lsn;
3576f58980aSGordon Ross 	boolean_t rv;
3586f58980aSGordon Ross 
3596f58980aSGordon Ross 	/*
3606f58980aSGordon Ross 	 * LockSequenceNumber is the low four bits.
3616f58980aSGordon Ross 	 * LockSequenceIndex is the remaining 28 bits.
3626f58980aSGordon Ross 	 * valid range is 1..64, which we convert to an
3636f58980aSGordon Ross 	 * array index in the range 0..63
3646f58980aSGordon Ross 	 */
3656f58980aSGordon Ross 	lsn = lockseq & SMB2_LSN_MASK;
3666f58980aSGordon Ross 	lsi = (lockseq >> SMB2_LSN_SHIFT);
3676f58980aSGordon Ross 	if (lsi == 0 || lsi > SMB_OFILE_LSEQ_MAX)
3686f58980aSGordon Ross 		return (B_FALSE);
3696f58980aSGordon Ross 	--lsi;
3706f58980aSGordon Ross 
3716f58980aSGordon Ross 	mutex_enter(&ofile->f_mutex);
3726f58980aSGordon Ross 
3736f58980aSGordon Ross 	if (ofile->f_lock_seq[lsi] == lsn) {
3746f58980aSGordon Ross 		rv = B_TRUE;
3756f58980aSGordon Ross 	} else {
3766f58980aSGordon Ross 		ofile->f_lock_seq[lsi] = (uint8_t)-1;	/* "Empty" */
3776f58980aSGordon Ross 		rv = B_FALSE;
3786f58980aSGordon Ross 	}
3796f58980aSGordon Ross 
3806f58980aSGordon Ross 	mutex_exit(&ofile->f_mutex);
3816f58980aSGordon Ross 
3826f58980aSGordon Ross 	return (rv);
3836f58980aSGordon Ross }
3846f58980aSGordon Ross 
3856f58980aSGordon Ross static void
smb2_lock_set_lockseq(smb_ofile_t * ofile,uint32_t lockseq)3866f58980aSGordon Ross smb2_lock_set_lockseq(smb_ofile_t *ofile, uint32_t lockseq)
3876f58980aSGordon Ross {
3886f58980aSGordon Ross 	uint32_t lsi;
3896f58980aSGordon Ross 	uint8_t lsn;
3906f58980aSGordon Ross 
3916f58980aSGordon Ross 	/*
3926f58980aSGordon Ross 	 * LockSequenceNumber is the low four bits.
3936f58980aSGordon Ross 	 * LockSequenceIndex is the remaining 28 bits.
3946f58980aSGordon Ross 	 * valid range is 1..64, which we convert to an
3956f58980aSGordon Ross 	 * array index in the range 0..63
3966f58980aSGordon Ross 	 */
3976f58980aSGordon Ross 	lsn = lockseq & SMB2_LSN_MASK;
3986f58980aSGordon Ross 	lsi = (lockseq >> SMB2_LSN_SHIFT);
3996f58980aSGordon Ross 	if (lsi == 0 || lsi > SMB_OFILE_LSEQ_MAX) {
4006f58980aSGordon Ross 		cmn_err(CE_NOTE, "smb2_lock_set_lockseq, index=%u", lsi);
4016f58980aSGordon Ross 		return;
4026f58980aSGordon Ross 	}
4036f58980aSGordon Ross 	--lsi;
4046f58980aSGordon Ross 
4056f58980aSGordon Ross 	mutex_enter(&ofile->f_mutex);
4066f58980aSGordon Ross 
4076f58980aSGordon Ross 	ofile->f_lock_seq[lsi] = lsn;
4086f58980aSGordon Ross 
4096f58980aSGordon Ross 	mutex_exit(&ofile->f_mutex);
4106f58980aSGordon Ross }
411