xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_qinfo_fs.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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