Print this page
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-1643 dtrace provider for smbsrv
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-6041 Should pass the smbtorture lock tests
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-1192 add context options to xpg4 grep (nits)
NEX-1192 add context options to xpg4 grep
SUP-867 panic in smb_com_locking_andx
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
@@ -19,11 +19,11 @@
* CDDL HEADER END
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
/*
* SMB: locking_andx
*
@@ -210,42 +210,55 @@
* ERRSRV/ERRbaduid
*/
#include <smbsrv/smb_kproto.h>
+/*
+ * This is a somewhat arbitrary sanity limit on the length of the
+ * SMB2_LOCK_ELEMENT array. It usually has length one or two.
+ */
+int smb_lock_max_elem = 1024;
+
smb_sdrc_t
smb_pre_locking_andx(smb_request_t *sr)
{
- DTRACE_SMB_1(op__LockingX__start, smb_request_t *, sr);
+ DTRACE_SMB_START(op__LockingX, smb_request_t *, sr);
return (SDRC_SUCCESS);
}
void
smb_post_locking_andx(smb_request_t *sr)
{
- DTRACE_SMB_1(op__LockingX__done, smb_request_t *, sr);
+ DTRACE_SMB_DONE(op__LockingX, smb_request_t *, sr);
}
+struct lreq {
+ uint64_t off;
+ uint64_t len;
+ uint32_t pid;
+ uint32_t _x;
+};
+
smb_sdrc_t
smb_com_locking_andx(smb_request_t *sr)
{
unsigned short i;
unsigned char lock_type; /* See lock_type table above */
unsigned char oplock_level; /* The new oplock level */
uint32_t timeout; /* Milliseconds to wait for lock */
unsigned short unlock_num; /* # unlock range structs */
unsigned short lock_num; /* # lock range structs */
- uint32_t save_pid; /* Process Id of owner */
- uint32_t offset32, length32;
- uint64_t offset64;
- uint64_t length64;
DWORD result;
int rc;
uint32_t ltype;
+ uint32_t status;
smb_ofile_t *ofile;
uint16_t tmp_pid; /* locking uses 16-bit pids */
- uint8_t brk;
+ uint32_t lrv_tot;
+ struct lreq *lrv_ul;
+ struct lreq *lrv_lk;
+ struct lreq *lr;
rc = smbsr_decode_vwv(sr, "4.wbblww", &sr->smb_fid, &lock_type,
&oplock_level, &timeout, &unlock_num, &lock_num);
if (rc != 0)
return (SDRC_ERROR);
@@ -260,23 +273,33 @@
smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
ERRDOS, ERROR_INVALID_PARAMETER);
return (SDRC_ERROR);
}
+ if (unlock_num > smb_lock_max_elem ||
+ lock_num > smb_lock_max_elem) {
+ smbsr_error(sr, NT_STATUS_INSUFFICIENT_RESOURCES,
+ ERRDOS, ERROR_NO_SYSTEM_RESOURCES);
+ return (SDRC_ERROR);
+ }
+
if (lock_type & LOCKING_ANDX_SHARED_LOCK)
ltype = SMB_LOCK_TYPE_READONLY;
else
ltype = SMB_LOCK_TYPE_READWRITE;
- save_pid = sr->smb_pid; /* Save the original pid */
-
if (lock_type & LOCKING_ANDX_OPLOCK_RELEASE) {
+ uint32_t NewLevel;
if (oplock_level == 0)
- brk = SMB_OPLOCK_BREAK_TO_NONE;
+ NewLevel = OPLOCK_LEVEL_NONE;
else
- brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
- smb_oplock_ack(ofile->f_node, ofile, brk);
+ NewLevel = OPLOCK_LEVEL_TWO;
+ status = smb_oplock_ack_break(sr, ofile, &NewLevel);
+ if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
+ (void) smb_oplock_wait_break(ofile->f_node, 0);
+ status = 0;
+ }
if (unlock_num == 0 && lock_num == 0)
return (SDRC_NO_REPLY);
}
/*
@@ -287,106 +310,108 @@
smbsr_error(sr, 0, ERRDOS,
ERROR_ATOMIC_LOCKS_NOT_SUPPORTED);
return (SDRC_ERROR);
}
- /*
- * No support for cancel lock (smbtorture expects this)
- */
- if (lock_type & LOCKING_ANDX_CANCEL_LOCK) {
- smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
- ERRDOS, ERROR_INVALID_PARAMETER);
- return (SDRC_ERROR);
- }
-
if (lock_type & LOCKING_ANDX_LARGE_FILES) {
/*
* negotiated protocol should be NT LM 0.12 or later
*/
if (sr->session->dialect < NT_LM_0_12) {
smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
ERRDOS, ERROR_INVALID_PARAMETER);
return (SDRC_ERROR);
}
+ }
- for (i = 0; i < unlock_num; i++) {
+ /*
+ * Parse the unlock, lock vectors. Will parse all the
+ * unlock + lock records into one array, and then use
+ * pointers to the unlock and lock parts.
+ */
+ lrv_tot = unlock_num + lock_num;
+ lrv_ul = smb_srm_zalloc(sr, lrv_tot * sizeof (*lrv_ul));
+ lrv_lk = &lrv_ul[unlock_num];
+
+ for (i = 0; i < lrv_tot; i++) {
+ lr = &lrv_ul[i];
+ if (lock_type & LOCKING_ANDX_LARGE_FILES) {
rc = smb_mbc_decodef(&sr->smb_data, "w2.QQ",
- &tmp_pid, &offset64, &length64);
+ &tmp_pid, &lr->off, &lr->len);
+ } else {
+ uint32_t offset32, length32;
+ rc = smb_mbc_decodef(&sr->smb_data, "wll",
+ &tmp_pid, &offset32, &length32);
+ lr->off = offset32;
+ lr->len = length32;
+ }
+ lr->pid = tmp_pid; /* 16-bit PID */
if (rc) {
/*
* This is the error returned by Windows 2000
* even when STATUS32 has been negotiated.
*/
smbsr_error(sr, 0, ERRSRV, ERRerror);
return (SDRC_ERROR);
}
- sr->smb_pid = tmp_pid; /* NB: 16-bit */
-
- result = smb_unlock_range(sr, sr->fid_ofile->f_node,
- offset64, length64);
- if (result != NT_STATUS_SUCCESS) {
- smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
- ERRDOS, ERROR_NOT_LOCKED);
- return (SDRC_ERROR);
}
- }
- for (i = 0; i < lock_num; i++) {
- rc = smb_mbc_decodef(&sr->smb_data, "w2.QQ",
- &tmp_pid, &offset64, &length64);
- if (rc) {
- smbsr_error(sr, 0, ERRSRV, ERRerror);
- return (SDRC_ERROR);
- }
- sr->smb_pid = tmp_pid; /* NB: 16-bit */
+ /*
+ * Cancel waiting locks. MS-CIFS says one place that
+ * this cancels all waiting locks for this FID+PID,
+ * but smbtorture insists this cancels just one.
+ * Tests with Windows 7 confirms that.
+ */
+ if ((lock_type & LOCKING_ANDX_CANCEL_LOCK) != 0) {
+ lr = lrv_lk;
- result = smb_lock_range(sr, offset64, length64, timeout,
- ltype);
+ result = smb_lock_range_cancel(sr, lr->off, lr->len, lr->pid);
+
if (result != NT_STATUS_SUCCESS) {
- smb_lock_range_error(sr, result);
+ smbsr_error(sr, 0, ERRDOS,
+ ERROR_CANCEL_VIOLATION);
return (SDRC_ERROR);
}
+ goto out;
}
- } else {
+
+ /*
+ * Normal unlock and lock list
+ */
for (i = 0; i < unlock_num; i++) {
- rc = smb_mbc_decodef(&sr->smb_data, "wll", &tmp_pid,
- &offset32, &length32);
- if (rc) {
- smbsr_error(sr, 0, ERRSRV, ERRerror);
- return (SDRC_ERROR);
- }
- sr->smb_pid = tmp_pid; /* NB: 16-bit */
+ lr = &lrv_ul[i];
- result = smb_unlock_range(sr, sr->fid_ofile->f_node,
- (uint64_t)offset32, (uint64_t)length32);
+ result = smb_unlock_range(sr, lr->off, lr->len, lr->pid);
if (result != NT_STATUS_SUCCESS) {
smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
ERRDOS, ERROR_NOT_LOCKED);
return (SDRC_ERROR);
}
}
-
for (i = 0; i < lock_num; i++) {
- rc = smb_mbc_decodef(&sr->smb_data, "wll", &tmp_pid,
- &offset32, &length32);
- if (rc) {
- smbsr_error(sr, 0, ERRSRV, ERRerror);
- return (SDRC_ERROR);
- }
- sr->smb_pid = tmp_pid; /* NB: 16-bit */
+ lr = &lrv_lk[i];
- result = smb_lock_range(sr, (uint64_t)offset32,
- (uint64_t)length32, timeout, ltype);
+ result = smb_lock_range(sr, lr->off, lr->len, lr->pid,
+ ltype, timeout);
if (result != NT_STATUS_SUCCESS) {
+ /*
+ * Oh... we have to rollback.
+ */
+ while (i > 0) {
+ --i;
+ lr = &lrv_lk[i];
+ (void) smb_unlock_range(sr,
+ lr->off, lr->len, lr->pid);
+ }
smb_lock_range_error(sr, result);
return (SDRC_ERROR);
}
}
- }
- sr->smb_pid = save_pid;
- if (smbsr_encode_result(sr, 2, 0, "bb.ww", 2, sr->andx_com, 7, 0))
+out:
+ if (smbsr_encode_result(sr, 2, 0, "bb.ww",
+ 2, sr->andx_com, 0x27, 0) != 0)
return (SDRC_ERROR);
return (SDRC_SUCCESS);
}
/*
@@ -393,25 +418,29 @@
* Compose an SMB1 Oplock Break Notification packet, including
* the SMB1 header and everything, in sr->reply.
* The caller will send it and free the request.
*/
void
-smb1_oplock_break_notification(smb_request_t *sr, uint8_t brk)
+smb1_oplock_break_notification(smb_request_t *sr, uint32_t NewLevel)
{
smb_ofile_t *ofile = sr->fid_ofile;
uint16_t fid;
uint8_t lock_type;
uint8_t oplock_level;
- switch (brk) {
+ /*
+ * Convert internal level to SMB1
+ */
+ switch (NewLevel) {
default:
ASSERT(0);
/* FALLTHROUGH */
- case SMB_OPLOCK_BREAK_TO_NONE:
+ case OPLOCK_LEVEL_NONE:
oplock_level = 0;
break;
- case SMB_OPLOCK_BREAK_TO_LEVEL_II:
+
+ case OPLOCK_LEVEL_TWO:
oplock_level = 1;
break;
}
sr->smb_com = SMB_COM_LOCKING_ANDX;