Windows: AFSVolumeCB track RefCount reasons
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSWorker.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: AFSWorker.cpp
37 //
38
39 #include "AFSCommon.h"
40
41 //
42 // Function: AFSInitializeWorkerPool
43 //
44 // Description:
45 //
46 //      This function initializes the worker thread pool
47 //
48 // Return:
49 //
50 //      A status is returned for the function
51 //
52
53 NTSTATUS
54 AFSInitializeWorkerPool()
55 {
56
57     NTSTATUS ntStatus = STATUS_SUCCESS;
58     AFSWorkQueueContext        *pCurrentWorker = NULL, *pLastWorker = NULL;
59     AFSDeviceExt *pDevExt = NULL;
60
61     __Enter
62     {
63
64         pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
65
66         //
67         // Initialize the worker threads.
68         //
69
70         pDevExt->Specific.Library.WorkerCount = 0;
71
72         KeInitializeEvent( &pDevExt->Specific.Library.WorkerQueueHasItems,
73                            SynchronizationEvent,
74                            FALSE);
75
76         //
77         // Initialize the queue resource
78         //
79
80         ExInitializeResourceLite( &pDevExt->Specific.Library.QueueLock);
81
82         while( pDevExt->Specific.Library.WorkerCount < AFS_WORKER_COUNT)
83         {
84
85             pCurrentWorker = (AFSWorkQueueContext *)AFSLibExAllocatePoolWithTag( NonPagedPool,
86                                                                                  sizeof( AFSWorkQueueContext),
87                                                                                  AFS_WORKER_CB_TAG);
88
89             if( pCurrentWorker == NULL)
90             {
91
92                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
93                               AFS_TRACE_LEVEL_ERROR,
94                               "AFSInitializeWorkerPool Failed to allocate worker context\n");
95
96                 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
97
98                 break;
99             }
100
101             RtlZeroMemory( pCurrentWorker,
102                            sizeof( AFSWorkQueueContext));
103
104             ntStatus = AFSInitWorkerThread( pCurrentWorker,
105                                             (PKSTART_ROUTINE)AFSWorkerThread);
106
107             if( !NT_SUCCESS( ntStatus))
108             {
109
110                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
111                               AFS_TRACE_LEVEL_ERROR,
112                               "AFSInitializeWorkerPool Failed to initialize worker thread Status %08lX\n", ntStatus);
113
114                 ExFreePool( pCurrentWorker);
115
116                 break;
117             }
118
119             if( pDevExt->Specific.Library.PoolHead == NULL)
120             {
121
122                 pDevExt->Specific.Library.PoolHead = pCurrentWorker;
123             }
124             else
125             {
126
127                 pLastWorker->fLink = pCurrentWorker;
128             }
129
130             pLastWorker = pCurrentWorker;
131
132             pDevExt->Specific.Library.WorkerCount++;
133         }
134
135         //
136         // If there was a failure but there is at least one worker, then go with it.
137         //
138
139         if( !NT_SUCCESS( ntStatus) &&
140             pDevExt->Specific.Library.WorkerCount == 0)
141         {
142
143             try_return( ntStatus);
144         }
145
146         ntStatus = STATUS_SUCCESS;
147
148         //
149         // Now our IO Worker queue
150         //
151
152         pDevExt->Specific.Library.IOWorkerCount = 0;
153
154         KeInitializeEvent( &pDevExt->Specific.Library.IOWorkerQueueHasItems,
155                            SynchronizationEvent,
156                            FALSE);
157
158         //
159         // Initialize the queue resource
160         //
161
162         ExInitializeResourceLite( &pDevExt->Specific.Library.IOQueueLock);
163
164         while( pDevExt->Specific.Library.IOWorkerCount < AFS_IO_WORKER_COUNT)
165         {
166
167             pCurrentWorker = (AFSWorkQueueContext *)AFSLibExAllocatePoolWithTag( NonPagedPool,
168                                                                                  sizeof( AFSWorkQueueContext),
169                                                                                  AFS_WORKER_CB_TAG);
170
171             if( pCurrentWorker == NULL)
172             {
173
174                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
175                               AFS_TRACE_LEVEL_ERROR,
176                               "AFSInitializeWorkerPool Failed to allocate IO worker context\n");
177
178                 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
179
180                 break;
181             }
182
183             RtlZeroMemory( pCurrentWorker,
184                            sizeof( AFSWorkQueueContext));
185
186             ntStatus = AFSInitWorkerThread( pCurrentWorker,
187                                             (PKSTART_ROUTINE)AFSIOWorkerThread);
188
189             if( !NT_SUCCESS( ntStatus))
190             {
191
192                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
193                               AFS_TRACE_LEVEL_ERROR,
194                               "AFSInitializeWorkerPool Failed to initialize IO worker thread Status %08lX\n", ntStatus);
195
196                 ExFreePool( pCurrentWorker);
197
198                 break;
199             }
200
201             if( pDevExt->Specific.Library.IOPoolHead == NULL)
202             {
203
204                 pDevExt->Specific.Library.IOPoolHead = pCurrentWorker;
205             }
206             else
207             {
208
209                 pLastWorker->fLink = pCurrentWorker;
210             }
211
212             pLastWorker = pCurrentWorker;
213
214             pDevExt->Specific.Library.IOWorkerCount++;
215         }
216
217         //
218         // If there was a failure but there is at least one worker, then go with it.
219         //
220
221         if( !NT_SUCCESS( ntStatus) &&
222             pDevExt->Specific.Library.IOWorkerCount == 0)
223         {
224
225             try_return( ntStatus);
226         }
227
228 try_exit:
229
230         if( !NT_SUCCESS( ntStatus))
231         {
232
233             //
234             // Failed to initialize the pool so tear it down
235             //
236
237             AFSRemoveWorkerPool();
238         }
239     }
240
241     return ntStatus;
242 }
243
244 //
245 // Function: AFSRemoveWorkerPool
246 //
247 // Description:
248 //
249 //      This function tears down the worker thread pool
250 //
251 // Return:
252 //
253 //      A status is returned for the function
254 //
255
256 NTSTATUS
257 AFSRemoveWorkerPool()
258 {
259
260     NTSTATUS ntStatus = STATUS_SUCCESS;
261     ULONG index = 0;
262     AFSWorkQueueContext        *pCurrentWorker = NULL, *pNextWorker = NULL;
263     AFSDeviceExt *pDevExt = NULL;
264
265     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
266
267     //
268     // Loop through the workers shutting them down in two stages.
269     // First, clear AFS_WORKER_PROCESS_REQUESTS so that workers
270     // stop processing requests.  Second, call AFSShutdownWorkerThread()
271     // to wake the workers and wait for them to exit.
272     //
273
274     pCurrentWorker = pDevExt->Specific.Library.PoolHead;
275
276     while( index < pDevExt->Specific.Library.WorkerCount)
277     {
278
279         ClearFlag( pCurrentWorker->State, AFS_WORKER_PROCESS_REQUESTS);
280
281         pCurrentWorker = pCurrentWorker->fLink;
282
283         if ( pCurrentWorker == NULL)
284         {
285
286             break;
287         }
288
289         index++;
290     }
291
292     pCurrentWorker = pDevExt->Specific.Library.PoolHead;
293
294     index = 0;
295
296     while( index < pDevExt->Specific.Library.WorkerCount)
297     {
298
299         ntStatus = AFSShutdownWorkerThread( pCurrentWorker);
300
301         pNextWorker = pCurrentWorker->fLink;
302
303         ExFreePool( pCurrentWorker);
304
305         pCurrentWorker = pNextWorker;
306
307         if( pCurrentWorker == NULL)
308         {
309
310             break;
311         }
312
313         index++;
314     }
315
316     pDevExt->Specific.Library.PoolHead = NULL;
317
318     ExDeleteResourceLite( &pDevExt->Specific.Library.QueueLock);
319
320     //
321     // Loop through the IO workers shutting them down in two stages.
322     // First, clear AFS_WORKER_PROCESS_REQUESTS so that workers
323     // stop processing requests.  Second, call AFSShutdownIOWorkerThread()
324     // to wake the workers and wait for them to exit.
325     //
326
327     pCurrentWorker = pDevExt->Specific.Library.IOPoolHead;
328
329     index = 0;
330
331     while( index < pDevExt->Specific.Library.IOWorkerCount)
332     {
333
334         ClearFlag( pCurrentWorker->State, AFS_WORKER_PROCESS_REQUESTS);
335
336         pCurrentWorker = pCurrentWorker->fLink;
337
338         if ( pCurrentWorker == NULL)
339         {
340
341             break;
342         }
343
344         index++;
345     }
346
347     pCurrentWorker = pDevExt->Specific.Library.IOPoolHead;
348
349     index = 0;
350
351     while( index < pDevExt->Specific.Library.IOWorkerCount)
352     {
353
354         ntStatus = AFSShutdownIOWorkerThread( pCurrentWorker);
355
356         pNextWorker = pCurrentWorker->fLink;
357
358         ExFreePool( pCurrentWorker);
359
360         pCurrentWorker = pNextWorker;
361
362         if( pCurrentWorker == NULL)
363         {
364
365             break;
366         }
367
368         index++;
369     }
370
371     pDevExt->Specific.Library.IOPoolHead = NULL;
372
373     ExDeleteResourceLite( &pDevExt->Specific.Library.IOQueueLock);
374
375     return ntStatus;
376 }
377
378 NTSTATUS
379 AFSInitVolumeWorker( IN AFSVolumeCB *VolumeCB)
380 {
381
382     NTSTATUS ntStatus = STATUS_SUCCESS;
383     AFSWorkQueueContext *pWorker = &VolumeCB->NonPagedVcb->VolumeWorkerContext;
384     HANDLE hThread;
385     AFSDeviceExt *pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
386     PKSTART_ROUTINE pStartRoutine = NULL;
387     LONG lCount;
388
389     __Enter
390     {
391
392         if ( VolumeCB != AFSGlobalRoot)
393         {
394
395             return STATUS_INVALID_PARAMETER;
396         }
397
398         pStartRoutine = AFSPrimaryVolumeWorkerThread;
399
400         //
401         // Initialize the worker thread
402         //
403
404         KeInitializeEvent( &pWorker->WorkerThreadReady,
405                            NotificationEvent,
406                            FALSE);
407
408         //
409         // Set the worker to process requests
410         //
411
412         pWorker->State = AFS_WORKER_PROCESS_REQUESTS;
413
414         //
415         // Launch the thread
416         //
417
418         ntStatus =  PsCreateSystemThread( &hThread,
419                                           0,
420                                           NULL,
421                                           NULL,
422                                           NULL,
423                                           pStartRoutine,
424                                           (void *)VolumeCB);
425
426         if( NT_SUCCESS( ntStatus))
427         {
428
429             ObReferenceObjectByHandle( hThread,
430                                        GENERIC_READ | GENERIC_WRITE,
431                                        NULL,
432                                        KernelMode,
433                                        (PVOID *)&pWorker->WorkerThreadObject,
434                                        NULL);
435
436             ntStatus = KeWaitForSingleObject( &pWorker->WorkerThreadReady,
437                                               Executive,
438                                               KernelMode,
439                                               FALSE,
440                                               NULL);
441
442             lCount = InterlockedIncrement( &pControlDeviceExt->Specific.Control.VolumeWorkerThreadCount);
443
444             if( lCount > 0)
445             {
446
447                 KeClearEvent( &pControlDeviceExt->Specific.Control.VolumeWorkerCloseEvent);
448             }
449
450             ZwClose( hThread);
451         }
452     }
453
454     return ntStatus;
455 }
456
457 //
458 // Function: AFSInitWorkerThread
459 //
460 // Description:
461 //
462 //      This function initializes a worker thread in the pool
463 //
464 // Return:
465 //
466 //      A status is returned for the function
467 //
468
469 NTSTATUS
470 AFSInitWorkerThread( IN AFSWorkQueueContext *PoolContext,
471                      IN PKSTART_ROUTINE WorkerRoutine)
472 {
473
474     NTSTATUS ntStatus = STATUS_SUCCESS;
475     HANDLE Handle;
476
477     //
478     // INitialize the worker signal thread
479     //
480
481     KeInitializeEvent( &PoolContext->WorkerThreadReady,
482                        NotificationEvent,
483                        FALSE);
484
485     //
486     // Set the worker to process requests
487     //
488
489     PoolContext->State = AFS_WORKER_PROCESS_REQUESTS;
490
491     //
492     // Launch the thread
493     //
494
495     ntStatus =  PsCreateSystemThread( &Handle,
496                                       0,
497                                       NULL,
498                                       NULL,
499                                       NULL,
500                                       WorkerRoutine,
501                                       (void *)PoolContext);
502
503     if( NT_SUCCESS( ntStatus))
504     {
505
506         ObReferenceObjectByHandle( Handle,
507                                    GENERIC_READ | GENERIC_WRITE,
508                                    NULL,
509                                    KernelMode,
510                                    (PVOID *)&PoolContext->WorkerThreadObject,
511                                    NULL);
512
513         ntStatus = KeWaitForSingleObject( &PoolContext->WorkerThreadReady,
514                                           Executive,
515                                           KernelMode,
516                                           FALSE,
517                                           NULL);
518
519         ZwClose( Handle);
520     }
521
522     return ntStatus;
523 }
524
525 NTSTATUS
526 AFSShutdownVolumeWorker( IN AFSVolumeCB *VolumeCB)
527 {
528
529     NTSTATUS ntStatus = STATUS_SUCCESS;
530     AFSWorkQueueContext *pWorker = &VolumeCB->NonPagedVcb->VolumeWorkerContext;
531
532     //
533     // Clear the 'keep processing' flag
534     //
535
536     ClearFlag( pWorker->State, AFS_WORKER_PROCESS_REQUESTS);
537
538     if( pWorker->WorkerThreadObject != NULL)
539     {
540         while ( BooleanFlagOn( pWorker->State, AFS_WORKER_INITIALIZED) )
541         {
542
543             ntStatus = KeWaitForSingleObject( pWorker->WorkerThreadObject,
544                                               Executive,
545                                               KernelMode,
546                                               FALSE,
547                                               NULL);
548         }
549
550         ObDereferenceObject( pWorker->WorkerThreadObject);
551
552         pWorker->WorkerThreadObject = NULL;
553     }
554
555     return ntStatus;
556 }
557
558 //
559 // Function: AFSShutdownWorkerThread
560 //
561 // Description:
562 //
563 //      This function shutsdown a worker thread in the pool
564 //
565 // Return:
566 //
567 //      A status is returned for the function
568 //
569
570 NTSTATUS
571 AFSShutdownWorkerThread( IN AFSWorkQueueContext *PoolContext)
572 {
573
574     NTSTATUS ntStatus = STATUS_SUCCESS;
575     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
576
577     if( PoolContext->WorkerThreadObject != NULL)
578     {
579
580         while ( BooleanFlagOn( PoolContext->State, AFS_WORKER_INITIALIZED) )
581         {
582
583             //
584             // Wake up the thread if it is a sleep
585             //
586
587             KeSetEvent( &pDeviceExt->Specific.Library.WorkerQueueHasItems,
588                         0,
589                         FALSE);
590
591             ntStatus = KeWaitForSingleObject( PoolContext->WorkerThreadObject,
592                                               Executive,
593                                               KernelMode,
594                                               FALSE,
595                                               NULL);
596         }
597
598         ObDereferenceObject( PoolContext->WorkerThreadObject);
599
600         PoolContext->WorkerThreadObject = NULL;
601     }
602
603     return ntStatus;
604 }
605
606 //
607 // Function: AFSShutdownIOWorkerThread
608 //
609 // Description:
610 //
611 //      This function shutsdown an IO worker thread in the pool
612 //
613 // Return:
614 //
615 //      A status is returned for the function
616 //
617
618 NTSTATUS
619 AFSShutdownIOWorkerThread( IN AFSWorkQueueContext *PoolContext)
620 {
621
622     NTSTATUS ntStatus = STATUS_SUCCESS;
623     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
624
625     if( PoolContext->WorkerThreadObject != NULL)
626     {
627
628         while ( BooleanFlagOn( PoolContext->State, AFS_WORKER_INITIALIZED) )
629         {
630
631             //
632             // Wake up the thread if it is a sleep
633             //
634
635             KeSetEvent( &pDeviceExt->Specific.Library.IOWorkerQueueHasItems,
636                         0,
637                         FALSE);
638
639             ntStatus = KeWaitForSingleObject( PoolContext->WorkerThreadObject,
640                                               Executive,
641                                               KernelMode,
642                                               FALSE,
643                                               NULL);
644         }
645
646         ObDereferenceObject( PoolContext->WorkerThreadObject);
647
648         PoolContext->WorkerThreadObject = NULL;
649     }
650
651     return ntStatus;
652 }
653
654 //
655 // Function: AFSWorkerThread
656 //
657 // Description:
658 //
659 //      This is the worker thread entry point.
660 //
661 // Return:
662 //
663 //      A status is returned for the function
664 //
665
666 void
667 AFSWorkerThread( IN PVOID Context)
668 {
669
670     NTSTATUS ntStatus = STATUS_SUCCESS;
671     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)Context;
672     AFSWorkItem *pWorkItem;
673     BOOLEAN freeWorkItem = TRUE;
674     AFSDeviceExt *pLibraryDevExt = NULL;
675     LONG lCount;
676
677     pLibraryDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
678
679     //
680     // Indicate that we are initialized and ready
681     //
682
683     KeSetEvent( &pPoolContext->WorkerThreadReady,
684                 0,
685                 FALSE);
686
687     //
688     // Indicate we are initialized
689     //
690
691     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
692
693     ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.WorkerQueueHasItems,
694                                       Executive,
695                                       KernelMode,
696                                       FALSE,
697                                       NULL);
698
699     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
700     {
701
702         if( !NT_SUCCESS( ntStatus))
703         {
704
705             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
706                           AFS_TRACE_LEVEL_ERROR,
707                           "AFSWorkerThread Wait for queue items failed Status %08lX\n", ntStatus);
708
709             ntStatus = STATUS_SUCCESS;
710         }
711         else
712         {
713
714             pWorkItem = AFSRemoveWorkItem();
715
716             if( pWorkItem == NULL)
717             {
718
719                 ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.WorkerQueueHasItems,
720                                                   Executive,
721                                                   KernelMode,
722                                                   FALSE,
723                                                   NULL);
724             }
725             else
726             {
727
728                 freeWorkItem = TRUE;
729
730                 //
731                 // Switch on the type of work item to process
732                 //
733
734                 switch( pWorkItem->RequestType)
735                 {
736
737                     case AFS_WORK_FLUSH_FCB:
738                     {
739
740                         ntStatus = AFSFlushExtents( pWorkItem->Specific.Fcb.Fcb,
741                                                     &pWorkItem->AuthGroup);
742
743                         if( !NT_SUCCESS( ntStatus))
744                         {
745
746                             AFSReleaseExtentsWithFlush( pWorkItem->Specific.Fcb.Fcb,
747                                                         &pWorkItem->AuthGroup,
748                                                         FALSE);
749                         }
750
751                         ASSERT( pWorkItem->Specific.Fcb.Fcb->OpenReferenceCount != 0);
752
753                         lCount = InterlockedDecrement( &pWorkItem->Specific.Fcb.Fcb->OpenReferenceCount);
754
755                         break;
756                     }
757
758                     case AFS_WORK_ENUMERATE_GLOBAL_ROOT:
759                     {
760
761                         AFSEnumerateGlobalRoot( NULL);
762
763                         break;
764                     }
765
766                     case AFS_WORK_INVALIDATE_OBJECT:
767                     {
768
769                         AFSPerformObjectInvalidate( pWorkItem->Specific.Invalidate.ObjectInfo,
770                                                     pWorkItem->Specific.Invalidate.InvalidateReason);
771
772                         freeWorkItem = TRUE;
773
774                         break;
775                     }
776
777                     case AFS_WORK_START_IOS:
778                     {
779
780                         freeWorkItem = TRUE;
781
782                         break;
783                     }
784
785                     default:
786
787                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
788                                       AFS_TRACE_LEVEL_ERROR,
789                                       "AFSWorkerThread Unknown request type %d\n", pWorkItem->RequestType);
790
791                         break;
792                 }
793
794                 if( freeWorkItem)
795                 {
796
797                     ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
798                 }
799
800                 ntStatus = STATUS_SUCCESS;
801             }
802         }
803     } // worker thread loop
804
805     ClearFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
806
807     // Wake up another worker so they too can exit
808
809     KeSetEvent( &pLibraryDevExt->Specific.Library.WorkerQueueHasItems,
810                 0,
811                 FALSE);
812
813     PsTerminateSystemThread( 0);
814
815     return;
816 }
817
818 void
819 AFSIOWorkerThread( IN PVOID Context)
820 {
821
822     NTSTATUS ntStatus = STATUS_SUCCESS;
823     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)Context;
824     AFSWorkItem *pWorkItem;
825     BOOLEAN freeWorkItem = TRUE;
826     AFSDeviceExt *pLibraryDevExt = NULL, *pRdrDevExt = NULL;
827
828     pLibraryDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
829
830     //
831     // Indicate that we are initialized and ready
832     //
833
834     KeSetEvent( &pPoolContext->WorkerThreadReady,
835                 0,
836                 FALSE);
837
838
839     //
840     // Indicate we are initialized
841     //
842
843     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
844
845     ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.IOWorkerQueueHasItems,
846                                       Executive,
847                                       KernelMode,
848                                       FALSE,
849                                       NULL);
850
851     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
852     {
853
854         if( !NT_SUCCESS( ntStatus))
855         {
856
857             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
858                           AFS_TRACE_LEVEL_ERROR,
859                           "AFSIOWorkerThread Wait for queue items failed Status %08lX\n", ntStatus);
860
861             ntStatus = STATUS_SUCCESS;
862         }
863         else
864         {
865
866             pWorkItem = AFSRemoveIOWorkItem();
867
868             if( pWorkItem == NULL)
869             {
870
871                 ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.IOWorkerQueueHasItems,
872                                                   Executive,
873                                                   KernelMode,
874                                                   FALSE,
875                                                   NULL);
876             }
877             else
878             {
879
880                 freeWorkItem = TRUE;
881
882                 //
883                 // Switch on the type of work item to process
884                 //
885
886                 switch( pWorkItem->RequestType)
887                 {
888
889                     case AFS_WORK_START_IOS:
890                     {
891
892                         pRdrDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
893
894                         //
895                         // The final status is in the gather io
896                         //
897
898                         ntStatus = AFSStartIos( pWorkItem->Specific.CacheAccess.CacheFileObject,
899                                                 pWorkItem->Specific.CacheAccess.FunctionCode,
900                                                 pWorkItem->Specific.CacheAccess.RequestFlags,
901                                                 pWorkItem->Specific.CacheAccess.IoRuns,
902                                                 pWorkItem->Specific.CacheAccess.RunCount,
903                                                 pWorkItem->Specific.CacheAccess.GatherIo);
904
905                         //
906                         // Regardless of the status we we do the complete - there may
907                         // be IOs in flight
908                         // Decrement the count - setting the event if we were told
909                         // to. This may trigger completion.
910                         //
911
912                         AFSCompleteIo( pWorkItem->Specific.CacheAccess.GatherIo, ntStatus );
913
914                         freeWorkItem = TRUE;
915
916                         break;
917                     }
918
919                     default:
920
921                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
922                                       AFS_TRACE_LEVEL_ERROR,
923                                       "AFSWorkerThread Unknown request type %d\n", pWorkItem->RequestType);
924
925                         break;
926                 }
927
928                 if( freeWorkItem)
929                 {
930
931                     ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
932                 }
933
934                 ntStatus = STATUS_SUCCESS;
935             }
936         }
937     } // worker thread loop
938
939     ClearFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
940
941     // Wake up another IOWorker so they too can exit
942
943     KeSetEvent( &pLibraryDevExt->Specific.Library.IOWorkerQueueHasItems,
944                 0,
945                 FALSE);
946
947     PsTerminateSystemThread( 0);
948
949     return;
950 }
951
952 static BOOLEAN
953 AFSExamineDirectory( IN AFSObjectInfoCB * pCurrentObject,
954                      IN AFSDirectoryCB  * pCurrentDirEntry)
955 {
956     NTSTATUS ntStatus;
957     AFSFcb *pFcb = NULL;
958     AFSObjectInfoCB *pCurrentChildObject = NULL;
959     AFSVolumeCB * pVolumeCB = pCurrentObject->VolumeCB;
960     BOOLEAN bFcbBusy = FALSE;
961     LONG lCount;
962
963     pCurrentChildObject = pCurrentDirEntry->ObjectInformation;
964
965     AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING | AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
966                   AFS_TRACE_LEVEL_VERBOSE,
967                   "AFSExamineDirectory Deleting DE %wZ Object %p\n",
968                   &pCurrentDirEntry->NameInformation.FileName,
969                   pCurrentChildObject);
970
971     AFSDeleteDirEntry( pCurrentObject,
972                        pCurrentDirEntry);
973
974     //
975     // Acquire ObjectInfoLock shared here so as not to deadlock
976     // with an invalidation call from the service during AFSCleanupFcb
977     //
978
979     lCount = AFSObjectInfoIncrement( pCurrentChildObject,
980                                      AFS_OBJECT_REFERENCE_WORKER);
981
982     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
983                   AFS_TRACE_LEVEL_VERBOSE,
984                   "AFSExamineDirectory Increment count on object %p Cnt %d\n",
985                   pCurrentChildObject,
986                   lCount);
987
988     if( lCount == 1 &&
989         pCurrentChildObject->Fcb != NULL &&
990         pCurrentChildObject->FileType == AFS_FILE_TYPE_FILE)
991     {
992
993         //
994         // We must not hold pVolumeCB->ObjectInfoTree.TreeLock exclusive
995         // across an AFSCleanupFcb call since it can deadlock with an
996         // invalidation call from the service.
997         //
998
999         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1000
1001         //
1002         // Cannot hold a TreeLock across an AFSCleanupFcb call
1003         // as it can deadlock with an invalidation ioctl initiated
1004         // from the service.
1005         //
1006         // Dropping the TreeLock permits the
1007         // pCurrentObject->ObjectReferenceCount to change
1008         //
1009
1010         ntStatus = AFSCleanupFcb( pCurrentChildObject->Fcb,
1011                                   TRUE);
1012
1013         if ( ntStatus == STATUS_RETRY)
1014         {
1015
1016             bFcbBusy = TRUE;
1017         }
1018
1019         AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1020                         TRUE);
1021     }
1022
1023     AFSAcquireExcl( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock,
1024                     TRUE);
1025
1026     lCount = AFSObjectInfoDecrement( pCurrentChildObject,
1027                                      AFS_OBJECT_REFERENCE_WORKER);
1028
1029     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1030                   AFS_TRACE_LEVEL_VERBOSE,
1031                   "AFSExamineDirectory Decrement1 count on object %p Cnt %d\n",
1032                   pCurrentChildObject,
1033                   lCount);
1034
1035     if( lCount == 0 &&
1036         pCurrentChildObject->Fcb != NULL &&
1037         pCurrentChildObject->Fcb->OpenReferenceCount == 0)
1038     {
1039
1040         AFSRemoveFcb( &pCurrentChildObject->Fcb);
1041
1042         if( pCurrentChildObject->FileType == AFS_FILE_TYPE_DIRECTORY &&
1043             pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
1044         {
1045
1046             AFSAcquireExcl( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock,
1047                             TRUE);
1048
1049             AFSRemoveFcb( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
1050
1051             AFSReleaseResource( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
1052
1053             AFSDeleteObjectInfo( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
1054
1055             ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
1056
1057             AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
1058
1059             AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
1060                           AFS_TRACE_LEVEL_VERBOSE,
1061                           "AFSExamineDirectory (pioctl) AFS_DIR_ENTRY_TAG deallocating %p\n",
1062                           pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB);
1063
1064             AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
1065         }
1066
1067         AFSReleaseResource( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock);
1068
1069         AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1070                       AFS_TRACE_LEVEL_VERBOSE,
1071                       "AFSExamineDirectory Deleting object %p\n",
1072                       pCurrentChildObject);
1073
1074         AFSDeleteObjectInfo( &pCurrentChildObject);
1075     }
1076     else
1077     {
1078
1079         AFSReleaseResource( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock);
1080     }
1081
1082     return bFcbBusy;
1083 }
1084
1085 //
1086 // Called with VolumeCB->ObjectInfoTree.TreeLock held shared.
1087 // The TreeLock will be released unless *pbReleaseVolumeLock is set to FALSE.
1088 //
1089
1090 static BOOLEAN
1091 AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
1092                       IN BOOLEAN           bVolumeObject,
1093                       IN OUT BOOLEAN     * pbReleaseVolumeLock)
1094 {
1095     NTSTATUS ntStatus = STATUS_SUCCESS;
1096     AFSDeviceExt *pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1097     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1098     AFSDirectoryCB *pCurrentDirEntry = NULL, *pNextDirEntry = NULL;
1099     AFSObjectInfoCB *pCurrentChildObject = NULL;
1100     AFSVolumeCB * pVolumeCB = pCurrentObject->VolumeCB;
1101     LARGE_INTEGER liCurrentTime;
1102     BOOLEAN bFcbBusy = FALSE;
1103     LONG lCount;
1104     BOOLEAN bTemp;
1105
1106     switch ( pCurrentObject->FileType) {
1107
1108     case AFS_FILE_TYPE_DIRECTORY:
1109         {
1110
1111             if ( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
1112             {
1113
1114                 return FALSE;
1115             }
1116
1117             //
1118             // If this object is deleted then remove it from the parent, if we can
1119             //
1120
1121             if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DELETED) &&
1122                 pCurrentObject->ObjectReferenceCount <= 0 &&
1123                 ( pCurrentObject->Fcb == NULL ||
1124                   pCurrentObject->Fcb->OpenReferenceCount == 0) &&
1125                 pCurrentObject->Specific.Directory.DirectoryNodeListHead == NULL &&
1126                 pCurrentObject->Specific.Directory.ChildOpenReferenceCount == 0)
1127             {
1128
1129                 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1130
1131                 //
1132                 // Dropping the TreeLock permits the
1133                 // pCurrentObject->ObjectReferenceCount to change
1134                 //
1135
1136                 if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1137                                     FALSE))
1138                 {
1139
1140                     AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
1141                                     TRUE);
1142
1143                     if ( pCurrentObject->ObjectReferenceCount <= 0)
1144                     {
1145
1146                         AFSRemoveFcb( &pCurrentObject->Fcb);
1147
1148                         if( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
1149                         {
1150
1151                             AFSAcquireExcl( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock,
1152                                             TRUE);
1153
1154                             AFSRemoveFcb( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
1155
1156                             AFSReleaseResource( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
1157
1158                             AFSDeleteObjectInfo( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
1159
1160                             ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
1161
1162                             AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
1163
1164                             AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
1165                                           AFS_TRACE_LEVEL_VERBOSE,
1166                                           "AFSExamineObjectInfo (pioctl) AFS_DIR_ENTRY_TAG deallocating %p\n",
1167                                           pCurrentObject->Specific.Directory.PIOCtlDirectoryCB);
1168
1169                             AFSExFreePoolWithTag( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
1170                         }
1171
1172                         AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1173
1174                         AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1175                                       AFS_TRACE_LEVEL_VERBOSE,
1176                                       "AFSExamineObjectInfo Deleting deleted object %p\n",
1177                                       pCurrentObject);
1178
1179                         AFSDeleteObjectInfo( &pCurrentObject);
1180                     }
1181                     else
1182                     {
1183
1184                         AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1185                     }
1186
1187                     AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1188                 }
1189                 else
1190                 {
1191
1192                     *pbReleaseVolumeLock = FALSE;
1193                 }
1194
1195                 return bFcbBusy;
1196             }
1197
1198             if ( pCurrentObject->Fcb != NULL &&
1199                  pCurrentObject->Fcb->CcbListHead != NULL)
1200             {
1201
1202                 AFSCcb *pCcb;
1203
1204                 for ( pCcb = pCurrentObject->Fcb->CcbListHead;
1205                       pCcb;
1206                       pCcb = (AFSCcb *)pCcb->ListEntry.fLink)
1207                 {
1208
1209                     if ( pCcb->NameArray) {
1210
1211                         AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1212                                       AFS_TRACE_LEVEL_VERBOSE,
1213                                       "AFSExamineObjectInfo Found Object %p Fcb %p Ccb %p\n",
1214                                       pCurrentObject,
1215                                       pCurrentObject->Fcb,
1216                                       pCcb);
1217                     }
1218                 }
1219
1220                 return bFcbBusy;
1221             }
1222
1223             if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0 ||
1224                 ( pCurrentObject->Fcb != NULL &&
1225                   pCurrentObject->Fcb->OpenReferenceCount > 0))
1226             {
1227
1228                 return bFcbBusy;
1229             }
1230
1231             if ( pCurrentObject->FileType != AFS_FILE_TYPE_DIRECTORY ||
1232                  pCurrentObject->Specific.Directory.DirectoryNodeListHead != NULL)
1233             {
1234
1235                 if( !AFSAcquireShared( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
1236                                        FALSE))
1237                 {
1238
1239                     return bFcbBusy;
1240                 }
1241
1242                 pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
1243
1244                 //
1245                 // Directory Entry Processing
1246                 //
1247
1248                 KeQueryTickCount( &liCurrentTime);
1249
1250                 while( pCurrentDirEntry != NULL)
1251                 {
1252
1253                     if( pCurrentDirEntry->DirOpenReferenceCount > 0)
1254                     {
1255
1256                         break;
1257                     }
1258
1259                     if ( pCurrentDirEntry->NameArrayReferenceCount > 0)
1260                     {
1261
1262                         break;
1263                     }
1264
1265                     if ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1266                          pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0)
1267                     {
1268
1269                         break;
1270                     }
1271
1272                     if ( liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart ||
1273                          liCurrentTime.QuadPart - pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart <
1274                          pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
1275                     {
1276
1277                         break;
1278                     }
1279
1280                     if ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY)
1281                     {
1282
1283                         if ( pCurrentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL)
1284                         {
1285
1286                             break;
1287                         }
1288
1289                         if ( pCurrentDirEntry->ObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)
1290                         {
1291
1292                             break;
1293                         }
1294                     }
1295
1296                     if ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE)
1297                     {
1298
1299                         if ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1300                              pCurrentDirEntry->ObjectInformation->Fcb->Specific.File.ExtentsDirtyCount > 0)
1301                         {
1302
1303                             break;
1304                         }
1305                     }
1306
1307                     pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
1308                 }
1309
1310                 if( pCurrentDirEntry != NULL)
1311                 {
1312
1313                     AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1314
1315                     return bFcbBusy;
1316                 }
1317
1318                 AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1319
1320                 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1321
1322                 //
1323                 // Now acquire the locks excl without deadlocking
1324                 //
1325
1326                 if( AFSAcquireExcl( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
1327                                     FALSE))
1328                 {
1329
1330                     if( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1331                                          FALSE))
1332                     {
1333
1334                         AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1335
1336                         *pbReleaseVolumeLock = FALSE;
1337
1338                         return bFcbBusy;
1339                     }
1340
1341                     if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0)
1342                     {
1343
1344                         AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1345
1346                         AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1347
1348                         return bFcbBusy;
1349                     }
1350
1351                     KeQueryTickCount( &liCurrentTime);
1352
1353                     pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
1354
1355                     while( pCurrentDirEntry != NULL)
1356                     {
1357
1358                         if( pCurrentDirEntry->DirOpenReferenceCount > 0)
1359                         {
1360
1361                             break;
1362                         }
1363
1364                         if ( pCurrentDirEntry->NameArrayReferenceCount > 0)
1365                         {
1366
1367                             break;
1368                         }
1369
1370                         if ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1371                              pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0)
1372                         {
1373
1374                             break;
1375                         }
1376
1377                         if ( liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart ||
1378                              liCurrentTime.QuadPart - pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart <
1379                              pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
1380                         {
1381
1382                             break;
1383                         }
1384
1385                         if ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY)
1386                         {
1387
1388                             if ( pCurrentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL)
1389                             {
1390
1391                                 break;
1392                             }
1393
1394                             if ( pCurrentDirEntry->ObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)
1395                             {
1396
1397                                 break;
1398                             }
1399                         }
1400
1401                         if ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE)
1402                         {
1403
1404                             if ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1405                                  pCurrentDirEntry->ObjectInformation->Fcb->Specific.File.ExtentsDirtyCount > 0)
1406                             {
1407
1408                                 break;
1409                             }
1410                         }
1411
1412                         pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
1413                     }
1414
1415                     if( pCurrentDirEntry != NULL)
1416                     {
1417
1418                         AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1419
1420                         AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1421
1422                         return bFcbBusy;
1423                     }
1424
1425                     pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
1426
1427                     while( pCurrentDirEntry != NULL)
1428                     {
1429
1430                         pNextDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
1431
1432                         AFSExamineDirectory( pCurrentObject,
1433                                              pCurrentDirEntry);
1434
1435                         pCurrentDirEntry = pNextDirEntry;
1436                     }
1437
1438                     //
1439                     // Clear our enumerated flag on this object so we retrieve info again on next access
1440                     //
1441
1442                     ClearFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED);
1443
1444                     AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1445
1446                     AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1447                 }
1448                 else
1449                 {
1450
1451                     //
1452                     // Try to grab the volume lock again ... no problem if we don't
1453                     //
1454
1455                     if( !AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1456                                            FALSE))
1457                     {
1458
1459                         *pbReleaseVolumeLock = FALSE;
1460
1461                         return bFcbBusy;
1462                     }
1463                 }
1464             }
1465             else if ( bVolumeObject == FALSE)
1466             {
1467                 //
1468                 // No children
1469                 //
1470
1471                 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1472
1473                 if ( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1474                                       FALSE))
1475                 {
1476
1477                     *pbReleaseVolumeLock = FALSE;
1478
1479                     return bFcbBusy;
1480                 }
1481
1482                 AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
1483                                 TRUE);
1484
1485                 KeQueryTickCount( &liCurrentTime);
1486
1487                 if( pCurrentObject->ObjectReferenceCount <= 0 &&
1488                     ( pCurrentObject->Fcb == NULL ||
1489                       pCurrentObject->Fcb->OpenReferenceCount <= 0) &&
1490                     liCurrentTime.QuadPart > pCurrentObject->LastAccessCount.QuadPart &&
1491                     liCurrentTime.QuadPart - pCurrentObject->LastAccessCount.QuadPart >
1492                     pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
1493                 {
1494
1495                     AFSRemoveFcb( &pCurrentObject->Fcb);
1496
1497                     AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1498
1499                     AFSDeleteObjectInfo( &pCurrentObject);
1500                 }
1501                 else
1502                 {
1503
1504                     AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1505                 }
1506
1507                 AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1508             }
1509         }
1510         break;
1511
1512     case AFS_FILE_TYPE_FILE:
1513         {
1514
1515             lCount = AFSObjectInfoIncrement( pCurrentObject,
1516                                              AFS_OBJECT_REFERENCE_WORKER);
1517
1518             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1519                           AFS_TRACE_LEVEL_VERBOSE,
1520                           "AFSExamineObjectInfo Increment3 count on object %p Cnt %d\n",
1521                           pCurrentObject,
1522                           lCount);
1523
1524             AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1525
1526             if( pCurrentObject->Fcb != NULL)
1527             {
1528
1529                 //
1530                 // Dropping the TreeLock permits the
1531                 // pCurrentObject->ObjectReferenceCount to change
1532                 //
1533
1534                 ntStatus = AFSCleanupFcb( pCurrentObject->Fcb,
1535                                           FALSE);
1536
1537                 if ( ntStatus == STATUS_RETRY)
1538                 {
1539
1540                     bFcbBusy = TRUE;
1541                 }
1542             }
1543
1544             bTemp = AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1545                                     FALSE);
1546
1547             lCount = AFSObjectInfoDecrement( pCurrentObject,
1548                                              AFS_OBJECT_REFERENCE_WORKER);
1549
1550             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1551                           AFS_TRACE_LEVEL_VERBOSE,
1552                           "AFSExamineObjectInfo Decrement3 count on object %p Cnt %d\n",
1553                           pCurrentObject,
1554                           lCount);
1555
1556
1557             if ( bTemp == FALSE)
1558             {
1559
1560                 *pbReleaseVolumeLock = FALSE;
1561
1562                 return bFcbBusy;
1563             }
1564
1565             AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
1566                             TRUE);
1567
1568             KeQueryTickCount( &liCurrentTime);
1569
1570             if( pCurrentObject->ObjectReferenceCount <= 0 &&
1571                 ( pCurrentObject->Fcb == NULL ||
1572                   ( pCurrentObject->Fcb->OpenReferenceCount <= 0 &&
1573                     pCurrentObject->Fcb->Specific.File.ExtentsDirtyCount <= 0)) &&
1574                 liCurrentTime.QuadPart > pCurrentObject->LastAccessCount.QuadPart &&
1575                 liCurrentTime.QuadPart - pCurrentObject->LastAccessCount.QuadPart >
1576                 pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
1577             {
1578
1579                 AFSRemoveFcb( &pCurrentObject->Fcb);
1580
1581                 AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1582
1583                 AFSDeleteObjectInfo( &pCurrentObject);
1584             }
1585             else
1586             {
1587
1588                 AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1589             }
1590
1591             AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1592         }
1593         break;
1594
1595     default:
1596         {
1597
1598             AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1599
1600             if ( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1601                                   FALSE))
1602             {
1603
1604                 *pbReleaseVolumeLock = FALSE;
1605
1606                 return bFcbBusy;
1607             }
1608
1609             AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
1610                             TRUE);
1611
1612             KeQueryTickCount( &liCurrentTime);
1613
1614             if( pCurrentObject->ObjectReferenceCount <= 0 &&
1615                 ( pCurrentObject->Fcb == NULL ||
1616                   pCurrentObject->Fcb->OpenReferenceCount <= 0) &&
1617                 liCurrentTime.QuadPart > pCurrentObject->LastAccessCount.QuadPart &&
1618                 liCurrentTime.QuadPart - pCurrentObject->LastAccessCount.QuadPart >
1619                 pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
1620             {
1621
1622                 AFSRemoveFcb( &pCurrentObject->Fcb);
1623
1624                 AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1625
1626                 AFSDeleteObjectInfo( &pCurrentObject);
1627             }
1628             else
1629             {
1630
1631                 AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1632             }
1633
1634             AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1635         }
1636     }
1637
1638     return bFcbBusy;
1639 }
1640
1641
1642 static BOOLEAN
1643 AFSExamineVolume( IN AFSVolumeCB *pVolumeCB)
1644 {
1645     NTSTATUS ntStatus = STATUS_SUCCESS;
1646     AFSObjectInfoCB *pCurrentObject = NULL, *pNextObject = NULL;
1647     BOOLEAN bReleaseVolumeLock = FALSE;
1648     BOOLEAN bVolumeObject = FALSE;
1649     BOOLEAN bFcbBusy = FALSE;
1650     LONG lCount;
1651
1652     if( AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1653                           FALSE))
1654     {
1655
1656         bReleaseVolumeLock = TRUE;
1657
1658         pCurrentObject = pVolumeCB->ObjectInfoListHead;
1659
1660         pNextObject = NULL;
1661
1662         while( pCurrentObject != NULL)
1663         {
1664
1665             if( pCurrentObject != &pVolumeCB->ObjectInformation)
1666             {
1667
1668                 pNextObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1669
1670                 //
1671                 // If the end of the VolumeCB ObjectInfo List is reached, then
1672                 // the next ObjectInformationCB to examine is the one embedded within
1673                 // the VolumeCB itself except when the VolumeCB is the AFSGlobalRoot.
1674                 //
1675                 // bVolumeObject is used to indicate whether the embedded ObjectInfoCB
1676                 // is being examined.
1677                 //
1678
1679                 if( pNextObject == NULL &&
1680                     pVolumeCB != AFSGlobalRoot)  // Don't free up the root of the global
1681                 {
1682
1683                     pNextObject = &pVolumeCB->ObjectInformation;
1684                 }
1685
1686                 bVolumeObject = FALSE;
1687
1688                 if ( pNextObject)
1689                 {
1690
1691                     lCount = AFSObjectInfoIncrement( pNextObject,
1692                                                      AFS_OBJECT_REFERENCE_WORKER);
1693
1694                     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1695                                   AFS_TRACE_LEVEL_VERBOSE,
1696                                   "AFSExamineVolume Increment count on object %p Cnt %d\n",
1697                                   pNextObject,
1698                                   lCount);
1699                 }
1700             }
1701             else
1702             {
1703
1704                 pNextObject = NULL;
1705
1706                 bVolumeObject = TRUE;
1707             }
1708
1709             bFcbBusy = AFSExamineObjectInfo( pCurrentObject, bVolumeObject, &bReleaseVolumeLock);
1710
1711             if ( pNextObject)
1712             {
1713
1714                 lCount = AFSObjectInfoDecrement( pNextObject,
1715                                                  AFS_OBJECT_REFERENCE_WORKER);
1716
1717                 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1718                               AFS_TRACE_LEVEL_VERBOSE,
1719                               "AFSExamineVolume Decrement count on object %p Cnt %d\n",
1720                               pNextObject,
1721                               lCount);
1722             }
1723
1724             //
1725             // If AFSExamineObjectInfo drops the VolumeLock before returning
1726             // we must halt processing of the Volume's ObjectInfo list.
1727             //
1728
1729             if ( bReleaseVolumeLock == FALSE)
1730             {
1731
1732                 break;
1733             }
1734
1735             pCurrentObject = pNextObject;
1736         }
1737
1738         if( bReleaseVolumeLock)
1739         {
1740
1741             AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1742         }
1743     }
1744
1745     return bFcbBusy;
1746 }
1747
1748 void
1749 AFSPrimaryVolumeWorkerThread( IN PVOID Context)
1750 {
1751
1752     UNREFERENCED_PARAMETER(Context);
1753     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)&AFSGlobalRoot->NonPagedVcb->VolumeWorkerContext;
1754     AFSDeviceExt *pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1755     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1756     LARGE_INTEGER DueTime;
1757     LONG TimeOut;
1758     KTIMER Timer;
1759     AFSVolumeCB *pVolumeCB = NULL, *pNextVolume = NULL;
1760     BOOLEAN bFcbBusy = FALSE;
1761     LONG lCount;
1762
1763     AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1764                   AFS_TRACE_LEVEL_VERBOSE,
1765                   "AFSPrimaryVolumeWorkerThread Initialized\n");
1766
1767     //
1768     // Initialize the timer for the worker thread
1769     //
1770
1771     DueTime.QuadPart = -(5000);
1772
1773     TimeOut = 5000;
1774
1775     KeInitializeTimerEx( &Timer,
1776                          SynchronizationTimer);
1777
1778     KeSetTimerEx( &Timer,
1779                   DueTime,
1780                   TimeOut,
1781                   NULL);
1782
1783     //
1784     // Indicate that we are initialized and ready
1785     //
1786
1787     KeSetEvent( &pPoolContext->WorkerThreadReady,
1788                 0,
1789                 FALSE);
1790
1791     //
1792     // Indicate we are initialized
1793     //
1794
1795     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
1796
1797     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
1798     {
1799
1800         if ( bFcbBusy == FALSE)
1801         {
1802
1803             KeWaitForSingleObject( &Timer,
1804                                    Executive,
1805                                    KernelMode,
1806                                    FALSE,
1807                                    NULL);
1808         }
1809         else
1810         {
1811
1812             bFcbBusy = FALSE;
1813         }
1814
1815         //
1816         // This is the primary volume worker so it will traverse the volume list
1817         // looking for cleanup or volumes requiring private workers
1818         //
1819
1820         AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1821                           TRUE);
1822
1823         pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead;
1824
1825         while( pVolumeCB != NULL)
1826         {
1827
1828             if( pVolumeCB == AFSGlobalRoot ||
1829                 !AFSAcquireExcl( pVolumeCB->VolumeLock,
1830                                  FALSE))
1831             {
1832
1833                 pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1834
1835                 continue;
1836             }
1837
1838             if( pVolumeCB->ObjectInfoListHead == NULL)
1839             {
1840
1841                 AFSReleaseResource( pVolumeCB->VolumeLock);
1842
1843                 AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1844
1845                 AFSAcquireExcl( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock,
1846                                 TRUE);
1847
1848                 AFSAcquireExcl( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1849                                 TRUE);
1850
1851                 if( !AFSAcquireExcl( pVolumeCB->VolumeLock,
1852                                      FALSE))
1853                 {
1854
1855                     AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1856
1857                     AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
1858
1859                     pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1860
1861                     continue;
1862                 }
1863
1864                 pNextVolume = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1865
1866                 AFSAcquireShared( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock,
1867                                   TRUE);
1868
1869                 //
1870                 // If VolumeCB is idle, the Volume can be garbage collected
1871                 //
1872
1873                 if( pVolumeCB->ObjectInfoListHead == NULL &&
1874                     pVolumeCB->DirectoryCB->DirOpenReferenceCount <= 0 &&
1875                     pVolumeCB->DirectoryCB->NameArrayReferenceCount <= 0 &&
1876                     pVolumeCB->VolumeReferenceCount == 0 &&
1877                     ( pVolumeCB->RootFcb == NULL ||
1878                       pVolumeCB->RootFcb->OpenReferenceCount == 0) &&
1879                     pVolumeCB->ObjectInformation.ObjectReferenceCount <= 0)
1880                 {
1881
1882                     AFSRemoveRootFcb( pVolumeCB);
1883
1884                     AFSReleaseResource( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
1885
1886                     AFSRemoveVolume( pVolumeCB);
1887                 }
1888                 else
1889                 {
1890
1891                     AFSReleaseResource( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
1892
1893                     AFSReleaseResource( pVolumeCB->VolumeLock);
1894                 }
1895
1896                 AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1897
1898                 AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
1899
1900                 pVolumeCB = pNextVolume;
1901
1902                 continue;
1903             }
1904
1905             //
1906             // Don't need this lock anymore now that we have a volume cb to work with
1907             //
1908
1909             AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1910
1911             //
1912             // For now we only need the volume lock shared
1913             //
1914
1915             AFSConvertToShared( pVolumeCB->VolumeLock);
1916
1917             AFSExamineVolume( pVolumeCB);
1918
1919             //
1920             // Next volume cb
1921             //
1922
1923             AFSReleaseResource( pVolumeCB->VolumeLock);
1924
1925             AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1926                               TRUE);
1927
1928             pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1929         }
1930
1931         AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1932
1933     } // worker thread loop
1934
1935     KeCancelTimer( &Timer);
1936
1937     ClearFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
1938
1939     AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1940                   AFS_TRACE_LEVEL_VERBOSE,
1941                   "AFSPrimaryVolumeWorkerThread Exiting\n");
1942
1943     lCount = InterlockedDecrement( &pControlDeviceExt->Specific.Control.VolumeWorkerThreadCount);
1944
1945     if( lCount == 0)
1946     {
1947
1948         KeSetEvent( &pControlDeviceExt->Specific.Control.VolumeWorkerCloseEvent,
1949                     0,
1950                     FALSE);
1951     }
1952
1953     PsTerminateSystemThread( 0);
1954
1955     return;
1956 }
1957
1958 NTSTATUS
1959 AFSInsertWorkitem( IN AFSWorkItem *WorkItem)
1960 {
1961
1962     NTSTATUS ntStatus = STATUS_SUCCESS;
1963     AFSDeviceExt *pDevExt = NULL;
1964     LONG lCount;
1965
1966     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1967
1968     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1969                   AFS_TRACE_LEVEL_VERBOSE,
1970                   "AFSInsertWorkitem Acquiring Control QueueLock lock %p EXCL %08lX\n",
1971                   &pDevExt->Specific.Library.QueueLock,
1972                   PsGetCurrentThread());
1973
1974     AFSAcquireExcl( &pDevExt->Specific.Library.QueueLock,
1975                     TRUE);
1976
1977     lCount = InterlockedIncrement( &pDevExt->Specific.Library.QueueItemCount);
1978
1979     AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
1980                   AFS_TRACE_LEVEL_VERBOSE,
1981                   "AFSInsertWorkitem Inserting work item %p Count %d\n",
1982                   WorkItem,
1983                   lCount);
1984
1985     if( pDevExt->Specific.Library.QueueTail != NULL) // queue already has nodes
1986     {
1987
1988         pDevExt->Specific.Library.QueueTail->next = WorkItem;
1989     }
1990     else // first node
1991     {
1992
1993         pDevExt->Specific.Library.QueueHead = WorkItem;
1994     }
1995
1996     WorkItem->next = NULL;
1997     pDevExt->Specific.Library.QueueTail = WorkItem;
1998
1999     // indicate that the queue has nodes
2000     KeSetEvent( &(pDevExt->Specific.Library.WorkerQueueHasItems),
2001                 0,
2002                 FALSE);
2003
2004     AFSReleaseResource( &pDevExt->Specific.Library.QueueLock);
2005
2006     return ntStatus;
2007 }
2008
2009 NTSTATUS
2010 AFSInsertIOWorkitem( IN AFSWorkItem *WorkItem)
2011 {
2012
2013     NTSTATUS ntStatus = STATUS_SUCCESS;
2014     AFSDeviceExt *pDevExt = NULL;
2015     LONG lCount;
2016
2017     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
2018
2019     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2020                   AFS_TRACE_LEVEL_VERBOSE,
2021                   "AFSInsertIOWorkitem Acquiring Control QueueLock lock %p EXCL %08lX\n",
2022                   &pDevExt->Specific.Library.IOQueueLock,
2023                   PsGetCurrentThread());
2024
2025     AFSAcquireExcl( &pDevExt->Specific.Library.IOQueueLock,
2026                     TRUE);
2027
2028     lCount = InterlockedIncrement( &pDevExt->Specific.Library.IOQueueItemCount);
2029
2030     AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2031                   AFS_TRACE_LEVEL_VERBOSE,
2032                   "AFSInsertWorkitem Inserting IO work item %p Count %d\n",
2033                   WorkItem,
2034                   lCount);
2035
2036     if( pDevExt->Specific.Library.IOQueueTail != NULL) // queue already has nodes
2037     {
2038
2039         pDevExt->Specific.Library.IOQueueTail->next = WorkItem;
2040     }
2041     else // first node
2042     {
2043
2044         pDevExt->Specific.Library.IOQueueHead = WorkItem;
2045     }
2046
2047     WorkItem->next = NULL;
2048     pDevExt->Specific.Library.IOQueueTail = WorkItem;
2049
2050     // indicate that the queue has nodes
2051     KeSetEvent( &(pDevExt->Specific.Library.IOWorkerQueueHasItems),
2052                 0,
2053                 FALSE);
2054
2055     AFSReleaseResource( &pDevExt->Specific.Library.IOQueueLock);
2056
2057     return ntStatus;
2058 }
2059
2060 NTSTATUS
2061 AFSInsertWorkitemAtHead( IN AFSWorkItem *WorkItem)
2062 {
2063
2064     NTSTATUS ntStatus = STATUS_SUCCESS;
2065     AFSDeviceExt *pDevExt = NULL;
2066     LONG lCount;
2067
2068     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
2069
2070     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2071                   AFS_TRACE_LEVEL_VERBOSE,
2072                   "AFSInsertWorkitemAtHead Acquiring Control QueueLock lock %p EXCL %08lX\n",
2073                   &pDevExt->Specific.Library.QueueLock,
2074                   PsGetCurrentThread());
2075
2076     AFSAcquireExcl( &pDevExt->Specific.Library.QueueLock,
2077                     TRUE);
2078
2079     WorkItem->next = pDevExt->Specific.Library.QueueHead;
2080
2081     pDevExt->Specific.Library.QueueHead = WorkItem;
2082
2083     lCount = InterlockedIncrement( &pDevExt->Specific.Library.QueueItemCount);
2084
2085     AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2086                   AFS_TRACE_LEVEL_VERBOSE,
2087                   "AFSInsertWorkitemAtHead Inserting work item %p Count %d\n",
2088                   WorkItem,
2089                   lCount);
2090
2091     //
2092     // indicate that the queue has nodes
2093     //
2094
2095     KeSetEvent( &(pDevExt->Specific.Library.WorkerQueueHasItems),
2096                 0,
2097                 FALSE);
2098
2099     AFSReleaseResource( &pDevExt->Specific.Library.QueueLock);
2100
2101     return ntStatus;
2102 }
2103
2104 AFSWorkItem *
2105 AFSRemoveWorkItem()
2106 {
2107
2108     AFSWorkItem        *pWorkItem = NULL;
2109     AFSDeviceExt *pDevExt = NULL;
2110     LONG lCount;
2111
2112     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
2113
2114     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2115                   AFS_TRACE_LEVEL_VERBOSE,
2116                   "AFSRemoveWorkItem Acquiring Control QueueLock lock %p EXCL %08lX\n",
2117                   &pDevExt->Specific.Library.QueueLock,
2118                   PsGetCurrentThread());
2119
2120     AFSAcquireExcl( &pDevExt->Specific.Library.QueueLock,
2121                     TRUE);
2122
2123     if( pDevExt->Specific.Library.QueueHead != NULL) // queue has nodes
2124     {
2125
2126         pWorkItem = pDevExt->Specific.Library.QueueHead;
2127
2128         lCount = InterlockedDecrement( &pDevExt->Specific.Library.QueueItemCount);
2129
2130         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2131                       AFS_TRACE_LEVEL_VERBOSE,
2132                       "AFSRemoveWorkItem Removing work item %p Count %d Thread %08lX\n",
2133                       pWorkItem,
2134                       lCount,
2135                       PsGetCurrentThreadId());
2136
2137         pDevExt->Specific.Library.QueueHead = pDevExt->Specific.Library.QueueHead->next;
2138
2139         if( pDevExt->Specific.Library.QueueHead == NULL) // if queue just became empty
2140         {
2141
2142             pDevExt->Specific.Library.QueueTail = NULL;
2143         }
2144         else
2145         {
2146
2147             //
2148             // Wake up another worker
2149             //
2150
2151             KeSetEvent( &(pDevExt->Specific.Library.WorkerQueueHasItems),
2152                         0,
2153                         FALSE);
2154         }
2155     }
2156
2157     AFSReleaseResource( &pDevExt->Specific.Library.QueueLock);
2158
2159     return pWorkItem;
2160 }
2161
2162 AFSWorkItem *
2163 AFSRemoveIOWorkItem()
2164 {
2165
2166     AFSWorkItem        *pWorkItem = NULL;
2167     AFSDeviceExt *pDevExt = NULL;
2168     LONG lCount;
2169
2170     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
2171
2172     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2173                   AFS_TRACE_LEVEL_VERBOSE,
2174                   "AFSRemoveIOWorkItem Acquiring Control QueueLock lock %p EXCL %08lX\n",
2175                   &pDevExt->Specific.Library.IOQueueLock,
2176                   PsGetCurrentThread());
2177
2178     AFSAcquireExcl( &pDevExt->Specific.Library.IOQueueLock,
2179                     TRUE);
2180
2181     if( pDevExt->Specific.Library.IOQueueHead != NULL) // queue has nodes
2182     {
2183
2184         pWorkItem = pDevExt->Specific.Library.IOQueueHead;
2185
2186         lCount = InterlockedDecrement( &pDevExt->Specific.Library.IOQueueItemCount);
2187
2188         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2189                       AFS_TRACE_LEVEL_VERBOSE,
2190                       "AFSRemoveWorkItem Removing work item %p Count %d Thread %08lX\n",
2191                       pWorkItem,
2192                       lCount,
2193                       PsGetCurrentThreadId());
2194
2195         pDevExt->Specific.Library.IOQueueHead = pDevExt->Specific.Library.IOQueueHead->next;
2196
2197         if( pDevExt->Specific.Library.IOQueueHead == NULL) // if queue just became empty
2198         {
2199
2200             pDevExt->Specific.Library.IOQueueTail = NULL;
2201         }
2202         else
2203         {
2204
2205             //
2206             // Wake up another worker
2207             //
2208
2209             KeSetEvent( &(pDevExt->Specific.Library.IOWorkerQueueHasItems),
2210                         0,
2211                         FALSE);
2212         }
2213     }
2214
2215     AFSReleaseResource( &pDevExt->Specific.Library.IOQueueLock);
2216
2217     return pWorkItem;
2218 }
2219
2220 NTSTATUS
2221 AFSQueueWorkerRequest( IN AFSWorkItem *WorkItem)
2222 {
2223
2224     NTSTATUS ntStatus = STATUS_SUCCESS;
2225     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
2226
2227     //
2228     // Submit the work item to the worker
2229     //
2230
2231     ntStatus = AFSInsertWorkitem( WorkItem);
2232
2233     if( bWait)
2234     {
2235
2236         //
2237         // Sync request so block on the work item event
2238         //
2239
2240         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2241                                           Executive,
2242                                           KernelMode,
2243                                           FALSE,
2244                                           NULL);
2245     }
2246
2247     return ntStatus;
2248 }
2249
2250 NTSTATUS
2251 AFSQueueIOWorkerRequest( IN AFSWorkItem *WorkItem)
2252 {
2253
2254     NTSTATUS ntStatus = STATUS_SUCCESS;
2255     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
2256
2257     //
2258     // Submit the work item to the worker
2259     //
2260
2261     ntStatus = AFSInsertIOWorkitem( WorkItem);
2262
2263     if( bWait)
2264     {
2265
2266         //
2267         // Sync request so block on the work item event
2268         //
2269
2270         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2271                                           Executive,
2272                                           KernelMode,
2273                                           FALSE,
2274                                           NULL);
2275     }
2276
2277     return ntStatus;
2278 }
2279
2280 NTSTATUS
2281 AFSQueueWorkerRequestAtHead( IN AFSWorkItem *WorkItem)
2282 {
2283
2284     NTSTATUS ntStatus = STATUS_SUCCESS;
2285     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
2286
2287     //
2288     // Submit the work item to the worker
2289     //
2290
2291     ntStatus = AFSInsertWorkitemAtHead( WorkItem);
2292
2293     if( bWait)
2294     {
2295
2296         //
2297         // Sync request so block on the work item event
2298         //
2299
2300         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2301                                           Executive,
2302                                           KernelMode,
2303                                           FALSE,
2304                                           NULL);
2305     }
2306
2307     return ntStatus;
2308 }
2309
2310 NTSTATUS
2311 AFSQueueFlushExtents( IN AFSFcb *Fcb,
2312                       IN GUID *AuthGroup)
2313 {
2314
2315     NTSTATUS ntStatus = STATUS_SUCCESS;
2316     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
2317     AFSWorkItem *pWorkItem = NULL;
2318     LONG lCount;
2319
2320     __try
2321     {
2322
2323         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2324                       AFS_TRACE_LEVEL_VERBOSE,
2325                       "AFSQueueFlushExtents Queuing request for FID %08lX-%08lX-%08lX-%08lX\n",
2326                       Fcb->ObjectInformation->FileId.Cell,
2327                       Fcb->ObjectInformation->FileId.Volume,
2328                       Fcb->ObjectInformation->FileId.Vnode,
2329                       Fcb->ObjectInformation->FileId.Unique);
2330
2331         //
2332         // Increment our flush count here just to keep the number of items in the
2333         // queue down. We'll decrement it just below.
2334         //
2335
2336         lCount = InterlockedIncrement( &Fcb->Specific.File.QueuedFlushCount);
2337
2338         if( lCount > 3)
2339         {
2340
2341             AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2342                           AFS_TRACE_LEVEL_VERBOSE,
2343                           "AFSQueueFlushExtents Max queued items for FID %08lX-%08lX-%08lX-%08lX\n",
2344                           Fcb->ObjectInformation->FileId.Cell,
2345                           Fcb->ObjectInformation->FileId.Volume,
2346                           Fcb->ObjectInformation->FileId.Vnode,
2347                           Fcb->ObjectInformation->FileId.Unique);
2348
2349             try_return( ntStatus);
2350         }
2351
2352         if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
2353         {
2354
2355             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2356                           AFS_TRACE_LEVEL_ERROR,
2357                           "AFSQueueFlushExtents Failing request, in shutdown\n");
2358
2359             try_return( ntStatus = STATUS_TOO_LATE);
2360         }
2361
2362         //
2363         // Allocate our request structure and send it to the worker
2364         //
2365
2366         pWorkItem = (AFSWorkItem *)AFSLibExAllocatePoolWithTag( NonPagedPool,
2367                                                                 sizeof( AFSWorkItem),
2368                                                                 AFS_WORK_ITEM_TAG);
2369
2370         if( pWorkItem == NULL)
2371         {
2372
2373             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2374                           AFS_TRACE_LEVEL_ERROR,
2375                           "AFSQueueFlushExtents Failed to allocate work item\n");
2376
2377             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2378         }
2379
2380         RtlZeroMemory( pWorkItem,
2381                        sizeof( AFSWorkItem));
2382
2383         pWorkItem->Size = sizeof( AFSWorkItem);
2384
2385         pWorkItem->ProcessID = (ULONGLONG)PsGetCurrentProcessId();
2386
2387         pWorkItem->RequestType = AFS_WORK_FLUSH_FCB;
2388
2389         if ( AuthGroup == NULL)
2390         {
2391
2392             RtlZeroMemory( &pWorkItem->AuthGroup,
2393                            sizeof( GUID));
2394
2395             ntStatus = AFSRetrieveValidAuthGroup( Fcb,
2396                                                   NULL,
2397                                                   TRUE,
2398                                                   &pWorkItem->AuthGroup);
2399         }
2400         else
2401         {
2402             RtlCopyMemory( &pWorkItem->AuthGroup,
2403                            AuthGroup,
2404                            sizeof( GUID));
2405         }
2406
2407         pWorkItem->Specific.Fcb.Fcb = Fcb;
2408
2409         lCount = InterlockedIncrement( &Fcb->OpenReferenceCount);
2410
2411         AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
2412                       AFS_TRACE_LEVEL_VERBOSE,
2413                       "AFSQueueFlushExtents Increment count on Fcb %p Cnt %d\n",
2414                       Fcb,
2415                       lCount);
2416
2417         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2418                       AFS_TRACE_LEVEL_VERBOSE,
2419                       "AFSQueueFlushExtents Workitem %p for FID %08lX-%08lX-%08lX-%08lX\n",
2420                       pWorkItem,
2421                       Fcb->ObjectInformation->FileId.Cell,
2422                       Fcb->ObjectInformation->FileId.Volume,
2423                       Fcb->ObjectInformation->FileId.Vnode,
2424                       Fcb->ObjectInformation->FileId.Unique);
2425
2426         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2427
2428 try_exit:
2429
2430         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2431                       AFS_TRACE_LEVEL_VERBOSE,
2432                       "AFSQueueFlushExtents Request complete Status %08lX FID %08lX-%08lX-%08lX-%08lX\n",
2433                       Fcb->ObjectInformation->FileId.Cell,
2434                       Fcb->ObjectInformation->FileId.Volume,
2435                       Fcb->ObjectInformation->FileId.Vnode,
2436                       Fcb->ObjectInformation->FileId.Unique,
2437                       ntStatus);
2438
2439         //
2440         // Remove the count we added above
2441         //
2442
2443         lCount = InterlockedDecrement( &Fcb->Specific.File.QueuedFlushCount);
2444
2445         ASSERT( lCount >= 0);
2446
2447         if( lCount == 0)
2448         {
2449
2450             KeSetEvent( &Fcb->NPFcb->Specific.File.QueuedFlushEvent,
2451                         0,
2452                         FALSE);
2453         }
2454
2455         if( !NT_SUCCESS( ntStatus))
2456         {
2457
2458             if( pWorkItem != NULL)
2459             {
2460
2461                 lCount = InterlockedDecrement( &Fcb->OpenReferenceCount);
2462
2463                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2464             }
2465
2466             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2467                           AFS_TRACE_LEVEL_ERROR,
2468                           "AFSQueueFlushExtents Failed to queue request Status %08lX\n", ntStatus);
2469         }
2470     }
2471     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2472     {
2473
2474         AFSDbgLogMsg( 0,
2475                       0,
2476                       "EXCEPTION - AFSQueueFlushExtents\n");
2477
2478         AFSDumpTraceFilesFnc();
2479     }
2480
2481     return ntStatus;
2482 }
2483
2484 NTSTATUS
2485 AFSQueueGlobalRootEnumeration()
2486 {
2487
2488     NTSTATUS ntStatus = STATUS_SUCCESS;
2489     AFSWorkItem *pWorkItem = NULL;
2490
2491     __try
2492     {
2493
2494         pWorkItem = (AFSWorkItem *) AFSLibExAllocatePoolWithTag( NonPagedPool,
2495                                                                  sizeof(AFSWorkItem),
2496                                                                  AFS_WORK_ITEM_TAG);
2497         if (NULL == pWorkItem)
2498         {
2499
2500             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2501                           AFS_TRACE_LEVEL_ERROR,
2502                           "AFSQueueGlobalRootEnumeration Failed to allocate work item\n");
2503
2504             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2505         }
2506
2507         RtlZeroMemory( pWorkItem,
2508                        sizeof(AFSWorkItem));
2509
2510         pWorkItem->Size = sizeof( AFSWorkItem);
2511
2512         pWorkItem->RequestType = AFS_WORK_ENUMERATE_GLOBAL_ROOT;
2513
2514         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2515                       AFS_TRACE_LEVEL_VERBOSE,
2516                       "AFSQueueGlobalRootEnumeration Workitem %p\n",
2517                       pWorkItem);
2518
2519         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2520
2521 try_exit:
2522
2523         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2524                       AFS_TRACE_LEVEL_VERBOSE,
2525                       "AFSQueueGlobalRootEnumeration Request complete Status %08lX\n",
2526                       ntStatus);
2527
2528         if( !NT_SUCCESS( ntStatus))
2529         {
2530
2531             if( pWorkItem != NULL)
2532             {
2533
2534                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2535             }
2536
2537             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2538                           AFS_TRACE_LEVEL_ERROR,
2539                           "AFSQueueGlobalRootEnumeration Failed to queue request Status %08lX\n",
2540                           ntStatus);
2541         }
2542     }
2543     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2544     {
2545
2546         AFSDbgLogMsg( 0,
2547                       0,
2548                       "EXCEPTION - AFSQueueGlobalRootEnumeration\n");
2549
2550         AFSDumpTraceFilesFnc();
2551     }
2552
2553     return ntStatus;
2554 }
2555
2556 NTSTATUS
2557 AFSQueueStartIos( IN PFILE_OBJECT CacheFileObject,
2558                   IN UCHAR FunctionCode,
2559                   IN ULONG RequestFlags,
2560                   IN AFSIoRun *IoRuns,
2561                   IN ULONG RunCount,
2562                   IN AFSGatherIo *GatherIo)
2563 {
2564
2565     NTSTATUS ntStatus = STATUS_SUCCESS;
2566     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
2567     AFSWorkItem *pWorkItem = NULL;
2568
2569     __try
2570     {
2571
2572         if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
2573         {
2574
2575             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2576                           AFS_TRACE_LEVEL_ERROR,
2577                           "AFSQueueStartIos Failing request, in shutdown\n");
2578
2579             try_return( ntStatus = STATUS_TOO_LATE);
2580         }
2581
2582         //
2583         // Allocate our request structure and send it to the worker
2584         //
2585
2586         pWorkItem = (AFSWorkItem *)AFSLibExAllocatePoolWithTag( NonPagedPool,
2587                                                                 sizeof( AFSWorkItem),
2588                                                                 AFS_WORK_ITEM_TAG);
2589
2590         if( pWorkItem == NULL)
2591         {
2592
2593             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2594                           AFS_TRACE_LEVEL_ERROR,
2595                           "AFSQueueStartIos Failed to allocate work item\n");
2596
2597             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2598         }
2599
2600         RtlZeroMemory( pWorkItem,
2601                        sizeof( AFSWorkItem));
2602
2603         KeInitializeEvent( &pWorkItem->Event,
2604                            NotificationEvent,
2605                            FALSE);
2606
2607         pWorkItem->Size = sizeof( AFSWorkItem);
2608
2609         pWorkItem->ProcessID = (ULONGLONG)PsGetCurrentProcessId();
2610
2611         pWorkItem->RequestType = AFS_WORK_START_IOS;
2612
2613         pWorkItem->Specific.CacheAccess.CacheFileObject = CacheFileObject;
2614
2615         pWorkItem->Specific.CacheAccess.FunctionCode = FunctionCode;
2616
2617         pWorkItem->Specific.CacheAccess.RequestFlags = RequestFlags;
2618
2619         pWorkItem->Specific.CacheAccess.IoRuns = IoRuns;
2620
2621         pWorkItem->Specific.CacheAccess.RunCount = RunCount;
2622
2623         pWorkItem->Specific.CacheAccess.GatherIo = GatherIo;
2624
2625         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2626                       AFS_TRACE_LEVEL_VERBOSE,
2627                       "AFSQueueStartIos Queuing IO Workitem %p\n",
2628                       pWorkItem);
2629
2630         ntStatus = AFSQueueIOWorkerRequest( pWorkItem);
2631
2632 try_exit:
2633
2634         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2635                       AFS_TRACE_LEVEL_VERBOSE,
2636                       "AFSQueueStartIos Request complete Status %08lX\n",
2637                       ntStatus);
2638
2639         if( !NT_SUCCESS( ntStatus))
2640         {
2641
2642             if( pWorkItem != NULL)
2643             {
2644
2645                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2646             }
2647         }
2648     }
2649     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2650     {
2651
2652         AFSDbgLogMsg( 0,
2653                       0,
2654                       "EXCEPTION - AFSQueueStartIos\n");
2655
2656         AFSDumpTraceFilesFnc();
2657     }
2658
2659     return ntStatus;
2660 }
2661
2662 NTSTATUS
2663 AFSQueueInvalidateObject( IN AFSObjectInfoCB *ObjectInfo,
2664                           IN ULONG InvalidateReason)
2665 {
2666
2667     NTSTATUS ntStatus = STATUS_SUCCESS;
2668     AFSWorkItem *pWorkItem = NULL;
2669
2670     __try
2671     {
2672
2673         pWorkItem = (AFSWorkItem *) AFSLibExAllocatePoolWithTag( NonPagedPool,
2674                                                                  sizeof(AFSWorkItem),
2675                                                                  AFS_WORK_ITEM_TAG);
2676         if (NULL == pWorkItem)
2677         {
2678
2679             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2680                           AFS_TRACE_LEVEL_ERROR,
2681                           "AFSQueueInvalidateObject Failed to allocate work item\n");
2682
2683             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2684         }
2685
2686         RtlZeroMemory( pWorkItem,
2687                        sizeof(AFSWorkItem));
2688
2689         pWorkItem->Size = sizeof( AFSWorkItem);
2690
2691         pWorkItem->RequestType = AFS_WORK_INVALIDATE_OBJECT;
2692
2693         pWorkItem->Specific.Invalidate.ObjectInfo = ObjectInfo;
2694
2695         pWorkItem->Specific.Invalidate.InvalidateReason = InvalidateReason;
2696
2697         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2698                       AFS_TRACE_LEVEL_VERBOSE,
2699                       "AFSQueueInvalidateObject Workitem %p\n",
2700                       pWorkItem);
2701
2702         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2703
2704 try_exit:
2705
2706         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2707                       AFS_TRACE_LEVEL_VERBOSE,
2708                       "AFSQueueInvalidateObject Request complete Status %08lX\n",
2709                       ntStatus);
2710
2711         if( !NT_SUCCESS( ntStatus))
2712         {
2713
2714             if( pWorkItem != NULL)
2715             {
2716                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2717             }
2718
2719             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2720                           AFS_TRACE_LEVEL_ERROR,
2721                           "AFSQueueInvalidateObject Failed to queue request Status %08lX\n",
2722                           ntStatus);
2723         }
2724     }
2725     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2726     {
2727
2728         AFSDbgLogMsg( 0,
2729                       0,
2730                       "EXCEPTION - AFSQueueInvalidateObject\n");
2731
2732         AFSDumpTraceFilesFnc();
2733     }
2734
2735     return ntStatus;
2736 }