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>
SMB-131 Don't allow setting delete-on-close on non empty dirs
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/smb_cmn_setfile.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb_cmn_setfile.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  
    | 
      ↓ open down ↓ | 
    12 lines elided | 
    
      ↑ open up ↑ | 
  
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23      - * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
       23 + * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  24   24   */
  25   25  
  26   26  /*
  27   27   * Common functions supporting both:
  28   28   * SMB1 Trans2 Set File/Path Info,
  29   29   * SMB2 Set File Info
  30   30   */
  31   31  
  32      -#include <smbsrv/smb_kproto.h>
       32 +#include <smbsrv/smb2_kproto.h>
  33   33  #include <smbsrv/smb_fsops.h>
  34   34  
  35   35  /*
  36   36   * smb_set_basic_info
  37   37   * [MS-FSCC] 2.4.7
  38   38   *      FileBasicInformation
  39   39   *      SMB_SET_FILE_BASIC_INFO
  40   40   *      SMB_FILE_BASIC_INFORMATION
  41   41   *
  42   42   * Sets basic file/path information.
  43   43   *
  44   44   * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
  45   45   * target is not a directory.
  46   46   *
  47   47   * For compatibility with windows servers:
  48   48   * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
  49   49   *   clear (0) the file's attributes.
  50   50   * - if the specified attributes are 0 do NOT change the file's attributes.
  51   51   */
  52   52  uint32_t
  53   53  smb_set_basic_info(smb_request_t *sr, smb_setinfo_t *si)
  54   54  {
  55   55          smb_attr_t *attr = &si->si_attr;
  56   56          smb_node_t *node = si->si_node;
  57   57          uint64_t crtime, atime, mtime, ctime;
  58   58          uint32_t attributes;
  59   59          int rc;
  60   60  
  61   61          if (smb_mbc_decodef(&si->si_data, "qqqql",
  62   62              &crtime, &atime, &mtime, &ctime, &attributes) != 0)
  63   63                  return (NT_STATUS_INFO_LENGTH_MISMATCH);
  64   64  
  65   65          if ((attributes & FILE_ATTRIBUTE_DIRECTORY) &&
  66   66              (!smb_node_is_dir(node)))
  67   67                  return (NT_STATUS_INVALID_PARAMETER);
  68   68  
  69   69          bzero(attr, sizeof (*attr));
  70   70          if (atime != 0 && atime != (uint64_t)-1) {
  71   71                  smb_time_nt_to_unix(atime, &attr->sa_vattr.va_atime);
  72   72                  attr->sa_mask |= SMB_AT_ATIME;
  73   73          }
  74   74          if (mtime != 0 && mtime != (uint64_t)-1) {
  75   75                  smb_time_nt_to_unix(mtime, &attr->sa_vattr.va_mtime);
  76   76                  attr->sa_mask |= SMB_AT_MTIME;
  77   77          }
  78   78          if (ctime != 0 && ctime != (uint64_t)-1) {
  79   79                  smb_time_nt_to_unix(ctime, &attr->sa_vattr.va_ctime);
  80   80                  attr->sa_mask |= SMB_AT_CTIME;
  81   81          }
  82   82          if (crtime != 0 && crtime != (uint64_t)-1) {
  83   83                  smb_time_nt_to_unix(crtime, &attr->sa_crtime);
  84   84                  attr->sa_mask |= SMB_AT_CRTIME;
  85   85          }
  86   86  
  87   87          if (attributes != 0) {
  88   88                  attr->sa_dosattr = attributes;
  89   89                  attr->sa_mask |= SMB_AT_DOSATTR;
  90   90          }
  91   91  
  92   92          rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr);
  93   93          if (rc != 0)
  94   94                  return (smb_errno2status(rc));
  95   95  
  96   96          return (0);
  97   97  }
  98   98  
  99   99  /*
 100  100   * smb_set_eof_info
  
    | 
      ↓ open down ↓ | 
    58 lines elided | 
    
      ↑ open up ↑ | 
  
 101  101   *      FileEndOfFileInformation
 102  102   *      SMB_SET_FILE_END_OF_FILE_INFO
 103  103   *      SMB_FILE_END_OF_FILE_INFORMATION
 104  104   */
 105  105  uint32_t
 106  106  smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *si)
 107  107  {
 108  108          smb_attr_t *attr = &si->si_attr;
 109  109          smb_node_t *node = si->si_node;
 110  110          uint64_t eof;
      111 +        uint32_t status;
 111  112          int rc;
 112  113  
 113  114          if (smb_mbc_decodef(&si->si_data, "q", &eof) != 0)
 114  115                  return (NT_STATUS_INFO_LENGTH_MISMATCH);
 115  116  
 116  117          if (smb_node_is_dir(node))
 117  118                  return (NT_STATUS_INVALID_PARAMETER);
 118  119  
 119      -        /* If opened by path, break exclusive oplock */
 120      -        if (sr->fid_ofile == NULL)
 121      -                (void) smb_oplock_break(sr, node,
 122      -                    SMB_OPLOCK_BREAK_EXCLUSIVE | SMB_OPLOCK_BREAK_TO_NONE);
      120 +        status = smb_oplock_break_SETINFO(node, sr->fid_ofile,
      121 +            FileEndOfFileInformation);
      122 +        if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
      123 +                if (sr->session->dialect >= SMB_VERS_2_BASE)
      124 +                        (void) smb2sr_go_async(sr);
      125 +                (void) smb_oplock_wait_break(node, 0);
      126 +                status = 0;
      127 +        }
      128 +        if (status != 0)
      129 +                return (status);
 123  130  
 124  131          bzero(attr, sizeof (*attr));
 125  132          attr->sa_mask = SMB_AT_SIZE;
 126  133          attr->sa_vattr.va_size = (u_offset_t)eof;
 127  134          rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr);
 128  135          if (rc != 0)
 129  136                  return (smb_errno2status(rc));
 130  137  
 131      -        smb_oplock_break_levelII(node);
 132  138          return (0);
 133  139  }
 134  140  
 135  141  /*
 136  142   * smb_set_alloc_info
 137  143   *      FileAllocationInformation
 138  144   *      SMB_SET_FILE_ALLOCATION_INFO
 139  145   *      SMB_FILE_ALLOCATION_INFORMATION
 140  146   */
 141  147  uint32_t
 142  148  smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *si)
 143  149  {
 144  150          smb_attr_t *attr = &si->si_attr;
 145  151          smb_node_t *node = si->si_node;
 146  152          uint64_t allocsz;
      153 +        uint32_t status;
 147  154          int rc;
 148  155  
 149  156          if (smb_mbc_decodef(&si->si_data, "q", &allocsz) != 0)
 150  157                  return (NT_STATUS_INFO_LENGTH_MISMATCH);
 151  158  
 152  159          if (smb_node_is_dir(node))
 153  160                  return (NT_STATUS_INVALID_PARAMETER);
 154  161  
 155      -        /* If opened by path, break exclusive oplock */
 156      -        if (sr->fid_ofile == NULL)
 157      -                (void) smb_oplock_break(sr, node,
 158      -                    SMB_OPLOCK_BREAK_EXCLUSIVE | SMB_OPLOCK_BREAK_TO_NONE);
      162 +        status = smb_oplock_break_SETINFO(node, sr->fid_ofile,
      163 +            FileAllocationInformation);
      164 +        if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
      165 +                if (sr->session->dialect >= SMB_VERS_2_BASE)
      166 +                        (void) smb2sr_go_async(sr);
      167 +                (void) smb_oplock_wait_break(node, 0);
      168 +                status = 0;
      169 +        }
      170 +        if (status != 0)
      171 +                return (status);
 159  172  
 160  173          bzero(attr, sizeof (*attr));
 161  174          attr->sa_mask = SMB_AT_ALLOCSZ;
 162  175          attr->sa_allocsz = (u_offset_t)allocsz;
 163  176          rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr);
 164  177          if (rc != 0)
 165  178                  return (smb_errno2status(rc));
 166  179  
 167      -        smb_oplock_break_levelII(node);
 168  180          return (0);
 169  181  }
 170  182  
 171  183  /*
 172  184   * smb_set_disposition_info
 173  185   * See:
 174  186   *      FileDispositionInformation
 175  187   *      SMB_SET_FILE_DISPOSITION_INFO
 176  188   *      SMB_FILE_DISPOSITION_INFORMATION
 177  189   *
 178  190   * Set/Clear DELETE_ON_CLOSE flag for an open file.
 179  191   * File should have been opened with DELETE access otherwise
 180  192   * the operation is not permitted.
 181  193   *
 182  194   * NOTE: The node should be marked delete-on-close upon the receipt
 183  195   * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set.
 184  196   * It is different than both SmbNtCreateAndX and SmbNtTransact, which
 185  197   * set delete-on-close on the ofile and defer setting the flag on the
 186  198   * node until the file is closed.
 187  199   *
 188  200   * Observation of Windows 2000 indicates the following:
 189  201   *
 190  202   * 1) If a file is not opened with delete-on-close create options and
 191  203   * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo)
 192  204   * using that open file handle, any subsequent open requests will fail
 193  205   * with DELETE_PENDING.
 194  206   *
 195  207   * 2) If a file is opened with delete-on-close create options and the
 196  208   * client attempts to unset delete-on-close via Trans2SetFileInfo
 197  209   * (SetDispositionInfo) prior to the file close, any subsequent open
 198  210   * requests will still fail with DELETE_PENDING after the file is closed.
 199  211   *
 200  212   * 3) If a file is opened with delete-on-close create options and that
 201  213   * file handle (not the last open handle and the only file handle
 202  214   * with delete-on-close set) is closed. Any subsequent open requests
 203  215   * will fail with DELETE_PENDING. Unsetting delete-on-close via
  
    | 
      ↓ open down ↓ | 
    26 lines elided | 
    
      ↑ open up ↑ | 
  
 204  216   * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the
 205  217   * node delete-on-close flag, which will result in the file not being
 206  218   * removed even after the last file handle is closed.
 207  219   */
 208  220  uint32_t
 209  221  smb_set_disposition_info(smb_request_t *sr, smb_setinfo_t *si)
 210  222  {
 211  223          smb_node_t *node = si->si_node;
 212  224          smb_ofile_t *of = sr->fid_ofile;
 213  225          uint8_t         mark_delete;
      226 +        uint32_t        status;
 214  227          uint32_t        flags = 0;
 215  228  
 216  229          if (smb_mbc_decodef(&si->si_data, "b", &mark_delete) != 0)
 217  230                  return (NT_STATUS_INFO_LENGTH_MISMATCH);
 218  231  
 219  232          if ((of == NULL) || !(smb_ofile_granted_access(of) & DELETE))
 220  233                  return (NT_STATUS_ACCESS_DENIED);
 221  234  
 222      -        if (mark_delete) {
 223      -                if (SMB_TREE_SUPPORTS_CATIA(sr))
 224      -                        flags |= SMB_CATIA;
 225      -                return (smb_node_set_delete_on_close(node, of->f_cr, flags));
 226      -        } else {
      235 +        if (mark_delete == 0) {
 227  236                  smb_node_reset_delete_on_close(node);
      237 +                return (NT_STATUS_SUCCESS);
 228  238          }
 229  239  
 230      -        return (NT_STATUS_SUCCESS);
      240 +        /*
      241 +         * Break any oplock handle caching.
      242 +         */
      243 +        status = smb_oplock_break_SETINFO(node, of,
      244 +            FileDispositionInformation);
      245 +        if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
      246 +                if (sr->session->dialect >= SMB_VERS_2_BASE)
      247 +                        (void) smb2sr_go_async(sr);
      248 +                (void) smb_oplock_wait_break(node, 0);
      249 +                status = 0;
      250 +        }
      251 +        if (status != 0)
      252 +                return (status);
      253 +
      254 +        if (SMB_TREE_SUPPORTS_CATIA(sr))
      255 +                flags |= SMB_CATIA;
      256 +
      257 +        return (smb_node_set_delete_on_close(node, of->f_cr, flags));
 231  258  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX