Print this page
NEX-17289 Minimal SMB 3.0.2 support
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@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-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-5844 want SMB2 ioctl FSCTL_SRV_COPYCHUNK
NEX-6124 smb_fsop_read/write should allow file != sr->fid_ofile
NEX-6125 smbtorture invalid response with smb2.ioctl
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
SMB-119 Text file contains garbage when re-opened
SMB-120 Share enumeration fails with Windows 8
SMB-122 smbd core dumps in smbd_dc_update / smb_log
SMB-117 Win7 fails to open security properties
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)
@@ -8,20 +8,22 @@
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*/
/*
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Dispatch function for SMB2_WRITE
*/
#include <smbsrv/smb2_kproto.h>
#include <smbsrv/smb_fsops.h>
+boolean_t smb_allow_unbuffered = B_TRUE;
+
smb_sdrc_t
smb2_write(smb_request_t *sr)
{
smb_ofile_t *of = NULL;
smb_vdb_t *vdb = NULL;
@@ -38,13 +40,14 @@
uint32_t XferCount;
uint32_t status;
int data_chain_off, skip;
int stability = 0;
int rc = 0;
+ boolean_t unbuffered = B_FALSE;
/*
- * SMB2 Write request
+ * Decode SMB2 Write request
*/
rc = smb_mbc_decodef(
&sr->smb_data,
"wwlqqqllwwl",
&StructSize, /* w */
@@ -61,48 +64,61 @@
if (rc)
return (SDRC_ERROR);
if (StructSize != 49)
return (SDRC_ERROR);
- status = smb2sr_lookup_fid(sr, &smb2fid);
- if (status) {
- smb2sr_put_error(sr, status);
- return (SDRC_SUCCESS);
- }
- of = sr->fid_ofile;
-
- if (Length > smb2_max_rwsize) {
- smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER);
- return (SDRC_SUCCESS);
- }
-
/*
* Skip any padding before the write data.
*/
data_chain_off = sr->smb2_cmd_hdr + DataOff;
skip = data_chain_off - sr->smb_data.chain_offset;
- if (skip < 0) {
- smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER);
- return (SDRC_SUCCESS);
- }
- if (skip > 0) {
+ if (skip < 0)
+ return (SDRC_ERROR);
+ if (skip > 0)
(void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
- }
- /* This is automatically free'd. */
+ /*
+ * Decode the write data (payload)
+ * This is automatically free'd.
+ */
+ if (Length > smb2_max_rwsize)
+ return (SDRC_ERROR);
vdb = smb_srm_zalloc(sr, sizeof (*vdb));
rc = smb_mbc_decodef(&sr->smb_data, "#B", Length, vdb);
- if (rc != 0 || vdb->vdb_len != Length) {
- smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER);
- return (SDRC_SUCCESS);
- }
+ if (rc != 0 || vdb->vdb_len != Length)
+ return (SDRC_ERROR);
vdb->vdb_uio.uio_loffset = (offset_t)Offset;
+ /*
+ * Want FID lookup before the start probe.
+ */
+ status = smb2sr_lookup_fid(sr, &smb2fid);
+ of = sr->fid_ofile;
+
+ DTRACE_SMB2_START(op__Write, smb_request_t *, sr); /* arg.rw */
+
+ if (status)
+ goto errout; /* Bad FID */
+
+
XferCount = 0;
if (Length == 0)
- goto doreply;
+ goto errout;
+ /*
+ * Unbuffered refers to the MS-FSA Write argument by the same name.
+ * It indicates that the cache for this range should be flushed to disk,
+ * and data written directly to disk, bypassing the cache.
+ * We don't allow that degree of cache management.
+ * Translate this directly as FSYNC,
+ * which should at least flush the cache.
+ */
+
+ if (smb_allow_unbuffered &&
+ (Flags & SMB2_WRITEFLAG_WRITE_UNBUFFERED) != 0)
+ unbuffered = B_TRUE;
+
switch (of->f_tree->t_res_type & STYPE_MASK) {
case STYPE_DISKTREE:
case STYPE_PRINTQ:
if (!smb_node_is_dir(of->f_node)) {
/* Check for conflicting locks. */
@@ -111,53 +127,63 @@
if (rc) {
rc = ERANGE;
break;
}
}
- if ((Flags & SMB2_WRITEFLAG_WRITE_THROUGH) ||
- (of->f_node->flags & NODE_FLAGS_WRITE_THROUGH)) {
+
+ if (unbuffered || (Flags & SMB2_WRITEFLAG_WRITE_THROUGH) != 0 ||
+ (of->f_node->flags & NODE_FLAGS_WRITE_THROUGH) != 0) {
stability = FSYNC;
}
- rc = smb_fsop_write(sr, of->f_cr, of->f_node,
+ rc = smb_fsop_write(sr, of->f_cr, of->f_node, of,
&vdb->vdb_uio, &XferCount, stability);
if (rc)
break;
of->f_written = B_TRUE;
- if (!smb_node_is_dir(of->f_node))
- smb_oplock_break_levelII(of->f_node);
+ /* This revokes read cache delegations. */
+ (void) smb_oplock_break_WRITE(of->f_node, of);
break;
case STYPE_IPC:
+ if (unbuffered || (Flags & SMB2_WRITEFLAG_WRITE_THROUGH) != 0)
+ rc = EINVAL;
+ else
rc = smb_opipe_write(sr, &vdb->vdb_uio);
if (rc == 0)
XferCount = Length;
break;
default:
rc = EACCES;
break;
}
+ status = smb_errno2status(rc);
- if (rc) {
- smb2sr_put_errno(sr, rc);
+errout:
+ sr->smb2_status = status;
+ DTRACE_SMB2_DONE(op__Write, smb_request_t *, sr); /* arg.rw */
+
+ if (status) {
+ smb2sr_put_error(sr, status);
return (SDRC_SUCCESS);
}
/*
- * SMB2 Write reply
+ * Encode SMB2 Write reply
*/
-doreply:
DataOff = SMB2_HDR_SIZE + 16;
rc = smb_mbc_encodef(
&sr->reply, "wwlll",
17, /* StructSize */ /* w */
0, /* reserved */ /* w */
XferCount, /* l */
0, /* DataRemaining */ /* l */
0); /* Channel Info */ /* l */
- if (rc)
+ if (rc) {
+ sr->smb2_status = NT_STATUS_INTERNAL_ERROR;
return (SDRC_ERROR);
+ }
mutex_enter(&of->f_mutex);
of->f_seek_pos = Offset + XferCount;
mutex_exit(&of->f_mutex);