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)

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/smbsrv/smb2_write.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb2_write.c
↓ open down ↓ 2 lines elided ↑ open up ↑
   3    3   * Common Development and Distribution License ("CDDL"), version 1.0.
   4    4   * You may only use this file in accordance with the terms of version
   5    5   * 1.0 of the CDDL.
   6    6   *
   7    7   * A full copy of the text of the CDDL should have accompanied this
   8    8   * source.  A copy of the CDDL is also available via the Internet at
   9    9   * http://www.illumos.org/license/CDDL.
  10   10   */
  11   11  
  12   12  /*
  13      - * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
       13 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  14   14   */
  15   15  
  16   16  /*
  17   17   * Dispatch function for SMB2_WRITE
  18   18   */
  19   19  
  20   20  #include <smbsrv/smb2_kproto.h>
  21   21  #include <smbsrv/smb_fsops.h>
  22   22  
       23 +boolean_t smb_allow_unbuffered = B_TRUE;
       24 +
  23   25  smb_sdrc_t
  24   26  smb2_write(smb_request_t *sr)
  25   27  {
  26   28          smb_ofile_t *of = NULL;
  27   29          smb_vdb_t *vdb = NULL;
  28   30          uint16_t StructSize;
  29   31          uint16_t DataOff;
  30   32          uint32_t Length;
  31   33          uint64_t Offset;
  32   34          smb2fid_t smb2fid;
  33   35          uint32_t Channel;
  34   36          uint32_t Remaining;
  35   37          uint16_t ChanInfoOffset;
  36   38          uint16_t ChanInfoLength;
  37   39          uint32_t Flags;
  38   40          uint32_t XferCount;
  39   41          uint32_t status;
  40   42          int data_chain_off, skip;
  41   43          int stability = 0;
  42   44          int rc = 0;
       45 +        boolean_t unbuffered = B_FALSE;
  43   46  
  44   47          /*
  45      -         * SMB2 Write request
       48 +         * Decode SMB2 Write request
  46   49           */
  47   50          rc = smb_mbc_decodef(
  48   51              &sr->smb_data,
  49   52              "wwlqqqllwwl",
  50   53              &StructSize,                /* w */
  51   54              &DataOff,                   /* w */
  52   55              &Length,                    /* l */
  53   56              &Offset,                    /* q */
  54   57              &smb2fid.persistent,        /* q */
  55   58              &smb2fid.temporal,          /* q */
  56   59              &Channel,                   /* l */
  57   60              &Remaining,                 /* l */
  58   61              &ChanInfoOffset,            /* w */
  59   62              &ChanInfoLength,            /* w */
  60   63              &Flags);                    /* l */
  61   64          if (rc)
  62   65                  return (SDRC_ERROR);
  63   66          if (StructSize != 49)
  64   67                  return (SDRC_ERROR);
  65   68  
  66      -        status = smb2sr_lookup_fid(sr, &smb2fid);
  67      -        if (status) {
  68      -                smb2sr_put_error(sr, status);
  69      -                return (SDRC_SUCCESS);
  70      -        }
  71      -        of = sr->fid_ofile;
  72      -
  73      -        if (Length > smb2_max_rwsize) {
  74      -                smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER);
  75      -                return (SDRC_SUCCESS);
  76      -        }
  77      -
  78   69          /*
  79   70           * Skip any padding before the write data.
  80   71           */
  81   72          data_chain_off = sr->smb2_cmd_hdr + DataOff;
  82   73          skip = data_chain_off - sr->smb_data.chain_offset;
  83      -        if (skip < 0) {
  84      -                smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER);
  85      -                return (SDRC_SUCCESS);
  86      -        }
  87      -        if (skip > 0) {
       74 +        if (skip < 0)
       75 +                return (SDRC_ERROR);
       76 +        if (skip > 0)
  88   77                  (void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
  89      -        }
  90   78  
  91      -        /* This is automatically free'd. */
       79 +        /*
       80 +         * Decode the write data (payload)
       81 +         * This is automatically free'd.
       82 +         */
       83 +        if (Length > smb2_max_rwsize)
       84 +                return (SDRC_ERROR);
  92   85          vdb = smb_srm_zalloc(sr, sizeof (*vdb));
  93   86          rc = smb_mbc_decodef(&sr->smb_data, "#B", Length, vdb);
  94      -        if (rc != 0 || vdb->vdb_len != Length) {
  95      -                smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER);
  96      -                return (SDRC_SUCCESS);
  97      -        }
       87 +        if (rc != 0 || vdb->vdb_len != Length)
       88 +                return (SDRC_ERROR);
  98   89          vdb->vdb_uio.uio_loffset = (offset_t)Offset;
  99   90  
       91 +        /*
       92 +         * Want FID lookup before the start probe.
       93 +         */
       94 +        status = smb2sr_lookup_fid(sr, &smb2fid);
       95 +        of = sr->fid_ofile;
       96 +
       97 +        DTRACE_SMB2_START(op__Write, smb_request_t *, sr); /* arg.rw */
       98 +
       99 +        if (status)
      100 +                goto errout; /* Bad FID */
      101 +
      102 +
 100  103          XferCount = 0;
 101  104          if (Length == 0)
 102      -                goto doreply;
      105 +                goto errout;
 103  106  
      107 +        /*
      108 +         * Unbuffered refers to the MS-FSA Write argument by the same name.
      109 +         * It indicates that the cache for this range should be flushed to disk,
      110 +         * and data written directly to disk, bypassing the cache.
      111 +         * We don't allow that degree of cache management.
      112 +         * Translate this directly as FSYNC,
      113 +         * which should at least flush the cache.
      114 +         */
      115 +
      116 +        if (smb_allow_unbuffered &&
      117 +            (Flags & SMB2_WRITEFLAG_WRITE_UNBUFFERED) != 0)
      118 +                unbuffered = B_TRUE;
      119 +
 104  120          switch (of->f_tree->t_res_type & STYPE_MASK) {
 105  121          case STYPE_DISKTREE:
 106  122          case STYPE_PRINTQ:
 107  123                  if (!smb_node_is_dir(of->f_node)) {
 108  124                          /* Check for conflicting locks. */
 109  125                          rc = smb_lock_range_access(sr, of->f_node,
 110  126                              Offset, Length, B_TRUE);
 111  127                          if (rc) {
 112  128                                  rc = ERANGE;
 113  129                                  break;
 114  130                          }
 115  131                  }
 116      -                if ((Flags & SMB2_WRITEFLAG_WRITE_THROUGH) ||
 117      -                    (of->f_node->flags & NODE_FLAGS_WRITE_THROUGH)) {
      132 +
      133 +                if (unbuffered || (Flags & SMB2_WRITEFLAG_WRITE_THROUGH) != 0 ||
      134 +                    (of->f_node->flags & NODE_FLAGS_WRITE_THROUGH) != 0) {
 118  135                          stability = FSYNC;
 119  136                  }
 120      -                rc = smb_fsop_write(sr, of->f_cr, of->f_node,
      137 +                rc = smb_fsop_write(sr, of->f_cr, of->f_node, of,
 121  138                      &vdb->vdb_uio, &XferCount, stability);
 122  139                  if (rc)
 123  140                          break;
 124  141                  of->f_written = B_TRUE;
 125      -                if (!smb_node_is_dir(of->f_node))
 126      -                        smb_oplock_break_levelII(of->f_node);
      142 +                /* This revokes read cache delegations. */
      143 +                (void) smb_oplock_break_WRITE(of->f_node, of);
 127  144                  break;
 128  145  
 129  146          case STYPE_IPC:
 130      -                rc = smb_opipe_write(sr, &vdb->vdb_uio);
      147 +                if (unbuffered || (Flags & SMB2_WRITEFLAG_WRITE_THROUGH) != 0)
      148 +                        rc = EINVAL;
      149 +                else
      150 +                        rc = smb_opipe_write(sr, &vdb->vdb_uio);
 131  151                  if (rc == 0)
 132  152                          XferCount = Length;
 133  153                  break;
 134  154  
 135  155          default:
 136  156                  rc = EACCES;
 137  157                  break;
 138  158          }
      159 +        status = smb_errno2status(rc);
 139  160  
 140      -        if (rc) {
 141      -                smb2sr_put_errno(sr, rc);
      161 +errout:
      162 +        sr->smb2_status = status;
      163 +        DTRACE_SMB2_DONE(op__Write, smb_request_t *, sr); /* arg.rw */
      164 +
      165 +        if (status) {
      166 +                smb2sr_put_error(sr, status);
 142  167                  return (SDRC_SUCCESS);
 143  168          }
 144  169  
 145  170          /*
 146      -         * SMB2 Write reply
      171 +         * Encode SMB2 Write reply
 147  172           */
 148      -doreply:
 149  173          DataOff = SMB2_HDR_SIZE + 16;
 150  174          rc = smb_mbc_encodef(
 151  175              &sr->reply, "wwlll",
 152  176              17, /* StructSize */        /* w */
 153  177              0, /* reserved */           /* w */
 154  178              XferCount,                  /* l */
 155  179              0, /* DataRemaining */      /* l */
 156  180              0); /* Channel Info */      /* l */
 157      -        if (rc)
      181 +        if (rc) {
      182 +                sr->smb2_status = NT_STATUS_INTERNAL_ERROR;
 158  183                  return (SDRC_ERROR);
      184 +        }
 159  185  
 160  186          mutex_enter(&of->f_mutex);
 161  187          of->f_seek_pos = Offset + XferCount;
 162  188          mutex_exit(&of->f_mutex);
 163  189  
 164  190          return (SDRC_SUCCESS);
 165  191  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX