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);