Windows: Avoid bottleneck on VolumeLock
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSVolumeInfo.cpp
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * - Redistributions of source code must retain the above copyright notice,
11  *   this list of conditions and the following disclaimer.
12  * - Redistributions in binary form must reproduce the above copyright
13  *   notice,
14  *   this list of conditions and the following disclaimer in the
15  *   documentation
16  *   and/or other materials provided with the distribution.
17  * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
18  *   nor the names of their contributors may be used to endorse or promote
19  *   products derived from this software without specific prior written
20  *   permission from Kernel Drivers, LLC and Your File System, Inc.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
26  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 //
36 // File: AFSVolumeInfo.cpp
37 //
38
39 #include "AFSCommon.h"
40
41 NTSTATUS
42 AFSQueryVolumeInfo( IN PDEVICE_OBJECT LibDeviceObject,
43                     IN PIRP Irp)
44 {
45
46     NTSTATUS ntStatus = STATUS_SUCCESS;
47     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
48     IO_STACK_LOCATION *pIrpSp;
49     FS_INFORMATION_CLASS FsInformationClass;
50     void *pBuffer = NULL;
51     ULONG ulLength = 0;
52     BOOLEAN bReleaseResource = FALSE;
53     AFSFcb *pFcb = NULL;
54     AFSVolumeCB *pVolumeCB = NULL;
55
56     pIrpSp = IoGetCurrentIrpStackLocation( Irp);
57
58     __try
59     {
60
61         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
62
63         if( pFcb == NULL)
64         {
65
66             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
67                           AFS_TRACE_LEVEL_ERROR,
68                           "AFSQueryVolumeInfo Failing request with NULL Fcb\n");
69
70             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
71         }
72
73         pVolumeCB = pFcb->ObjectInformation->VolumeCB;
74
75         ASSERT( pVolumeCB->ObjectInformation.FileType == AFS_FILE_TYPE_DIRECTORY &&
76                 pVolumeCB->ObjectInformation.FileId.Vnode == 1);
77
78         ulLength = pIrpSp->Parameters.QueryVolume.Length;
79         FsInformationClass = pIrpSp->Parameters.QueryVolume.FsInformationClass;
80         pBuffer = Irp->AssociatedIrp.SystemBuffer;
81
82         AFSAcquireShared( pVolumeCB->VolumeLock,
83                           TRUE);
84
85         bReleaseResource = TRUE;
86
87         //
88         // Don't allow requests against IOCtl nodes
89         //
90
91         if( pFcb->Header.NodeTypeCode == AFS_IOCTL_FCB)
92         {
93
94             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
95                           AFS_TRACE_LEVEL_ERROR,
96                           "AFSQueryVolumeInfo Failing request against PIOCtl Fcb\n");
97
98             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
99         }
100         else if( pFcb->Header.NodeTypeCode == AFS_SPECIAL_SHARE_FCB)
101         {
102
103             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
104                           AFS_TRACE_LEVEL_ERROR,
105                           "AFSQueryVolumeInfo Failing request against SpecialShare Fcb\n");
106
107             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
108         }
109
110         //
111         // Process the request
112         //
113
114         switch( FsInformationClass)
115         {
116
117             case FileFsVolumeInformation:
118             {
119
120                 ntStatus = AFSQueryFsVolumeInfo( &pVolumeCB->VolumeInformation,
121                                                  (PFILE_FS_VOLUME_INFORMATION)pBuffer,
122                                                  &ulLength);
123
124                 break;
125             }
126
127             case FileFsSizeInformation:
128             {
129
130                 ntStatus = AFSQueryFsSizeInfo( &pVolumeCB->VolumeInformation,
131                                                (PFILE_FS_SIZE_INFORMATION)pBuffer,
132                                                &ulLength);
133
134                 break;
135             }
136
137             case FileFsDeviceInformation:
138             {
139
140                 ntStatus = AFSQueryFsDeviceInfo( &pVolumeCB->VolumeInformation,
141                                                  (PFILE_FS_DEVICE_INFORMATION)pBuffer,
142                                                  &ulLength);
143
144                 break;
145             }
146
147             case FileFsAttributeInformation:
148             {
149
150                 ntStatus = AFSQueryFsAttributeInfo( &pVolumeCB->VolumeInformation,
151                                                     (PFILE_FS_ATTRIBUTE_INFORMATION)pBuffer,
152                                                     &ulLength);
153
154                 break;
155             }
156
157             case FileFsFullSizeInformation:
158             {
159
160                 ntStatus = AFSQueryFsFullSizeInfo( &pVolumeCB->VolumeInformation,
161                                                    (PFILE_FS_FULL_SIZE_INFORMATION)pBuffer,
162                                                    &ulLength);
163
164                 break;
165             }
166
167             default:
168
169                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
170                               AFS_TRACE_LEVEL_WARNING,
171                               "AFSQueryVolumeInfo Invalid class %d\n",
172                               FsInformationClass);
173
174                 ntStatus = STATUS_INVALID_PARAMETER;
175
176                 break;
177         }
178
179 try_exit:
180
181         //
182         // Setup the Irp's information field to what we actually copied in.
183         //
184
185         Irp->IoStatus.Information = pIrpSp->Parameters.QueryVolume.Length - ulLength;
186
187         if( bReleaseResource)
188         {
189
190             AFSReleaseResource( pVolumeCB->VolumeLock);
191         }
192
193         AFSCompleteRequest( Irp,
194                             ntStatus);
195
196     }
197     __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) )
198     {
199
200         AFSDbgLogMsg( 0,
201                       0,
202                       "EXCEPTION - AFSQueryVolumeInfo\n");
203     }
204
205     return ntStatus;
206 }
207
208 NTSTATUS
209 AFSSetVolumeInfo( IN PDEVICE_OBJECT DeviceObject,
210                   IN PIRP Irp)
211 {
212
213     NTSTATUS ntStatus = STATUS_SUCCESS;
214     IO_STACK_LOCATION *pIrpSp;
215
216     pIrpSp = IoGetCurrentIrpStackLocation( Irp);
217
218     __try
219     {
220
221         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
222                       AFS_TRACE_LEVEL_WARNING,
223                       "AFSSetVolumeInfo Entry for FO %08lX\n", pIrpSp->FileObject);
224
225         AFSCompleteRequest( Irp,
226                             ntStatus);
227
228     }
229     __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) )
230     {
231
232         AFSDbgLogMsg( 0,
233                       0,
234                       "EXCEPTION - AFSSetVolumeInfo\n");
235     }
236
237     return ntStatus;
238 }
239
240 NTSTATUS
241 AFSQueryFsVolumeInfo( IN AFSVolumeInfoCB *VolumeInfo,
242                       IN PFILE_FS_VOLUME_INFORMATION Buffer,
243                       IN OUT PULONG Length)
244
245 {
246
247     NTSTATUS ntStatus = STATUS_BUFFER_TOO_SMALL;
248     ULONG ulCopyLength;
249
250     RtlZeroMemory( Buffer,
251                    *Length);
252
253     if( *Length >= (ULONG)sizeof( FILE_FS_VOLUME_INFORMATION))
254     {
255
256         if( *Length >= (ULONG)(FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel) + (LONG)VolumeInfo->VolumeLabelLength))
257         {
258
259             ulCopyLength = (LONG)VolumeInfo->VolumeLabelLength;
260
261             ntStatus = STATUS_SUCCESS;
262         }
263         else
264         {
265
266             ulCopyLength = *Length - FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel);
267
268             ntStatus = STATUS_BUFFER_OVERFLOW;
269         }
270
271         Buffer->VolumeCreationTime.QuadPart = VolumeInfo->VolumeCreationTime.QuadPart;
272
273         Buffer->VolumeSerialNumber = VolumeInfo->VolumeID;
274
275         Buffer->VolumeLabelLength = VolumeInfo->VolumeLabelLength;
276
277         Buffer->SupportsObjects = FALSE;
278
279         *Length -= FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel);
280
281         if( ulCopyLength > 0)
282         {
283
284             RtlCopyMemory( Buffer->VolumeLabel,
285                            VolumeInfo->VolumeLabel,
286                            ulCopyLength);
287
288             *Length -= ulCopyLength;
289         }
290     }
291
292     return ntStatus;
293 }
294
295 NTSTATUS
296 AFSQueryFsSizeInfo( IN AFSVolumeInfoCB *VolumeInfo,
297                     IN PFILE_FS_SIZE_INFORMATION Buffer,
298                     IN OUT PULONG Length)
299 {
300
301     NTSTATUS ntStatus = STATUS_SUCCESS;
302
303     RtlZeroMemory( Buffer,
304                    *Length);
305
306     if( *Length >= sizeof( FILE_FS_SIZE_INFORMATION))
307     {
308
309         Buffer->TotalAllocationUnits.QuadPart = VolumeInfo->TotalAllocationUnits.QuadPart;
310
311         Buffer->AvailableAllocationUnits.QuadPart = VolumeInfo->AvailableAllocationUnits.QuadPart;
312
313         Buffer->SectorsPerAllocationUnit = VolumeInfo->SectorsPerAllocationUnit;
314
315         Buffer->BytesPerSector = VolumeInfo->BytesPerSector;
316
317         *Length -= sizeof( FILE_FS_SIZE_INFORMATION);
318     }
319     else
320     {
321
322         ntStatus = STATUS_BUFFER_TOO_SMALL;
323     }
324
325     return ntStatus;
326 }
327
328 NTSTATUS
329 AFSQueryFsDeviceInfo( IN AFSVolumeInfoCB *VolumeInfo,
330                       IN PFILE_FS_DEVICE_INFORMATION Buffer,
331                       IN OUT PULONG Length)
332 {
333     NTSTATUS ntStatus = STATUS_SUCCESS;
334
335     RtlZeroMemory( Buffer,
336                    *Length);
337
338     if( *Length >= (LONG)sizeof( FILE_FS_DEVICE_INFORMATION))
339     {
340
341         Buffer->DeviceType = FILE_DEVICE_DISK;
342
343         Buffer->Characteristics = VolumeInfo->Characteristics;
344
345         *Length -= sizeof( FILE_FS_DEVICE_INFORMATION);
346     }
347     else
348     {
349
350         ntStatus = STATUS_BUFFER_TOO_SMALL;
351     }
352
353     return ntStatus;
354 }
355
356 NTSTATUS
357 AFSQueryFsAttributeInfo( IN AFSVolumeInfoCB *VolumeInfo,
358                          IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
359                          IN OUT PULONG Length)
360 {
361     NTSTATUS ntStatus = STATUS_SUCCESS;
362
363     RtlZeroMemory( Buffer,
364                    *Length);
365
366     if( *Length >= (LONG)(sizeof( FILE_FS_ATTRIBUTE_INFORMATION)))
367     {
368
369         Buffer->FileSystemAttributes = (FILE_CASE_PRESERVED_NAMES |
370                                         FILE_UNICODE_ON_DISK |
371                                         FILE_SUPPORTS_REPARSE_POINTS);
372
373         Buffer->MaximumComponentNameLength = 255;
374
375         Buffer->FileSystemNameLength = 18;
376
377         *Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName);
378
379         if( *Length >= 18)
380         {
381
382             RtlCopyMemory( Buffer->FileSystemName,
383                            L"AFSRDRFsd",
384                            18);
385
386             *Length -= 18;
387         }
388         else
389         {
390
391             ntStatus = STATUS_BUFFER_OVERFLOW;
392         }
393     }
394     else
395     {
396
397         ntStatus = STATUS_BUFFER_TOO_SMALL;
398     }
399
400     return ntStatus;
401 }
402
403 NTSTATUS
404 AFSQueryFsFullSizeInfo( IN AFSVolumeInfoCB *VolumeInfo,
405                         IN PFILE_FS_FULL_SIZE_INFORMATION Buffer,
406                         IN OUT PULONG Length)
407 {
408
409     NTSTATUS ntStatus = STATUS_SUCCESS;
410
411     RtlZeroMemory( Buffer,
412                    *Length);
413
414     if( *Length >= sizeof( FILE_FS_FULL_SIZE_INFORMATION))
415     {
416
417         Buffer->TotalAllocationUnits.QuadPart = VolumeInfo->TotalAllocationUnits.QuadPart;
418
419         Buffer->CallerAvailableAllocationUnits.QuadPart = VolumeInfo->AvailableAllocationUnits.QuadPart;
420
421         Buffer->ActualAvailableAllocationUnits.QuadPart = VolumeInfo->AvailableAllocationUnits.QuadPart;
422
423         Buffer->SectorsPerAllocationUnit = VolumeInfo->SectorsPerAllocationUnit;
424
425         Buffer->BytesPerSector = VolumeInfo->BytesPerSector;
426
427         *Length -= sizeof( FILE_FS_FULL_SIZE_INFORMATION);
428     }
429     else
430     {
431
432         ntStatus = STATUS_BUFFER_TOO_SMALL;
433     }
434
435     return ntStatus;
436 }