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,29 ****
* CDDL HEADER END
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
! * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
/*
* SMB: locking_andx
*
--- 19,29 ----
* CDDL HEADER END
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
! * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
/*
* SMB: locking_andx
*
*** 210,251 ****
* ERRSRV/ERRbaduid
*/
#include <smbsrv/smb_kproto.h>
smb_sdrc_t
smb_pre_locking_andx(smb_request_t *sr)
{
! DTRACE_SMB_1(op__LockingX__start, 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);
}
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;
smb_ofile_t *ofile;
uint16_t tmp_pid; /* locking uses 16-bit pids */
! uint8_t brk;
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);
--- 210,264 ----
* 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_START(op__LockingX, smb_request_t *, sr);
return (SDRC_SUCCESS);
}
void
smb_post_locking_andx(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 */
DWORD result;
int rc;
uint32_t ltype;
+ uint32_t status;
smb_ofile_t *ofile;
uint16_t tmp_pid; /* locking uses 16-bit pids */
! 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,282 ****
smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
ERRDOS, ERROR_INVALID_PARAMETER);
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) {
if (oplock_level == 0)
! brk = SMB_OPLOCK_BREAK_TO_NONE;
else
! brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
! smb_oplock_ack(ofile->f_node, ofile, brk);
if (unlock_num == 0 && lock_num == 0)
return (SDRC_NO_REPLY);
}
/*
--- 273,305 ----
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;
if (lock_type & LOCKING_ANDX_OPLOCK_RELEASE) {
+ uint32_t NewLevel;
if (oplock_level == 0)
! NewLevel = OPLOCK_LEVEL_NONE;
else
! 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,392 ****
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++) {
rc = smb_mbc_decodef(&sr->smb_data, "w2.QQ",
! &tmp_pid, &offset64, &length64);
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 */
! result = smb_lock_range(sr, offset64, length64, timeout,
! ltype);
if (result != NT_STATUS_SUCCESS) {
! smb_lock_range_error(sr, result);
return (SDRC_ERROR);
}
}
! } else {
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 */
! result = smb_unlock_range(sr, sr->fid_ofile->f_node,
! (uint64_t)offset32, (uint64_t)length32);
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 */
! result = smb_lock_range(sr, (uint64_t)offset32,
! (uint64_t)length32, timeout, ltype);
if (result != NT_STATUS_SUCCESS) {
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))
return (SDRC_ERROR);
return (SDRC_SUCCESS);
}
/*
--- 310,417 ----
smbsr_error(sr, 0, ERRDOS,
ERROR_ATOMIC_LOCKS_NOT_SUPPORTED);
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);
}
+ }
! /*
! * 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, &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);
}
}
! /*
! * 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_cancel(sr, lr->off, lr->len, lr->pid);
!
if (result != NT_STATUS_SUCCESS) {
! smbsr_error(sr, 0, ERRDOS,
! ERROR_CANCEL_VIOLATION);
return (SDRC_ERROR);
}
+ goto out;
}
!
! /*
! * Normal unlock and lock list
! */
for (i = 0; i < unlock_num; i++) {
! lr = &lrv_ul[i];
! 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++) {
! lr = &lrv_lk[i];
! 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);
}
}
! out:
! if (smbsr_encode_result(sr, 2, 0, "bb.ww",
! 2, sr->andx_com, 0x27, 0) != 0)
return (SDRC_ERROR);
return (SDRC_SUCCESS);
}
/*
*** 393,417 ****
* 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)
{
smb_ofile_t *ofile = sr->fid_ofile;
uint16_t fid;
uint8_t lock_type;
uint8_t oplock_level;
! switch (brk) {
default:
ASSERT(0);
/* FALLTHROUGH */
! case SMB_OPLOCK_BREAK_TO_NONE:
oplock_level = 0;
break;
! case SMB_OPLOCK_BREAK_TO_LEVEL_II:
oplock_level = 1;
break;
}
sr->smb_com = SMB_COM_LOCKING_ANDX;
--- 418,446 ----
* 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, uint32_t NewLevel)
{
smb_ofile_t *ofile = sr->fid_ofile;
uint16_t fid;
uint8_t lock_type;
uint8_t oplock_level;
! /*
! * Convert internal level to SMB1
! */
! switch (NewLevel) {
default:
ASSERT(0);
/* FALLTHROUGH */
! case OPLOCK_LEVEL_NONE:
oplock_level = 0;
break;
!
! case OPLOCK_LEVEL_TWO:
oplock_level = 1;
break;
}
sr->smb_com = SMB_COM_LOCKING_ANDX;