Print this page
    
NEX-15680 Implement SMB2 getinfo FS level FileFsSectorSizeInformation
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15680 Implement SMB2 getinfo FS level FileFsSectorSizeInformation
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5598 SMB needs a few more ioctls for Hyper-V
Reviewed by: Gordon Ross <gwr@nexenta.com>
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_qinfo_fs.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb2_qinfo_fs.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 2013 Nexenta Systems, Inc.  All rights reserved.
       23 + * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  24   24   */
  25   25  
  26   26  /*
  27   27   * Dispatch function for SMB2_QUERY_INFO
  28   28   *
  29   29   * [MS-FSCC 2.5] If a file system does not implement ...
  30   30   * an Information Classs, NT_STATUS_INVALID_PARAMETER...
  31   31   */
  32   32  
  33   33  #include <smbsrv/smb2_kproto.h>
  34   34  #include <smbsrv/smb_fsops.h>
  35   35  #include <smbsrv/ntifs.h>
  36   36  
  37   37  uint32_t smb2_qfs_volume(smb_request_t *);
  38   38  uint32_t smb2_qfs_size(smb_request_t *);
  39   39  uint32_t smb2_qfs_device(smb_request_t *);
  40   40  uint32_t smb2_qfs_attr(smb_request_t *);
  41   41  uint32_t smb2_qfs_control(smb_request_t *);
  42   42  uint32_t smb2_qfs_fullsize(smb_request_t *);
  43   43  uint32_t smb2_qfs_obj_id(smb_request_t *);
       44 +uint32_t smb2_qfs_sectorsize(smb_request_t *);
  44   45  
  45   46  uint32_t
  46   47  smb2_qinfo_fs(smb_request_t *sr, smb_queryinfo_t *qi)
  47   48  {
  48   49          uint32_t status;
  49   50  
  50   51          switch (qi->qi_InfoClass) {
  51   52  
  52   53          /* pg 153 */
  53   54          case FileFsVolumeInformation:   /* 1 */
  54   55                  status = smb2_qfs_volume(sr);
  55   56                  break;
  56   57          case FileFsSizeInformation:     /* 3 */
  57   58                  status = smb2_qfs_size(sr);
  58   59                  break;
  59   60          case FileFsDeviceInformation:   /* 4 */
  60   61                  status = smb2_qfs_device(sr);
  61   62                  break;
  62   63          case FileFsAttributeInformation: /* 5 */
  63   64                  status = smb2_qfs_attr(sr);
  
    | 
      ↓ open down ↓ | 
    10 lines elided | 
    
      ↑ open up ↑ | 
  
  64   65                  break;
  65   66          case FileFsControlInformation:  /* 6 */
  66   67                  status = smb2_qfs_control(sr);
  67   68                  break;
  68   69          case FileFsFullSizeInformation: /* 7 */
  69   70                  status = smb2_qfs_fullsize(sr);
  70   71                  break;
  71   72          case FileFsObjectIdInformation: /* 8 */
  72   73                  status = smb2_qfs_obj_id(sr);
  73   74                  break;
  74      -
  75      -        default:
       75 +        case FileFsVolumeFlagsInformation:      /* A */
  76   76                  status = NT_STATUS_INVALID_INFO_CLASS;
  77   77                  break;
       78 +        case FileFsSectorSizeInformation:       /* B */
       79 +                status = smb2_qfs_sectorsize(sr);
       80 +                break;
       81 +        default: /* there are some infoclasses we don't yet handle */
       82 +                status = NT_STATUS_INVALID_INFO_CLASS;
       83 +#ifdef  DEBUG
       84 +                cmn_err(CE_NOTE, "unknown InfoClass 0x%x", qi->qi_InfoClass);
       85 +#endif
       86 +                break;
  78   87          }
  79   88  
  80   89          return (status);
  81   90  }
  82   91  
  83   92  /*
  84   93   * FileFsVolumeInformation
  85   94   */
  86   95  uint32_t
  87   96  smb2_qfs_volume(smb_request_t *sr)
  88   97  {
  89   98          smb_tree_t *tree = sr->tid_tree;
  90   99          smb_node_t *snode;
  91  100          fsid_t fsid;
  92  101          uint32_t LabelLength;
  93  102  
  94  103          if (!STYPE_ISDSK(tree->t_res_type))
  95  104                  return (NT_STATUS_INVALID_PARAMETER);
  96  105  
  97  106          snode = tree->t_snode;
  98  107          fsid = SMB_NODE_FSID(snode);
  99  108  
 100  109          LabelLength = smb_wcequiv_strlen(tree->t_volume);
 101  110  
 102  111          /*
 103  112           * NT has the "supports objects" flag set to 1.
 104  113           */
 105  114          (void) smb_mbc_encodef(
 106  115              &sr->raw_data, "qllb.U",
 107  116              0LL,        /* Volume creation time (q) */
 108  117              fsid.val[0],        /* serial no.   (l) */
 109  118              LabelLength,                /*      (l) */
 110  119              0,          /* Supports objects     (b) */
 111  120              /* reserved                         (.) */
 112  121              tree->t_volume);            /*      (U) */
 113  122  
 114  123          return (0);
 115  124  }
 116  125  
 117  126  /*
 118  127   * FileFsSizeInformation
 119  128   */
 120  129  uint32_t
 121  130  smb2_qfs_size(smb_request_t *sr)
 122  131  {
 123  132          smb_fssize_t            fssize;
 124  133          smb_tree_t *tree = sr->tid_tree;
 125  134          int rc;
 126  135  
 127  136          if (!STYPE_ISDSK(tree->t_res_type))
 128  137                  return (NT_STATUS_INVALID_PARAMETER);
 129  138  
 130  139          rc = smb_fssize(sr, &fssize);
 131  140          if (rc)
 132  141                  return (smb_errno2status(rc));
 133  142  
 134  143          (void) smb_mbc_encodef(
 135  144              &sr->raw_data, "qqll",
 136  145              fssize.fs_caller_units,
 137  146              fssize.fs_caller_avail,
 138  147              fssize.fs_sectors_per_unit,
 139  148              fssize.fs_bytes_per_sector);
 140  149  
 141  150          return (0);
 142  151  }
 143  152  
 144  153  /*
 145  154   * FileFsFullSizeInformation
 146  155   */
 147  156  uint32_t
 148  157  smb2_qfs_fullsize(smb_request_t *sr)
 149  158  {
 150  159          smb_fssize_t            fssize;
 151  160          smb_tree_t *tree = sr->tid_tree;
 152  161          int rc;
 153  162  
 154  163          if (!STYPE_ISDSK(tree->t_res_type))
 155  164                  return (NT_STATUS_INVALID_PARAMETER);
 156  165  
 157  166          rc = smb_fssize(sr, &fssize);
 158  167          if (rc)
 159  168                  return (smb_errno2status(rc));
 160  169  
 161  170          (void) smb_mbc_encodef(
 162  171              &sr->raw_data, "qqqll",
 163  172              fssize.fs_caller_units,
 164  173              fssize.fs_caller_avail,
 165  174              fssize.fs_volume_avail,
 166  175              fssize.fs_sectors_per_unit,
 167  176              fssize.fs_bytes_per_sector);
 168  177  
 169  178          return (0);
 170  179  }
 171  180  
 172  181  /*
 173  182   * FileFsDeviceInformation
 174  183   */
 175  184  uint32_t
 176  185  smb2_qfs_device(smb_request_t *sr)
 177  186  {
 178  187          smb_tree_t *tree = sr->tid_tree;
 179  188          uint32_t DeviceType;
 180  189          uint32_t Characteristics;
 181  190  
 182  191          if (!STYPE_ISDSK(tree->t_res_type))
 183  192                  return (NT_STATUS_INVALID_PARAMETER);
 184  193  
 185  194          DeviceType = FILE_DEVICE_DISK;
 186  195          Characteristics = FILE_DEVICE_IS_MOUNTED;
 187  196  
 188  197          (void) smb_mbc_encodef(
 189  198              &sr->raw_data, "ll",
 190  199              DeviceType,
 191  200              Characteristics);
 192  201  
 193  202          return (0);
 194  203  }
 195  204  
 196  205  /*
 197  206   * FileFsAttributeInformation
 198  207   */
 199  208  uint32_t
 200  209  smb2_qfs_attr(smb_request_t *sr)
 201  210  {
 202  211          smb_tree_t *tree = sr->tid_tree;
 203  212          char *fsname;
 204  213          uint32_t namelen;
 205  214          uint32_t FsAttr;
 206  215  
 207  216          /* This call is OK on all tree types. */
 208  217          switch (tree->t_res_type & STYPE_MASK) {
 209  218          case STYPE_IPC:
 210  219                  fsname = "PIPE";
 211  220                  break;
 212  221          case STYPE_DISKTREE:
 213  222                  fsname = "NTFS"; /* A lie, but compatible... */
 214  223                  break;
 215  224          case STYPE_PRINTQ:
 216  225          case STYPE_DEVICE:
 217  226          default: /* gcc -Wuninitialized */
 218  227                  return (NT_STATUS_INVALID_PARAMETER);
 219  228          }
 220  229          namelen = smb_wcequiv_strlen(fsname);
 221  230  
 222  231          /*
 223  232           * Todo: Store the FsAttributes in the tree object,
 224  233           * then just return that directly here.
 225  234           */
 226  235          FsAttr = FILE_CASE_PRESERVED_NAMES;
 227  236          if (tree->t_flags & SMB_TREE_UNICODE_ON_DISK)
 228  237                  FsAttr |= FILE_UNICODE_ON_DISK;
 229  238          if (tree->t_flags & SMB_TREE_SUPPORTS_ACLS)
 230  239                  FsAttr |= FILE_PERSISTENT_ACLS;
 231  240          if ((tree->t_flags & SMB_TREE_CASEINSENSITIVE) == 0)
 232  241                  FsAttr |= FILE_CASE_SENSITIVE_SEARCH;
 233  242          if (tree->t_flags & SMB_TREE_STREAMS)
 234  243                  FsAttr |= FILE_NAMED_STREAMS;
 235  244          if (tree->t_flags & SMB_TREE_QUOTA)
 236  245                  FsAttr |= FILE_VOLUME_QUOTAS;
 237  246          if (tree->t_flags & SMB_TREE_SPARSE)
 238  247                  FsAttr |= FILE_SUPPORTS_SPARSE_FILES;
 239  248  
 240  249          (void) smb_mbc_encodef(
 241  250              &sr->raw_data, "lllU",
 242  251              FsAttr,
 243  252              MAXNAMELEN-1,
 244  253              namelen,
 245  254              fsname);
 246  255  
 247  256          return (0);
 248  257  }
 249  258  
 250  259  /*
 251  260   * FileFsControlInformation
 252  261   */
 253  262  uint32_t
 254  263  smb2_qfs_control(smb_request_t *sr)
 255  264  {
 256  265          smb_tree_t *tree = sr->tid_tree;
 257  266  
 258  267          if (!STYPE_ISDSK(tree->t_res_type))
 259  268                  return (NT_STATUS_INVALID_PARAMETER);
 260  269          if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_QUOTA)) {
 261  270                  /*
 262  271                   * Strange error per. [MS-FSCC 2.5.2]
 263  272                   * which means quotas not supported.
 264  273                   */
 265  274                  return (NT_STATUS_VOLUME_NOT_UPGRADED);
 266  275          }
 267  276  
 268  277          (void) smb_mbc_encodef(
 269  278              &sr->raw_data, "qqqqqll",
 270  279              0,          /* free space start filtering - MUST be 0 */
 271  280              0,          /* free space threshold - MUST be 0 */
 272  281              0,          /* free space stop filtering - MUST be 0 */
 273  282              SMB_QUOTA_UNLIMITED,        /* default quota threshold */
 274  283              SMB_QUOTA_UNLIMITED,        /* default quota limit */
 275  284              FILE_VC_QUOTA_ENFORCE,      /* fs control flag */
 276  285              0);                         /* pad bytes */
 277  286  
 278  287          return (0);
  
    | 
      ↓ open down ↓ | 
    191 lines elided | 
    
      ↑ open up ↑ | 
  
 279  288  }
 280  289  
 281  290  /*
 282  291   * FileFsObjectIdInformation
 283  292   */
 284  293  /* ARGSUSED */
 285  294  uint32_t
 286  295  smb2_qfs_obj_id(smb_request_t *sr)
 287  296  {
 288  297          return (NT_STATUS_INVALID_PARAMETER);
      298 +}
      299 +
      300 +/*
      301 + * Not sure yet where these should go.
      302 + * Flags in FileFsSectorSizeInformation
      303 + */
      304 +
      305 +#define SSINFO_FLAGS_ALIGNED_DEVICE     0x00000001
      306 +// When set, this flag indicates that the first physical sector of the device
      307 +// is aligned with the first logical sector. When not set, the first physical
      308 +// sector of the device is misaligned with the first logical sector.
      309 +
      310 +#define SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE        0x00000002
      311 +// When set, this flag indicates that the partition is aligned to physical
      312 +// sector boundaries on the storage device.
      313 +
      314 +#define SSINFO_FLAGS_NO_SEEK_PENALTY    0x00000004
      315 +// When set, the device reports that it does not incur a seek penalty (this
      316 +// typically indicates that the device does not have rotating media, such as
      317 +// flash-based disks).
      318 +
      319 +#define SSINFO_FLAGS_TRIM_ENABLED       0x00000008
      320 +// When set, the device supports TRIM operations, either T13 (ATA) TRIM or
      321 +// T10 (SCSI/SAS) UNMAP.
      322 +
      323 +#define SSINFO_OFFSET_UNKNOWN           0xffffffff
      324 +// For "Alignment" fields below
      325 +
      326 +/* We have to lie to Windows Hyper-V about our logical record size. */
      327 +int smb2_max_logical_sector_size = 4096;
      328 +
      329 +/*
      330 + * FileFsSectorSizeInformation
      331 + *
      332 + * Returns a FILE_FS_SECTOR_SIZE_INFORMATION
      333 + * See: [MS-FSCC] 2.5.8 FileFsSizeInformation
      334 + *
      335 + * LogicalBytesPerSector (4 bytes): ... number of bytes in a logical sector
      336 + *   for the device backing the volume. This field is the unit of logical
      337 + *   addressing for the device and is not the unit of atomic write.
      338 + * PhysicalBytesPerSectorForAtomicity (4 bytes): ... number of bytes in a
      339 + *   physical sector for the device backing the volume.  This is the reported
      340 + *   physical sector size of the device and is the unit of atomic write.
      341 + * PhysicalBytesPerSectorForPerformance (4 bytes): ... number of bytes in a
      342 + *   physical sector for the device backing the volume. This is the reported
      343 + *   physical sector size of the device and is the unit of performance.
      344 + * FileSystemEffectivePhysicalBytesPerSectorForAtomicity (4 bytes): unit, in
      345 + *   bytes, that the file system on the volume will use for internal operations
      346 + *   that require alignment and atomicity.
      347 + * Flags (4 bytes): See ...
      348 + * ByteOffsetForSectorAlignment (4 bytes): ... logical sector offset within the
      349 + *   first physical sector where the first logical sector is placed, in bytes.
      350 + *   If this value is set to SSINFO_OFFSET_UNKNOWN (0xffffffff), there was
      351 + *   insufficient information to compute this field.
      352 + * ByteOffsetForPartitionAlignment (4 bytes): ... byte offset from the first
      353 + *   physical sector where the first partition is placed. If this value is
      354 + *   set to SSINFO_OFFSET_UNKNOWN (0xffffffff), there was either insufficient
      355 + *   information or an error was encountered in computing this field.
      356 + */
      357 +uint32_t
      358 +smb2_qfs_sectorsize(smb_request_t *sr)
      359 +{
      360 +        smb_fssize_t            fssize;
      361 +        smb_tree_t *tree = sr->tid_tree;
      362 +        uint32_t lbps, pbps;
      363 +        uint32_t flags;
      364 +        int rc;
      365 +
      366 +        if (!STYPE_ISDSK(tree->t_res_type))
      367 +                return (NT_STATUS_INVALID_PARAMETER);
      368 +
      369 +        rc = smb_fssize(sr, &fssize);
      370 +        if (rc)
      371 +                return (smb_errno2status(rc));
      372 +        pbps = fssize.fs_bytes_per_sector;
      373 +        lbps = fssize.fs_sectors_per_unit * pbps;
      374 +        if (lbps > smb2_max_logical_sector_size)
      375 +                lbps = smb2_max_logical_sector_size;
      376 +
      377 +        // LogicalBytesPerSector
      378 +        (void) smb_mbc_encodef(&sr->raw_data, "l", lbps);
      379 +
      380 +        // PhysicalBytesPerSectorForAtomicity
      381 +        (void) smb_mbc_encodef(&sr->raw_data, "l", pbps);
      382 +
      383 +        // PhysicalBytesPerSectorForPerformance
      384 +        // Using logical size here.
      385 +        (void) smb_mbc_encodef(&sr->raw_data, "l", lbps);
      386 +
      387 +        // FileSystemEffectivePhysicalBytesPerSectorForAtomicity
      388 +        (void) smb_mbc_encodef(&sr->raw_data, "l", pbps);
      389 +
      390 +        // Flags
      391 +        // We include "no seek penalty" because our files are
      392 +        // always ZFS-backed, which can reorder things on disk.
      393 +        // Leaving out SSINFO_FLAGS_TRIM_ENABLED for now.
      394 +        flags = SSINFO_FLAGS_ALIGNED_DEVICE |
      395 +                SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE |
      396 +                SSINFO_FLAGS_NO_SEEK_PENALTY;
      397 +        (void) smb_mbc_encodef(&sr->raw_data, "l", flags);
      398 +
      399 +        // ByteOffsetForSectorAlignment
      400 +        // ByteOffsetForPartitionAlignment
      401 +        // Just say "unknown" for these two.
      402 +        (void) smb_mbc_encodef(
      403 +            &sr->raw_data, "l",
      404 +            SSINFO_OFFSET_UNKNOWN,
      405 +            SSINFO_OFFSET_UNKNOWN);
      406 +
      407 +        return (0);
 289  408  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX