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-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>
NEX-3662 Backport illumos 1501: taskq_create_proc ... TQ_DYNAMIC puts tasks in p0 (take 2)
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Marcel Telka <marcel.telka@nexenta.com>
NEX-3576 RPC error when displaying open files via Windows MMC
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-2188 Browsing top level share produces RPC error 1728
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,28 +8,31 @@
  * source.  A copy of the CDDL is also available via the Internet at
  * http://www.illumos.org/license/CDDL.
  */
 
 /*
- * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
  * Dispatch function for SMB2_READ
  */
 
 #include <smbsrv/smb2_kproto.h>
 #include <smbsrv/smb_fsops.h>
 
+extern boolean_t smb_allow_unbuffered;
+
 smb_sdrc_t
 smb2_read(smb_request_t *sr)
 {
         smb_ofile_t *of = NULL;
         smb_vdb_t *vdb = NULL;
         struct mbuf *m = NULL;
         uint16_t StructSize;
         uint8_t Padding;
+        uint8_t Flags;
         uint8_t DataOff;
         uint32_t Length;
         uint64_t Offset;
         smb2fid_t smb2fid;
         uint32_t MinCount;

@@ -38,19 +41,22 @@
         uint16_t ChanInfoOffset;
         uint16_t ChanInfoLength;
         uint32_t XferCount;
         uint32_t status;
         int rc = 0;
+        boolean_t unbuffered = B_FALSE;
+        int ioflag = 0;
 
         /*
          * SMB2 Read request
          */
         rc = smb_mbc_decodef(
             &sr->smb_data,
-            "wb.lqqqlllww",
+            "wbblqqqlllww",
             &StructSize,                /* w */
-            &Padding,                   /* b. */
+            &Padding,                   /* b */
+            &Flags,                     /* b */
             &Length,                    /* l */
             &Offset,                    /* q */
             &smb2fid.persistent,        /* q */
             &smb2fid.temporal,          /* q */
             &MinCount,                  /* l */

@@ -61,20 +67,24 @@
         if (rc)
                 return (SDRC_ERROR);
         if (StructSize != 49)
                 return (SDRC_ERROR);
 
+        /*
+         * Want FID lookup before the start probe.
+         */
         status = smb2sr_lookup_fid(sr, &smb2fid);
-        if (status) {
-                smb2sr_put_error(sr, status);
-                return (SDRC_SUCCESS);
-        }
         of = sr->fid_ofile;
 
+        DTRACE_SMB2_START(op__Read, smb_request_t *, sr); /* arg.rw */
+
+        if (status)
+                goto errout; /* Bad FID */
+
         if (Length > smb2_max_rwsize) {
-                smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER);
-                return (SDRC_SUCCESS);
+                status = NT_STATUS_INVALID_PARAMETER;
+                goto errout;
         }
         if (MinCount > Length)
                 MinCount = Length;
 
         /* This is automatically free'd. */

@@ -88,10 +98,25 @@
         vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
 
         sr->raw_data.max_bytes = Length;
         m = smb_mbuf_allocate(&vdb->vdb_uio);
 
+        /*
+         * Unbuffered refers to the MS-FSA Read argument by the same name.
+         * It indicates that the cache for this range should be flushed to disk,
+         * and data read directly from disk, bypassing the cache.
+         * We don't allow that degree of cache management.
+         * Translate this directly as FRSYNC,
+         * which should at least flush the cache first.
+         */
+
+        if (smb_allow_unbuffered &&
+            (Flags & SMB2_READFLAG_READ_UNBUFFERED) != 0) {
+                unbuffered = B_TRUE;
+                ioflag = FRSYNC;
+        }
+
         switch (of->f_tree->t_res_type & STYPE_MASK) {
         case STYPE_DISKTREE:
                 if (!smb_node_is_dir(of->f_node)) {
                         /* Check for conflicting locks. */
                         rc = smb_lock_range_access(sr, of->f_node,

@@ -99,20 +124,25 @@
                         if (rc) {
                                 rc = ERANGE;
                                 break;
                         }
                 }
-                rc = smb_fsop_read(sr, of->f_cr, of->f_node, &vdb->vdb_uio);
+                rc = smb_fsop_read(sr, of->f_cr, of->f_node, of,
+                    &vdb->vdb_uio, ioflag);
                 break;
         case STYPE_IPC:
+                if (unbuffered)
+                        rc = EINVAL;
+                else
                 rc = smb_opipe_read(sr, &vdb->vdb_uio);
                 break;
         default:
         case STYPE_PRINTQ:
                 rc = EACCES;
                 break;
         }
+        status = smb_errno2status(rc);
 
         /* How much data we moved. */
         XferCount = Length - vdb->vdb_uio.uio_resid;
 
         sr->raw_data.max_bytes = XferCount;

@@ -122,12 +152,15 @@
         /*
          * Checking the error return _after_ dealing with
          * the returned data so that if m was allocated,
          * it will be free'd via sr->raw_data cleanup.
          */
-        if (rc) {
-                smb2sr_put_errno(sr, rc);
+errout:
+        sr->smb2_status = status;
+        DTRACE_SMB2_DONE(op__Read, smb_request_t *, sr); /* arg.rw */
+        if (status) {
+                smb2sr_put_error(sr, status);
                 return (SDRC_SUCCESS);
         }
 
         /*
          * SMB2 Read reply

@@ -140,12 +173,14 @@
             DataOff,                    /* b. */
             XferCount,                  /* l */
             0, /* DataRemaining */      /* l */
             0, /* reserved */           /* l */
             &sr->raw_data);             /* C */
-        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);