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