77a1b8a5794f3ab6c6e938176dd3affea34f27e2
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSVolume.cpp
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011, 2012, 2013 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, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
16  *   nor the names of their contributors may be used to endorse or promote
17  *   products derived from this software without specific prior written
18  *   permission from Kernel Drivers, LLC and Your File System, Inc.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
24  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 //
34 // File: AFSVolume.cpp
35 //
36
37 #include "AFSCommon.h"
38
39 NTSTATUS
40 AFSInitVolume( IN GUID *AuthGroup,
41                IN AFSFileID *RootFid,
42                IN LONG VolumeReferenceReason,
43                OUT AFSVolumeCB **VolumeCB)
44 {
45
46     NTSTATUS ntStatus = STATUS_SUCCESS;
47     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
48     AFSNonPagedVolumeCB *pNonPagedVcb = NULL;
49     AFSVolumeCB *pVolumeCB = NULL;
50     AFSNonPagedObjectInfoCB *pNonPagedObject = NULL;
51     ULONGLONG ullIndex = 0;
52     BOOLEAN bReleaseLocks = FALSE;
53     AFSVolumeInfoCB stVolumeInformation = {0};
54     AFSNonPagedDirectoryCB *pNonPagedDirEntry = NULL;
55     LONG lCount;
56
57     __Enter
58     {
59
60         //
61         // Before grabbing any locks ask the service for the volume information
62         // This may be a waste but we need to get this information prior to
63         // taking any volume tree locks. Don't do this for any 'reserved' cell entries
64         //
65
66         if( RootFid->Cell != 0)
67         {
68
69             RtlZeroMemory( &stVolumeInformation,
70                            sizeof( AFSVolumeInfoCB));
71
72             ntStatus = AFSRetrieveVolumeInformation( AuthGroup,
73                                                      RootFid,
74                                                      &stVolumeInformation);
75
76             if( !NT_SUCCESS( ntStatus))
77             {
78
79                 AFSDbgTrace(( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING,
80                               AFS_TRACE_LEVEL_ERROR,
81                               "AFSInitVolume AFSRetrieveVolumeInformation(RootFid) failure %08lX\n",
82                               ntStatus));
83
84                 try_return( ntStatus);
85             }
86
87             //
88             // Grab our tree locks and see if we raced with someone else
89             //
90
91             AFSAcquireExcl( pDeviceExt->Specific.RDR.VolumeTree.TreeLock,
92                             TRUE);
93
94             AFSAcquireExcl( &pDeviceExt->Specific.RDR.VolumeListLock,
95                             TRUE);
96
97             bReleaseLocks = TRUE;
98
99             ullIndex = AFSCreateHighIndex( RootFid);
100
101             ntStatus = AFSLocateHashEntry( pDeviceExt->Specific.RDR.VolumeTree.TreeHead,
102                                            ullIndex,
103                                            (AFSBTreeEntry **)&pVolumeCB);
104
105             if( NT_SUCCESS( ntStatus) &&
106                 pVolumeCB != NULL)
107             {
108
109                 //
110                 // So we don't lock with an invalidation call ...
111                 //
112
113                 lCount = AFSVolumeIncrement( pVolumeCB,
114                                              VolumeReferenceReason);
115
116                 AFSDbgTrace(( AFS_SUBSYSTEM_VOLUME_REF_COUNTING,
117                               AFS_TRACE_LEVEL_VERBOSE,
118                               "AFSInitVolume Increment count on volume %p Reason %u Cnt %d\n",
119                               pVolumeCB,
120                               VolumeReferenceReason,
121                               lCount));
122
123                 AFSReleaseResource( pDeviceExt->Specific.RDR.VolumeTree.TreeLock);
124
125                 AFSReleaseResource( &pDeviceExt->Specific.RDR.VolumeListLock);
126
127                 bReleaseLocks = FALSE;
128
129                 AFSAcquireExcl( pVolumeCB->VolumeLock,
130                                 TRUE);
131
132                 *VolumeCB = pVolumeCB;
133
134                 try_return( ntStatus);
135             }
136
137             //
138             // Revert our status from the above call back to success.
139             //
140
141             ntStatus = STATUS_SUCCESS;
142         }
143
144         //
145         // For the global root we allocate out volume node and insert it
146         // into the volume tree ...
147         //
148
149         pVolumeCB = (AFSVolumeCB *)AFSExAllocatePoolWithTag( PagedPool,
150                                                              sizeof( AFSVolumeCB),
151                                                              AFS_VCB_ALLOCATION_TAG);
152
153         if( pVolumeCB == NULL)
154         {
155
156             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
157                           AFS_TRACE_LEVEL_ERROR,
158                           "AFSInitVolume Failed to allocate the root volume cb\n"));
159
160             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
161         }
162
163         RtlZeroMemory( pVolumeCB,
164                        sizeof( AFSVolumeCB));
165
166         //
167         // The non paged portion
168         //
169
170         pNonPagedVcb = (AFSNonPagedVolumeCB *)AFSExAllocatePoolWithTag( NonPagedPool,
171                                                                         sizeof( AFSNonPagedVolumeCB),
172                                                                         AFS_VCB_NP_ALLOCATION_TAG);
173
174         if( pNonPagedVcb == NULL)
175         {
176
177             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
178                           AFS_TRACE_LEVEL_ERROR,
179                           "AFSInitVolume Failed to allocate the root non paged volume cb\n"));
180
181             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
182         }
183
184         RtlZeroMemory( pNonPagedVcb,
185                        sizeof( AFSNonPagedVolumeCB));
186
187         ExInitializeResourceLite( &pNonPagedVcb->VolumeLock);
188
189         ExInitializeResourceLite( &pNonPagedVcb->ObjectInfoTreeLock);
190
191         pNonPagedObject = (AFSNonPagedObjectInfoCB *)AFSExAllocatePoolWithTag( NonPagedPool,
192                                                                                sizeof( AFSNonPagedObjectInfoCB),
193                                                                                AFS_NP_OBJECT_INFO_TAG);
194
195         if( pNonPagedObject == NULL)
196         {
197
198             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
199                           AFS_TRACE_LEVEL_ERROR,
200                           "AFSInitVolume Failed to allocate the root non paged object cb\n"));
201
202             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
203         }
204
205         RtlZeroMemory( pNonPagedObject,
206                        sizeof( AFSNonPagedObjectInfoCB));
207
208         ExInitializeResourceLite( &pNonPagedObject->ObjectInfoLock);
209
210         ExInitializeResourceLite( &pNonPagedObject->DirectoryNodeHdrLock);
211
212         pVolumeCB->NonPagedVcb = pNonPagedVcb;
213
214         pVolumeCB->ObjectInformation.NonPagedInfo = pNonPagedObject;
215
216         pVolumeCB->VolumeLock = &pNonPagedVcb->VolumeLock;
217
218         pVolumeCB->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock = &pNonPagedObject->DirectoryNodeHdrLock;
219
220         pVolumeCB->ObjectInfoTree.TreeLock = &pNonPagedVcb->ObjectInfoTreeLock;
221
222         lCount = AFSVolumeIncrement( pVolumeCB,
223                                      VolumeReferenceReason);
224
225         AFSDbgTrace(( AFS_SUBSYSTEM_VOLUME_REF_COUNTING,
226                       AFS_TRACE_LEVEL_VERBOSE,
227                       "AFSInitVolume Initializing volume %p Reason %u count %d\n",
228                       pVolumeCB,
229                       VolumeReferenceReason,
230                       lCount));
231
232         AFSAcquireExcl( pVolumeCB->VolumeLock,
233                         TRUE);
234
235         pVolumeCB->DirectoryCB = (AFSDirectoryCB *)AFSExAllocatePoolWithTag( PagedPool,
236                                                                              sizeof( AFSDirectoryCB) + sizeof( WCHAR),
237                                                                              AFS_DIR_ENTRY_TAG);
238
239         if( pVolumeCB->DirectoryCB == NULL)
240         {
241
242             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
243         }
244
245         AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
246                       AFS_TRACE_LEVEL_VERBOSE,
247                       "AFSInitVolume AFS_DIR_ENTRY_TAG allocated %p\n",
248                       pVolumeCB->DirectoryCB));
249
250         pNonPagedDirEntry = (AFSNonPagedDirectoryCB *)AFSExAllocatePoolWithTag( NonPagedPool,
251                                                                                 sizeof( AFSNonPagedDirectoryCB),
252                                                                                 AFS_DIR_ENTRY_NP_TAG);
253
254         if( pNonPagedDirEntry == NULL)
255         {
256
257             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
258         }
259
260         RtlZeroMemory( pVolumeCB->DirectoryCB,
261                        sizeof( AFSDirectoryCB) + sizeof( WCHAR));
262
263         RtlZeroMemory( pNonPagedDirEntry,
264                        sizeof( AFSNonPagedDirectoryCB));
265
266         ExInitializeResourceLite( &pNonPagedDirEntry->Lock);
267
268         pVolumeCB->DirectoryCB->NonPaged = pNonPagedDirEntry;
269
270         //
271         // Initialize the non-paged portion of the directory entry
272         //
273
274         KeQuerySystemTime( &pVolumeCB->ObjectInformation.CreationTime);
275         KeQuerySystemTime( &pVolumeCB->ObjectInformation.LastWriteTime);
276         KeQuerySystemTime( &pVolumeCB->ObjectInformation.LastAccessTime);
277
278         pVolumeCB->ObjectInformation.FileType = AFS_FILE_TYPE_DIRECTORY;
279
280         SetFlag( pVolumeCB->ObjectInformation.Flags, AFS_OBJECT_ROOT_VOLUME);
281
282         pVolumeCB->ObjectInformation.FileId.Cell = RootFid->Cell;
283         pVolumeCB->ObjectInformation.FileId.Volume = RootFid->Volume;
284         pVolumeCB->ObjectInformation.FileId.Vnode = RootFid->Vnode;
285         pVolumeCB->ObjectInformation.FileId.Unique = RootFid->Unique;
286         pVolumeCB->ObjectInformation.FileId.Hash = RootFid->Hash;
287
288         pVolumeCB->ObjectInformation.FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
289
290         pVolumeCB->DirectoryCB->NameInformation.FileName.Length = sizeof( WCHAR);
291
292         pVolumeCB->DirectoryCB->NameInformation.FileName.MaximumLength = pVolumeCB->DirectoryCB->NameInformation.FileName.Length;
293
294         pVolumeCB->DirectoryCB->NameInformation.FileName.Buffer = (WCHAR *)((char *)pVolumeCB->DirectoryCB + sizeof( AFSDirectoryCB));
295
296         RtlCopyMemory( pVolumeCB->DirectoryCB->NameInformation.FileName.Buffer,
297                        L"\\",
298                        sizeof( WCHAR));
299
300         //
301         // Copy in the volume information retrieved above
302         //
303
304         RtlCopyMemory( &pVolumeCB->VolumeInformation,
305                        &stVolumeInformation,
306                        sizeof( AFSVolumeInfoCB));
307
308         //
309         // Setup pointers
310         //
311
312         pVolumeCB->DirectoryCB->ObjectInformation = &pVolumeCB->ObjectInformation;
313
314         //
315         // The ObjectInformation VolumeCB pointer does not obtain
316         // a reference count.
317         //
318
319         pVolumeCB->DirectoryCB->ObjectInformation->VolumeCB = pVolumeCB;
320
321         //
322         // Insert the volume into our volume tree. Don't insert any reserved entries
323         //
324
325         if( RootFid->Cell != 0)
326         {
327
328             pVolumeCB->TreeEntry.HashIndex = ullIndex;
329
330             if( pDeviceExt->Specific.RDR.VolumeTree.TreeHead == NULL)
331             {
332
333                 pDeviceExt->Specific.RDR.VolumeTree.TreeHead = &pVolumeCB->TreeEntry;
334
335                 SetFlag( pVolumeCB->Flags, AFS_VOLUME_INSERTED_HASH_TREE);
336             }
337             else
338             {
339
340                 if ( NT_SUCCESS( AFSInsertHashEntry( pDeviceExt->Specific.RDR.VolumeTree.TreeHead,
341                                                      &pVolumeCB->TreeEntry)))
342                 {
343
344                     SetFlag( pVolumeCB->Flags, AFS_VOLUME_INSERTED_HASH_TREE);
345                 }
346             }
347
348             if( pDeviceExt->Specific.RDR.VolumeListHead == NULL)
349             {
350
351                 pDeviceExt->Specific.RDR.VolumeListHead = pVolumeCB;
352             }
353             else
354             {
355
356                 pDeviceExt->Specific.RDR.VolumeListTail->ListEntry.fLink = (void *)pVolumeCB;
357
358                 pVolumeCB->ListEntry.bLink = pDeviceExt->Specific.RDR.VolumeListTail;
359             }
360
361             pDeviceExt->Specific.RDR.VolumeListTail = pVolumeCB;
362         }
363
364         *VolumeCB = pVolumeCB;
365
366 try_exit:
367
368         if( !NT_SUCCESS( ntStatus))
369         {
370
371             if( pNonPagedVcb != NULL)
372             {
373
374                 AFSReleaseResource( pVolumeCB->VolumeLock);
375
376                 ExDeleteResourceLite( &pNonPagedVcb->VolumeLock);
377
378                 ExDeleteResourceLite( &pNonPagedVcb->ObjectInfoTreeLock);
379
380                 AFSExFreePoolWithTag( pNonPagedVcb, AFS_VCB_NP_ALLOCATION_TAG);
381             }
382
383             if( pNonPagedObject != NULL)
384             {
385
386                 ExDeleteResourceLite( &pNonPagedObject->ObjectInfoLock);
387
388                 AFSExFreePoolWithTag( pNonPagedObject, AFS_NP_OBJECT_INFO_TAG);
389             }
390
391             if( pVolumeCB != NULL)
392             {
393
394                 if( pVolumeCB->DirectoryCB != NULL)
395                 {
396
397                     AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
398                                   AFS_TRACE_LEVEL_VERBOSE,
399                                   "AFSInitVolume AFS_DIR_ENTRY_TAG deallocating %p\n",
400                                   pVolumeCB->DirectoryCB));
401
402                     AFSExFreePoolWithTag( pVolumeCB->DirectoryCB, AFS_DIR_ENTRY_TAG);
403                 }
404
405                 AFSExFreePoolWithTag( pVolumeCB, AFS_VCB_ALLOCATION_TAG);
406             }
407
408             if( pNonPagedDirEntry != NULL)
409             {
410
411                 ExDeleteResourceLite( &pNonPagedDirEntry->Lock);
412
413                 AFSExFreePoolWithTag( pNonPagedDirEntry, AFS_DIR_ENTRY_NP_TAG);
414             }
415         }
416
417         if( bReleaseLocks)
418         {
419
420             AFSReleaseResource( pDeviceExt->Specific.RDR.VolumeTree.TreeLock);
421
422             AFSReleaseResource( &pDeviceExt->Specific.RDR.VolumeListLock);
423         }
424     }
425
426     return ntStatus;
427 }
428
429 NTSTATUS
430 AFSRemoveVolume( IN AFSVolumeCB *VolumeCB)
431 {
432
433     NTSTATUS ntStatus = STATUS_SUCCESS;
434     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
435
436     __Enter
437     {
438
439         ASSERT( VolumeCB->VolumeReferenceCount == 0);
440
441         //
442         // Remove the volume from the tree and list
443         // Don't process the list information for reserved entries
444         //
445
446         if( VolumeCB->ObjectInformation.FileId.Cell != 0)
447         {
448
449             if( BooleanFlagOn( VolumeCB->Flags, AFS_VOLUME_INSERTED_HASH_TREE))
450             {
451
452                 AFSRemoveHashEntry( &pDeviceExt->Specific.RDR.VolumeTree.TreeHead,
453                                     &VolumeCB->TreeEntry);
454             }
455
456             if( VolumeCB->ListEntry.fLink == NULL)
457             {
458
459                 pDeviceExt->Specific.RDR.VolumeListTail = (AFSVolumeCB *)VolumeCB->ListEntry.bLink;
460
461                 if( pDeviceExt->Specific.RDR.VolumeListTail != NULL)
462                 {
463
464                     pDeviceExt->Specific.RDR.VolumeListTail->ListEntry.fLink = NULL;
465                 }
466             }
467             else
468             {
469
470                 ((AFSVolumeCB *)(VolumeCB->ListEntry.fLink))->ListEntry.bLink = VolumeCB->ListEntry.bLink;
471             }
472
473             if( VolumeCB->ListEntry.bLink == NULL)
474             {
475
476                 pDeviceExt->Specific.RDR.VolumeListHead = (AFSVolumeCB *)VolumeCB->ListEntry.fLink;
477
478                 if( pDeviceExt->Specific.RDR.VolumeListHead != NULL)
479                 {
480
481                     pDeviceExt->Specific.RDR.VolumeListHead->ListEntry.bLink = NULL;
482                 }
483             }
484             else
485             {
486
487                 ((AFSVolumeCB *)(VolumeCB->ListEntry.bLink))->ListEntry.fLink = VolumeCB->ListEntry.fLink;
488             }
489         }
490
491         //
492         // Remove any PIOctl objects we have
493         //
494
495         if( VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB != NULL)
496         {
497
498             if( VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb != NULL)
499             {
500
501                 AFSAcquireExcl( &VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock,
502                                 TRUE);
503
504                 AFSRemoveFcb( &VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
505
506                 AFSReleaseResource( &VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
507             }
508
509             AFSDeleteObjectInfo( &VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
510
511             ExDeleteResourceLite( &VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
512
513             AFSExFreePoolWithTag( VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
514
515             AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
516                           AFS_TRACE_LEVEL_VERBOSE,
517                           "AFSRemoveVolume (pioctl) AFS_DIR_ENTRY_TAG deallocating %p\n",
518                           VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB));
519
520             AFSExFreePoolWithTag( VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
521         }
522
523         if( BooleanFlagOn( VolumeCB->ObjectInformation.Flags, AFS_OBJECT_HELD_IN_SERVICE))
524         {
525
526             //
527             // Release the fid in the service
528             //
529
530             AFSReleaseFid( &VolumeCB->ObjectInformation.FileId);
531         }
532
533         //
534         // Free up the memory
535         //
536
537         if( VolumeCB->NonPagedVcb != NULL)
538         {
539
540             if( ExIsResourceAcquiredLite( VolumeCB->VolumeLock))
541             {
542                 AFSReleaseResource( VolumeCB->VolumeLock);
543             }
544
545             ExDeleteResourceLite( &VolumeCB->NonPagedVcb->VolumeLock);
546
547             ExDeleteResourceLite( &VolumeCB->NonPagedVcb->ObjectInfoTreeLock);
548
549             AFSExFreePoolWithTag( VolumeCB->NonPagedVcb, AFS_VCB_NP_ALLOCATION_TAG);
550         }
551
552         if( VolumeCB->ObjectInformation.NonPagedInfo != NULL)
553         {
554
555             ExDeleteResourceLite( &VolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
556
557             ExDeleteResourceLite( &VolumeCB->ObjectInformation.NonPagedInfo->DirectoryNodeHdrLock);
558
559             AFSExFreePoolWithTag( VolumeCB->ObjectInformation.NonPagedInfo, AFS_NP_OBJECT_INFO_TAG);
560         }
561
562         if( VolumeCB->DirectoryCB != NULL)
563         {
564
565             if( VolumeCB->DirectoryCB->NonPaged != NULL)
566             {
567
568                 ExDeleteResourceLite( &VolumeCB->DirectoryCB->NonPaged->Lock);
569
570                 AFSExFreePoolWithTag( VolumeCB->DirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
571             }
572
573             AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
574                           AFS_TRACE_LEVEL_VERBOSE,
575                           "AFSRemoveVolume AFS_DIR_ENTRY_TAG deallocating %p\n",
576                           VolumeCB->DirectoryCB));
577
578             AFSExFreePoolWithTag( VolumeCB->DirectoryCB, AFS_DIR_ENTRY_TAG);
579         }
580
581         AFSExFreePoolWithTag( VolumeCB, AFS_VCB_ALLOCATION_TAG);
582     }
583
584     return ntStatus;
585 }
586
587 LONG
588 AFSVolumeIncrement( IN AFSVolumeCB *VolumeCB,
589                     IN LONG Reason)
590 {
591
592     LONG lCount;
593
594     lCount = InterlockedIncrement( &VolumeCB->VolumeReferenceCount);
595
596     InterlockedIncrement( &VolumeCB->VolumeReferences[ Reason]);
597
598     return lCount;
599 }
600
601 LONG
602 AFSVolumeDecrement( IN AFSVolumeCB *VolumeCB,
603                     IN LONG Reason)
604 {
605
606     LONG lCount;
607
608     lCount = InterlockedDecrement( &VolumeCB->VolumeReferences[ Reason]);
609
610     ASSERT( lCount >= 0);
611
612     lCount = InterlockedDecrement( &VolumeCB->VolumeReferenceCount);
613
614     ASSERT( lCount >= 0);
615
616     return lCount;
617 }