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)
        
@@ -18,11 +18,11 @@
  *
  * CDDL HEADER END
  */
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
  * Dispatch function for SMB2_QUERY_INFO
  *
@@ -39,10 +39,11 @@
 uint32_t smb2_qfs_device(smb_request_t *);
 uint32_t smb2_qfs_attr(smb_request_t *);
 uint32_t smb2_qfs_control(smb_request_t *);
 uint32_t smb2_qfs_fullsize(smb_request_t *);
 uint32_t smb2_qfs_obj_id(smb_request_t *);
+uint32_t smb2_qfs_sectorsize(smb_request_t *);
 
 uint32_t
 smb2_qinfo_fs(smb_request_t *sr, smb_queryinfo_t *qi)
 {
         uint32_t status;
@@ -69,14 +70,22 @@
                 status = smb2_qfs_fullsize(sr);
                 break;
         case FileFsObjectIdInformation: /* 8 */
                 status = smb2_qfs_obj_id(sr);
                 break;
-
-        default:
+        case FileFsVolumeFlagsInformation:      /* A */
                 status = NT_STATUS_INVALID_INFO_CLASS;
                 break;
+        case FileFsSectorSizeInformation:       /* B */
+                status = smb2_qfs_sectorsize(sr);
+                break;
+        default: /* there are some infoclasses we don't yet handle */
+                status = NT_STATUS_INVALID_INFO_CLASS;
+#ifdef  DEBUG
+                cmn_err(CE_NOTE, "unknown InfoClass 0x%x", qi->qi_InfoClass);
+#endif
+                break;
         }
 
         return (status);
 }
 
@@ -284,6 +293,116 @@
 /* ARGSUSED */
 uint32_t
 smb2_qfs_obj_id(smb_request_t *sr)
 {
         return (NT_STATUS_INVALID_PARAMETER);
+}
+
+/*
+ * Not sure yet where these should go.
+ * Flags in FileFsSectorSizeInformation
+ */
+
+#define SSINFO_FLAGS_ALIGNED_DEVICE     0x00000001
+// When set, this flag indicates that the first physical sector of the device
+// is aligned with the first logical sector. When not set, the first physical
+// sector of the device is misaligned with the first logical sector.
+
+#define SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE        0x00000002
+// When set, this flag indicates that the partition is aligned to physical
+// sector boundaries on the storage device.
+
+#define SSINFO_FLAGS_NO_SEEK_PENALTY    0x00000004
+// When set, the device reports that it does not incur a seek penalty (this
+// typically indicates that the device does not have rotating media, such as
+// flash-based disks).
+
+#define SSINFO_FLAGS_TRIM_ENABLED       0x00000008
+// When set, the device supports TRIM operations, either T13 (ATA) TRIM or
+// T10 (SCSI/SAS) UNMAP.
+
+#define SSINFO_OFFSET_UNKNOWN           0xffffffff
+// For "Alignment" fields below
+
+/* We have to lie to Windows Hyper-V about our logical record size. */
+int smb2_max_logical_sector_size = 4096;
+
+/*
+ * FileFsSectorSizeInformation
+ *
+ * Returns a FILE_FS_SECTOR_SIZE_INFORMATION
+ * See: [MS-FSCC] 2.5.8 FileFsSizeInformation
+ *
+ * LogicalBytesPerSector (4 bytes): ... number of bytes in a logical sector
+ *   for the device backing the volume. This field is the unit of logical
+ *   addressing for the device and is not the unit of atomic write.
+ * PhysicalBytesPerSectorForAtomicity (4 bytes): ... number of bytes in a
+ *   physical sector for the device backing the volume.  This is the reported
+ *   physical sector size of the device and is the unit of atomic write.
+ * PhysicalBytesPerSectorForPerformance (4 bytes): ... number of bytes in a
+ *   physical sector for the device backing the volume. This is the reported
+ *   physical sector size of the device and is the unit of performance.
+ * FileSystemEffectivePhysicalBytesPerSectorForAtomicity (4 bytes): unit, in
+ *   bytes, that the file system on the volume will use for internal operations
+ *   that require alignment and atomicity.
+ * Flags (4 bytes): See ...
+ * ByteOffsetForSectorAlignment (4 bytes): ... logical sector offset within the
+ *   first physical sector where the first logical sector is placed, in bytes.
+ *   If this value is set to SSINFO_OFFSET_UNKNOWN (0xffffffff), there was
+ *   insufficient information to compute this field.
+ * ByteOffsetForPartitionAlignment (4 bytes): ... byte offset from the first
+ *   physical sector where the first partition is placed. If this value is
+ *   set to SSINFO_OFFSET_UNKNOWN (0xffffffff), there was either insufficient
+ *   information or an error was encountered in computing this field.
+ */
+uint32_t
+smb2_qfs_sectorsize(smb_request_t *sr)
+{
+        smb_fssize_t            fssize;
+        smb_tree_t *tree = sr->tid_tree;
+        uint32_t lbps, pbps;
+        uint32_t flags;
+        int rc;
+
+        if (!STYPE_ISDSK(tree->t_res_type))
+                return (NT_STATUS_INVALID_PARAMETER);
+
+        rc = smb_fssize(sr, &fssize);
+        if (rc)
+                return (smb_errno2status(rc));
+        pbps = fssize.fs_bytes_per_sector;
+        lbps = fssize.fs_sectors_per_unit * pbps;
+        if (lbps > smb2_max_logical_sector_size)
+                lbps = smb2_max_logical_sector_size;
+
+        // LogicalBytesPerSector
+        (void) smb_mbc_encodef(&sr->raw_data, "l", lbps);
+
+        // PhysicalBytesPerSectorForAtomicity
+        (void) smb_mbc_encodef(&sr->raw_data, "l", pbps);
+
+        // PhysicalBytesPerSectorForPerformance
+        // Using logical size here.
+        (void) smb_mbc_encodef(&sr->raw_data, "l", lbps);
+
+        // FileSystemEffectivePhysicalBytesPerSectorForAtomicity
+        (void) smb_mbc_encodef(&sr->raw_data, "l", pbps);
+
+        // Flags
+        // We include "no seek penalty" because our files are
+        // always ZFS-backed, which can reorder things on disk.
+        // Leaving out SSINFO_FLAGS_TRIM_ENABLED for now.
+        flags = SSINFO_FLAGS_ALIGNED_DEVICE |
+                SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE |
+                SSINFO_FLAGS_NO_SEEK_PENALTY;
+        (void) smb_mbc_encodef(&sr->raw_data, "l", flags);
+
+        // ByteOffsetForSectorAlignment
+        // ByteOffsetForPartitionAlignment
+        // Just say "unknown" for these two.
+        (void) smb_mbc_encodef(
+            &sr->raw_data, "l",
+            SSINFO_OFFSET_UNKNOWN,
+            SSINFO_OFFSET_UNKNOWN);
+
+        return (0);
 }