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 2019 Nexenta by DDN, 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 int rc; 104 105 if (!STYPE_ISDSK(tree->t_res_type)) 106 return (NT_STATUS_INVALID_PARAMETER); 107 108 snode = tree->t_snode; 109 fsid = SMB_NODE_FSID(snode); 110 111 LabelLength = smb_wcequiv_strlen(tree->t_volume); 112 113 /* 114 * NT has the "supports objects" flag set to 1. 115 */ 116 rc = smb_mbc_encodef( 117 &sr->raw_data, "Tllb.U", 118 &tree->t_create_time, /* (T) */ 119 fsid.val[0], /* serial no. (l) */ 120 LabelLength, /* (l) */ 121 0, /* Supports objects (b) */ 122 /* reserved (.) */ 123 tree->t_volume); /* (U) */ 124 if (rc != 0) 125 return (NT_STATUS_BUFFER_OVERFLOW); 126 127 return (0); 128 } 129 130 /* 131 * FileFsSizeInformation 132 */ 133 uint32_t 134 smb2_qfs_size(smb_request_t *sr) 135 { 136 smb_fssize_t fssize; 137 smb_tree_t *tree = sr->tid_tree; 138 int rc; 139 140 if (!STYPE_ISDSK(tree->t_res_type)) 141 return (NT_STATUS_INVALID_PARAMETER); 142 143 rc = smb_fssize(sr, &fssize); 144 if (rc) 145 return (smb_errno2status(rc)); 146 147 rc = smb_mbc_encodef( 148 &sr->raw_data, "qqll", 149 fssize.fs_caller_units, 150 fssize.fs_caller_avail, 151 fssize.fs_sectors_per_unit, 152 fssize.fs_bytes_per_sector); 153 if (rc != 0) 154 return (NT_STATUS_BUFFER_OVERFLOW); 155 156 return (0); 157 } 158 159 /* 160 * FileFsFullSizeInformation 161 */ 162 uint32_t 163 smb2_qfs_fullsize(smb_request_t *sr) 164 { 165 smb_fssize_t fssize; 166 smb_tree_t *tree = sr->tid_tree; 167 int rc; 168 169 if (!STYPE_ISDSK(tree->t_res_type)) 170 return (NT_STATUS_INVALID_PARAMETER); 171 172 rc = smb_fssize(sr, &fssize); 173 if (rc) 174 return (smb_errno2status(rc)); 175 176 rc = smb_mbc_encodef( 177 &sr->raw_data, "qqqll", 178 fssize.fs_caller_units, 179 fssize.fs_caller_avail, 180 fssize.fs_volume_avail, 181 fssize.fs_sectors_per_unit, 182 fssize.fs_bytes_per_sector); 183 if (rc != 0) 184 return (NT_STATUS_BUFFER_OVERFLOW); 185 186 return (0); 187 } 188 189 /* 190 * FileFsDeviceInformation 191 */ 192 uint32_t 193 smb2_qfs_device(smb_request_t *sr) 194 { 195 smb_tree_t *tree = sr->tid_tree; 196 uint32_t DeviceType; 197 uint32_t Characteristics; 198 int rc; 199 200 if (!STYPE_ISDSK(tree->t_res_type)) 201 return (NT_STATUS_INVALID_PARAMETER); 202 203 DeviceType = FILE_DEVICE_DISK; 204 Characteristics = FILE_DEVICE_IS_MOUNTED; 205 206 rc = smb_mbc_encodef( 207 &sr->raw_data, "ll", 208 DeviceType, 209 Characteristics); 210 if (rc != 0) 211 return (NT_STATUS_BUFFER_OVERFLOW); 212 213 return (0); 214 } 215 216 /* 217 * FileFsAttributeInformation 218 */ 219 uint32_t 220 smb2_qfs_attr(smb_request_t *sr) 221 { 222 smb_tree_t *tree = sr->tid_tree; 223 char *fsname; 224 uint32_t namelen; 225 uint32_t FsAttr; 226 int rc; 227 228 /* This call is OK on all tree types. */ 229 switch (tree->t_res_type & STYPE_MASK) { 230 case STYPE_IPC: 231 fsname = "PIPE"; 232 break; 233 case STYPE_DISKTREE: 234 fsname = "NTFS"; /* A lie, but compatible... */ 235 break; 236 case STYPE_PRINTQ: 237 case STYPE_DEVICE: 238 default: /* gcc -Wuninitialized */ 239 return (NT_STATUS_INVALID_PARAMETER); 240 } 241 namelen = smb_wcequiv_strlen(fsname); 242 243 /* 244 * Todo: Store the FsAttributes in the tree object, 245 * then just return that directly here. 246 */ 247 FsAttr = FILE_CASE_PRESERVED_NAMES; 248 if (tree->t_flags & SMB_TREE_UNICODE_ON_DISK) 249 FsAttr |= FILE_UNICODE_ON_DISK; 250 if (tree->t_flags & SMB_TREE_SUPPORTS_ACLS) 251 FsAttr |= FILE_PERSISTENT_ACLS; 252 if ((tree->t_flags & SMB_TREE_CASEINSENSITIVE) == 0) 253 FsAttr |= FILE_CASE_SENSITIVE_SEARCH; 254 if (tree->t_flags & SMB_TREE_STREAMS) 255 FsAttr |= FILE_NAMED_STREAMS; 256 if (tree->t_flags & SMB_TREE_QUOTA) 257 FsAttr |= FILE_VOLUME_QUOTAS; 258 if (tree->t_flags & SMB_TREE_SPARSE) 259 FsAttr |= FILE_SUPPORTS_SPARSE_FILES; 260 261 rc = smb_mbc_encodef( 262 &sr->raw_data, "lllU", 263 FsAttr, 264 MAXNAMELEN-1, 265 namelen, 266 fsname); 267 if (rc != 0) 268 return (NT_STATUS_BUFFER_OVERFLOW); 269 270 return (0); 271 } 272 273 /* 274 * FileFsControlInformation 275 */ 276 uint32_t 277 smb2_qfs_control(smb_request_t *sr) 278 { 279 smb_tree_t *tree = sr->tid_tree; 280 int rc; 281 282 if (!STYPE_ISDSK(tree->t_res_type)) 283 return (NT_STATUS_INVALID_PARAMETER); 284 if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_QUOTA)) { 285 /* 286 * Strange error per. [MS-FSCC 2.5.2] 287 * which means quotas not supported. 288 */ 289 return (NT_STATUS_VOLUME_NOT_UPGRADED); 290 } 291 292 rc = smb_mbc_encodef( 293 &sr->raw_data, "qqqqqll", 294 0, /* free space start filtering - MUST be 0 */ 295 0, /* free space threshold - MUST be 0 */ 296 0, /* free space stop filtering - MUST be 0 */ 297 SMB_QUOTA_UNLIMITED, /* default quota threshold */ 298 SMB_QUOTA_UNLIMITED, /* default quota limit */ 299 FILE_VC_QUOTA_ENFORCE, /* fs control flag */ 300 0); /* pad bytes */ 301 if (rc != 0) 302 return (NT_STATUS_BUFFER_OVERFLOW); 303 304 return (0); 305 } 306 307 /* 308 * FileFsObjectIdInformation 309 */ 310 /* ARGSUSED */ 311 uint32_t 312 smb2_qfs_obj_id(smb_request_t *sr) 313 { 314 return (NT_STATUS_INVALID_PARAMETER); 315 } 316 317 /* 318 * Not sure yet where these should go. 319 * Flags in FileFsSectorSizeInformation 320 */ 321 322 #define SSINFO_FLAGS_ALIGNED_DEVICE 0x00000001 323 // When set, this flag indicates that the first physical sector of the device 324 // is aligned with the first logical sector. When not set, the first physical 325 // sector of the device is misaligned with the first logical sector. 326 327 #define SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE 0x00000002 328 // When set, this flag indicates that the partition is aligned to physical 329 // sector boundaries on the storage device. 330 331 #define SSINFO_FLAGS_NO_SEEK_PENALTY 0x00000004 332 // When set, the device reports that it does not incur a seek penalty (this 333 // typically indicates that the device does not have rotating media, such as 334 // flash-based disks). 335 336 #define SSINFO_FLAGS_TRIM_ENABLED 0x00000008 337 // When set, the device supports TRIM operations, either T13 (ATA) TRIM or 338 // T10 (SCSI/SAS) UNMAP. 339 340 #define SSINFO_OFFSET_UNKNOWN 0xffffffff 341 // For "Alignment" fields below 342 343 /* 344 * We have to lie to Windows Hyper-V about our logical record size, 345 * because with larger sizes it fails setting up a virtual disk. 346 */ 347 int smb2_max_logical_sector_size = 4096; 348 349 /* 350 * FileFsSectorSizeInformation 351 * 352 * Returns a FILE_FS_SECTOR_SIZE_INFORMATION 353 * See: [MS-FSCC] 2.5.8 FileFsSizeInformation 354 * 355 * LogicalBytesPerSector (4 bytes): ... number of bytes in a logical sector 356 * for the device backing the volume. This field is the unit of logical 357 * addressing for the device and is not the unit of atomic write. 358 * PhysicalBytesPerSectorForAtomicity (4 bytes): ... number of bytes in a 359 * physical sector for the device backing the volume. This is the reported 360 * physical sector size of the device and is the unit of atomic write. 361 * PhysicalBytesPerSectorForPerformance (4 bytes): ... number of bytes in a 362 * physical sector for the device backing the volume. This is the reported 363 * physical sector size of the device and is the unit of performance. 364 * FileSystemEffectivePhysicalBytesPerSectorForAtomicity (4 bytes): unit, in 365 * bytes, that the file system on the volume will use for internal operations 366 * that require alignment and atomicity. 367 * Flags (4 bytes): See ... 368 * ByteOffsetForSectorAlignment (4 bytes): ... logical sector offset within the 369 * first physical sector where the first logical sector is placed, in bytes. 370 * If this value is set to SSINFO_OFFSET_UNKNOWN (0xffffffff), there was 371 * insufficient information to compute this field. 372 * ByteOffsetForPartitionAlignment (4 bytes): ... byte offset from the first 373 * physical sector where the first partition is placed. If this value is 374 * set to SSINFO_OFFSET_UNKNOWN (0xffffffff), there was either insufficient 375 * information or an error was encountered in computing this field. 376 */ 377 uint32_t 378 smb2_qfs_sectorsize(smb_request_t *sr) 379 { 380 smb_fssize_t fssize; 381 smb_tree_t *tree = sr->tid_tree; 382 uint32_t lbps, pbps; 383 uint32_t flags, unk; 384 int rc; 385 386 if (!STYPE_ISDSK(tree->t_res_type)) 387 return (NT_STATUS_INVALID_PARAMETER); 388 389 rc = smb_fssize(sr, &fssize); 390 if (rc) 391 return (smb_errno2status(rc)); 392 393 // PhysicalBytesPerSector 394 pbps = fssize.fs_bytes_per_sector; 395 396 // LogicalBytesPerSector 397 lbps = fssize.fs_sectors_per_unit * pbps; 398 if (lbps > smb2_max_logical_sector_size) 399 lbps = smb2_max_logical_sector_size; 400 401 // Flags 402 // We include "no seek penalty" because our files are 403 // always ZFS-backed, which can reorder things on disk. 404 // Leaving out SSINFO_FLAGS_TRIM_ENABLED for now. 405 flags = SSINFO_FLAGS_ALIGNED_DEVICE | 406 SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE | 407 SSINFO_FLAGS_NO_SEEK_PENALTY; 408 409 // ByteOffsetForSectorAlignment 410 // ByteOffsetForPartitionAlignment 411 // Just say "unknown" for these two. 412 unk = SSINFO_OFFSET_UNKNOWN; 413 414 rc = smb_mbc_encodef( 415 &sr->raw_data, 416 "lllllll", 417 lbps, // LogicalBytesPerSector 418 pbps, // PhysicalBytesPerSectorForAtomicity 419 lbps, // PhysicalBytesPerSectorForPerformance 420 pbps, // FileSystemEffectivePhysicalBytesPerSectorForAtomicity 421 flags, 422 unk, unk); 423 424 if (rc != 0) 425 return (NT_STATUS_BUFFER_OVERFLOW); 426 427 return (0); 428 } 429