Windows: Trace DirectoryCB allocations
[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 void
953 AFSPrimaryVolumeWorkerThread( IN PVOID Context)
954 {
955
956     UNREFERENCED_PARAMETER(Context);
957     NTSTATUS ntStatus = STATUS_SUCCESS;
958     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)&AFSGlobalRoot->NonPagedVcb->VolumeWorkerContext;
959     AFSDeviceExt *pControlDeviceExt = NULL;
960     AFSDeviceExt *pRDRDeviceExt = NULL;
961     LARGE_INTEGER DueTime;
962     LONG TimeOut;
963     KTIMER Timer;
964     AFSObjectInfoCB *pCurrentObject = NULL, *pNextObject = NULL, *pCurrentChildObject = NULL;
965     AFSDirectoryCB *pCurrentDirEntry = NULL, *pNextDirEntry = NULL;
966     BOOLEAN bReleaseVolumeLock = FALSE;
967     AFSVolumeCB *pVolumeCB = NULL, *pNextVolume = NULL;
968     AFSFcb *pFcb = NULL;
969     LARGE_INTEGER liCurrentTime;
970     BOOLEAN bVolumeObject = FALSE;
971     BOOLEAN bFcbBusy = FALSE;
972     LONG lCount;
973
974     pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
975
976     pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
977
978     AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
979                   AFS_TRACE_LEVEL_VERBOSE,
980                   "AFSPrimaryVolumeWorkerThread Initialized\n");
981
982     //
983     // Initialize the timer for the worker thread
984     //
985
986     DueTime.QuadPart = -(5000);
987
988     TimeOut = 5000;
989
990     KeInitializeTimerEx( &Timer,
991                          SynchronizationTimer);
992
993     KeSetTimerEx( &Timer,
994                   DueTime,
995                   TimeOut,
996                   NULL);
997
998     //
999     // Indicate that we are initialized and ready
1000     //
1001
1002     KeSetEvent( &pPoolContext->WorkerThreadReady,
1003                 0,
1004                 FALSE);
1005
1006     //
1007     // Indicate we are initialized
1008     //
1009
1010     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
1011
1012     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
1013     {
1014
1015         if ( bFcbBusy == FALSE)
1016         {
1017
1018             KeWaitForSingleObject( &Timer,
1019                                    Executive,
1020                                    KernelMode,
1021                                    FALSE,
1022                                    NULL);
1023         }
1024         else
1025         {
1026
1027             bFcbBusy = FALSE;
1028         }
1029
1030         //
1031         // This is the primary volume worker so it will traverse the volume list
1032         // looking for cleanup or volumes requiring private workers
1033         //
1034
1035         AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1036                           TRUE);
1037
1038         pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead;
1039
1040         while( pVolumeCB != NULL)
1041         {
1042
1043             if( pVolumeCB == AFSGlobalRoot ||
1044                 !AFSAcquireExcl( pVolumeCB->VolumeLock,
1045                                  FALSE))
1046             {
1047
1048                 pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1049
1050                 continue;
1051             }
1052
1053             if( pVolumeCB->ObjectInfoListHead == NULL)
1054             {
1055
1056                 AFSReleaseResource( pVolumeCB->VolumeLock);
1057
1058                 AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1059
1060                 AFSAcquireExcl( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock,
1061                                 TRUE);
1062
1063                 AFSAcquireExcl( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1064                                 TRUE);
1065
1066                 if( !AFSAcquireExcl( pVolumeCB->VolumeLock,
1067                                      FALSE))
1068                 {
1069
1070                     AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1071
1072                     AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
1073
1074                     pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1075
1076                     continue;
1077                 }
1078
1079                 KeQueryTickCount( &liCurrentTime);
1080
1081                 pNextVolume = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1082
1083                 AFSAcquireShared( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock,
1084                                   TRUE);
1085
1086                 if( pVolumeCB->ObjectInfoListHead == NULL &&
1087                     pVolumeCB->DirectoryCB->DirOpenReferenceCount <= 0 &&
1088                     pVolumeCB->DirectoryCB->NameArrayReferenceCount <= 0 &&
1089                     pVolumeCB->VolumeReferenceCount == 1 &&
1090                     ( pVolumeCB->RootFcb == NULL ||
1091                       pVolumeCB->RootFcb->OpenReferenceCount == 0) &&
1092                     pVolumeCB->ObjectInformation.ObjectReferenceCount <= 0)
1093                 {
1094
1095                     if( pVolumeCB->RootFcb != NULL)
1096                     {
1097
1098                         AFSRemoveRootFcb( pVolumeCB->RootFcb);
1099                     }
1100
1101                     AFSReleaseResource( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
1102
1103                     AFSRemoveVolume( pVolumeCB);
1104                 }
1105                 else
1106                 {
1107
1108                     AFSReleaseResource( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
1109
1110                     AFSReleaseResource( pVolumeCB->VolumeLock);
1111                 }
1112
1113                 AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1114
1115                 AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
1116
1117                 pVolumeCB = pNextVolume;
1118
1119                 continue;
1120             }
1121
1122             //
1123             // Don't need this lock anymore now that we have a volume cb to work with
1124             //
1125
1126             AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1127
1128             //
1129             // For now we only need the volume lock shared
1130             //
1131
1132             AFSConvertToShared( pVolumeCB->VolumeLock);
1133
1134             if( AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1135                                   FALSE))
1136             {
1137
1138                 pCurrentObject = pVolumeCB->ObjectInfoListHead;
1139
1140                 pNextObject = NULL;
1141
1142                 bReleaseVolumeLock = TRUE;
1143
1144                 while( pCurrentObject != NULL)
1145                 {
1146
1147                     if( pCurrentObject != &pVolumeCB->ObjectInformation)
1148                     {
1149
1150                         pNextObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1151
1152                         if( pNextObject == NULL &&
1153                             pVolumeCB != AFSGlobalRoot)  // Don't free up the root of the global
1154                         {
1155
1156                             pNextObject = &pVolumeCB->ObjectInformation;
1157                         }
1158
1159                         bVolumeObject = FALSE;
1160                     }
1161                     else
1162                     {
1163
1164                         pNextObject = NULL;
1165
1166                         bVolumeObject = TRUE;
1167                     }
1168
1169                     if( pCurrentObject->FileType == AFS_FILE_TYPE_DIRECTORY &&
1170                         !BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))  // If we are in shutdown mode skip directories
1171                     {
1172
1173                         //
1174                         // If this object is deleted then remove it from the parent, if we can
1175                         //
1176
1177                         if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DELETED) &&
1178                             pCurrentObject->ObjectReferenceCount <= 0 &&
1179                             ( pCurrentObject->Fcb == NULL ||
1180                               pCurrentObject->Fcb->OpenReferenceCount == 0) &&
1181                             pCurrentObject->Specific.Directory.DirectoryNodeListHead == NULL &&
1182                             pCurrentObject->Specific.Directory.ChildOpenReferenceCount == 0)
1183                         {
1184
1185                             AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1186
1187                             //
1188                             // Dropping the TreeLock permits the
1189                             // pCurrentObject->ObjectReferenceCount to change
1190                             //
1191
1192                             if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1193                                                 FALSE))
1194                             {
1195
1196                                 AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
1197                                                 TRUE);
1198
1199                                 if ( pCurrentObject->ObjectReferenceCount <= 0)
1200                                 {
1201
1202                                     AFSRemoveFcb( &pCurrentObject->Fcb);
1203
1204                                     if( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
1205                                     {
1206
1207                                         AFSAcquireExcl( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock,
1208                                                         TRUE);
1209
1210                                         AFSRemoveFcb( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
1211
1212                                         AFSReleaseResource( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
1213
1214                                         AFSDeleteObjectInfo( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
1215
1216                                         ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
1217
1218                                         AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
1219
1220                                         AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
1221                                                       AFS_TRACE_LEVEL_VERBOSE,
1222                                                       "AFSPrimaryVolumeWorkerThread (pioctl) AFS_DIR_ENTRY_TAG deallocating %p\n",
1223                                                       pCurrentObject->Specific.Directory.PIOCtlDirectoryCB);
1224
1225                                         AFSExFreePoolWithTag( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
1226                                     }
1227
1228                                     AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1229
1230                                     AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1231                                                   AFS_TRACE_LEVEL_VERBOSE,
1232                                                   "AFSPrimaryVolumeWorkerThread Deleting deleted object %p\n",
1233                                                   pCurrentObject);
1234
1235                                     AFSDeleteObjectInfo( pCurrentObject);
1236                                 }
1237                                 else
1238                                 {
1239
1240                                     AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1241                                 }
1242
1243                                 AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1244
1245                                 pCurrentObject = pNextObject;
1246
1247                                 continue;
1248                             }
1249                             else
1250                             {
1251
1252                                 bReleaseVolumeLock = FALSE;
1253
1254                                 break;
1255                             }
1256                         }
1257
1258                         if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0 ||
1259                             ( pCurrentObject->Fcb != NULL &&
1260                               pCurrentObject->Fcb->OpenReferenceCount > 0) ||
1261                             pCurrentObject->Specific.Directory.DirectoryNodeListHead == NULL)
1262                         {
1263
1264                             pCurrentObject = pNextObject;
1265
1266                             continue;
1267                         }
1268
1269                         if( !AFSAcquireShared( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
1270                                                FALSE))
1271                         {
1272
1273                             pCurrentObject = pNextObject;
1274
1275                             continue;
1276                         }
1277
1278                         KeQueryTickCount( &liCurrentTime);
1279
1280                         pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
1281
1282                         while( pCurrentDirEntry != NULL)
1283                         {
1284
1285                             if( pCurrentDirEntry->DirOpenReferenceCount > 0 ||
1286                                 pCurrentDirEntry->NameArrayReferenceCount > 0 ||
1287                                 ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1288                                   pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0) ||
1289                                 liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart ||
1290                                 liCurrentTime.QuadPart - pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart <
1291                                                                         pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart ||
1292                                 ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY &&
1293                                    ( pCurrentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL ||
1294                                      pCurrentDirEntry->ObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)) ||
1295                                 ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE &&
1296                                   pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1297                                   pCurrentDirEntry->ObjectInformation->Fcb->Specific.File.ExtentsDirtyCount > 0))
1298                             {
1299
1300                                 break;
1301                             }
1302
1303                             pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
1304                         }
1305
1306                         if( pCurrentDirEntry != NULL)
1307                         {
1308
1309                             AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1310
1311                             pCurrentObject = pNextObject;
1312
1313                             continue;
1314                         }
1315
1316                         AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1317
1318                         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1319
1320                         //
1321                         // Now acquire the locks excl
1322                         //
1323
1324                         if( AFSAcquireExcl( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
1325                                             FALSE))
1326                         {
1327
1328                             if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1329                                                 FALSE))
1330                             {
1331
1332                                 if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0)
1333                                 {
1334
1335                                     AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1336
1337                                     AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1338
1339                                     pCurrentObject = pNextObject;
1340
1341                                     continue;
1342                                 }
1343
1344                                 KeQueryTickCount( &liCurrentTime);
1345
1346                                 pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
1347
1348                                 while( pCurrentDirEntry != NULL)
1349                                 {
1350
1351                                     if( pCurrentDirEntry->DirOpenReferenceCount > 0 ||
1352                                         pCurrentDirEntry->NameArrayReferenceCount > 0 ||
1353                                         ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1354                                           pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0) ||
1355                                         liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart ||
1356                                         liCurrentTime.QuadPart - pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart <
1357                                                                                 pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart ||
1358                                         ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY &&
1359                                           ( pCurrentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL ||
1360                                             pCurrentDirEntry->ObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)) ||
1361                                         ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE &&
1362                                           pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1363                                           pCurrentDirEntry->ObjectInformation->Fcb->Specific.File.ExtentsDirtyCount > 0))
1364                                     {
1365
1366                                         break;
1367                                     }
1368
1369                                     pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
1370                                 }
1371
1372                                 if( pCurrentDirEntry != NULL)
1373                                 {
1374
1375                                     AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1376
1377                                     AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1378
1379                                     pCurrentObject = pNextObject;
1380
1381                                     continue;
1382                                 }
1383
1384                                 pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
1385
1386                                 while( pCurrentDirEntry != NULL)
1387                                 {
1388
1389                                     pNextDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
1390
1391                                     pCurrentChildObject = pCurrentDirEntry->ObjectInformation;
1392
1393                                     pFcb = NULL;
1394
1395                                     AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING | AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1396                                                   AFS_TRACE_LEVEL_VERBOSE,
1397                                                   "AFSPrimaryVolumeWorkerThread Deleting DE %wZ Object %p\n",
1398                                                   &pCurrentDirEntry->NameInformation.FileName,
1399                                                   pCurrentChildObject);
1400
1401                                     AFSDeleteDirEntry( pCurrentObject,
1402                                                        pCurrentDirEntry);
1403
1404
1405                                     //
1406                                     // Acquire ObjectInfoLock shared here so as not to deadlock
1407                                     // with an invalidation call from the service during AFSCleanupFcb
1408                                     //
1409
1410                                     lCount = AFSObjectInfoIncrement( pCurrentChildObject,
1411                                                                      AFS_OBJECT_REFERENCE_WORKER);
1412
1413                                     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1414                                                   AFS_TRACE_LEVEL_VERBOSE,
1415                                                   "AFSPrimaryVolumeWorkerThread Increment count on object %p Cnt %d\n",
1416                                                   pCurrentChildObject,
1417                                                   lCount);
1418
1419                                     if( lCount == 1 &&
1420                                         pCurrentChildObject->Fcb != NULL &&
1421                                         pCurrentChildObject->FileType == AFS_FILE_TYPE_FILE)
1422                                     {
1423
1424                                         //
1425                                         // We must not hold pVolumeCB->ObjectInfoTree.TreeLock exclusive
1426                                         // across an AFSCleanupFcb call since it can deadlock with an
1427                                         // invalidation call from the service.
1428                                         //
1429
1430                                         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1431
1432                                         //
1433                                         // Cannot hold a TreeLock across an AFSCleanupFcb call
1434                                         // as it can deadlock with an invalidation ioctl initiated
1435                                         // from the service.
1436                                         //
1437                                         // Dropping the TreeLock permits the
1438                                         // pCurrentObject->ObjectReferenceCount to change
1439                                         //
1440
1441                                         ntStatus = AFSCleanupFcb( pCurrentChildObject->Fcb,
1442                                                                   TRUE);
1443
1444                                         if ( ntStatus == STATUS_RETRY)
1445                                         {
1446
1447                                             bFcbBusy = TRUE;
1448                                         }
1449
1450                                         AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1451                                                         TRUE);
1452                                     }
1453
1454                                     lCount = AFSObjectInfoDecrement( pCurrentChildObject,
1455                                                                      AFS_OBJECT_REFERENCE_WORKER);
1456
1457                                     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1458                                                   AFS_TRACE_LEVEL_VERBOSE,
1459                                                   "AFSPrimaryVolumeWorkerThread Decrement1 count on object %p Cnt %d\n",
1460                                                   pCurrentChildObject,
1461                                                   lCount);
1462
1463                                     AFSAcquireExcl( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock,
1464                                                     TRUE);
1465
1466                                     if( pCurrentChildObject->ObjectReferenceCount <= 0)
1467                                     {
1468
1469                                         AFSRemoveFcb( &pCurrentChildObject->Fcb);
1470
1471                                         if( pCurrentChildObject->FileType == AFS_FILE_TYPE_DIRECTORY &&
1472                                             pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
1473                                         {
1474
1475                                             AFSAcquireExcl( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock,
1476                                                             TRUE);
1477
1478                                             AFSRemoveFcb( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
1479
1480                                             AFSReleaseResource( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
1481
1482                                             AFSDeleteObjectInfo( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
1483
1484                                             ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
1485
1486                                             AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
1487
1488                                             AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
1489                                                           AFS_TRACE_LEVEL_VERBOSE,
1490                                                           "AFSPrimaryVolumeWorkerThread (pioctl) AFS_DIR_ENTRY_TAG deallocating %p\n",
1491                                                           pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB);
1492
1493                                             AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
1494                                         }
1495
1496                                         AFSReleaseResource( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock);
1497
1498                                         AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1499                                                       AFS_TRACE_LEVEL_VERBOSE,
1500                                                       "AFSPrimaryVolumeWorkerThread Deleting object %p\n",
1501                                                       pCurrentChildObject);
1502
1503                                         AFSDeleteObjectInfo( pCurrentChildObject);
1504                                     }
1505                                     else
1506                                     {
1507
1508                                         AFSReleaseResource( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock);
1509                                     }
1510
1511                                     pCurrentDirEntry = pNextDirEntry;
1512
1513                                 }
1514
1515                                 pCurrentObject->Specific.Directory.DirectoryNodeListHead = NULL;
1516
1517                                 pCurrentObject->Specific.Directory.DirectoryNodeListTail = NULL;
1518
1519                                 pCurrentObject->Specific.Directory.ShortNameTree = NULL;
1520
1521                                 pCurrentObject->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead = NULL;
1522
1523                                 pCurrentObject->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead = NULL;
1524
1525                                 pCurrentObject->Specific.Directory.DirectoryNodeCount = 0;
1526
1527                                 AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NODE_COUNT,
1528                                               AFS_TRACE_LEVEL_VERBOSE,
1529                                               "AFSPrimaryVolumeWorkerThread Reset count to 0 on parent FID %08lX-%08lX-%08lX-%08lX\n",
1530                                               pCurrentObject->FileId.Cell,
1531                                               pCurrentObject->FileId.Volume,
1532                                               pCurrentObject->FileId.Vnode,
1533                                               pCurrentObject->FileId.Unique);
1534
1535                                 //
1536                                 // Clear our enumerated flag on this object so we retrieve info again on next access
1537                                 //
1538
1539                                 ClearFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED);
1540
1541                                 AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1542
1543                                 AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1544                             }
1545                             else
1546                             {
1547
1548                                 AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1549
1550                                 bReleaseVolumeLock = FALSE;
1551
1552                                 break;
1553                             }
1554                         }
1555                         else
1556                         {
1557
1558                             //
1559                             // Try to grab the volume lock again ... no problem if we don't
1560                             //
1561
1562                             if( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1563                                                  FALSE))
1564                             {
1565
1566                                 bReleaseVolumeLock = FALSE;
1567
1568                                 break;
1569                             }
1570                         }
1571
1572                         if( pCurrentObject != &pVolumeCB->ObjectInformation)
1573                         {
1574
1575                             pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1576
1577                             if( pCurrentObject == NULL &&
1578                                 pVolumeCB != AFSGlobalRoot)
1579                             {
1580
1581                                 pCurrentObject = &pVolumeCB->ObjectInformation;
1582                             }
1583                         }
1584                         else
1585                         {
1586
1587                             pCurrentObject = NULL;
1588                         }
1589
1590                         continue;
1591                     }
1592                     else if( pCurrentObject->FileType == AFS_FILE_TYPE_FILE)
1593                     {
1594
1595                         lCount = AFSObjectInfoIncrement( pCurrentObject,
1596                                                          AFS_OBJECT_REFERENCE_WORKER);
1597
1598                         AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1599                                       AFS_TRACE_LEVEL_VERBOSE,
1600                                       "AFSPrimaryVolumeWorkerThread Increment2 count on object %p Cnt %d\n",
1601                                       pCurrentObject,
1602                                       lCount);
1603
1604                         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1605
1606                         if( pCurrentObject->Fcb != NULL)
1607                         {
1608
1609                             //
1610                             // Dropping the TreeLock permits the
1611                             // pCurrentObject->ObjectReferenceCount to change
1612                             //
1613
1614                             ntStatus = AFSCleanupFcb( pCurrentObject->Fcb,
1615                                                       FALSE);
1616
1617                             if ( ntStatus == STATUS_RETRY)
1618                             {
1619
1620                                 bFcbBusy = TRUE;
1621                             }
1622                         }
1623
1624                         lCount = AFSObjectInfoDecrement( pCurrentObject,
1625                                                          AFS_OBJECT_REFERENCE_WORKER);
1626
1627                         AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1628                                       AFS_TRACE_LEVEL_VERBOSE,
1629                                       "AFSPrimaryVolumeWorkerThread Decrement2 count on object %p Cnt %d\n",
1630                                       pCurrentObject,
1631                                       lCount);
1632
1633                         if( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1634                                              FALSE))
1635                         {
1636
1637                             bReleaseVolumeLock = FALSE;
1638
1639                             break;
1640                         }
1641
1642                         AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
1643                                         TRUE);
1644
1645                         if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DELETED) &&
1646                             pCurrentObject->ObjectReferenceCount <= 0)
1647                         {
1648
1649                             AFSRemoveFcb( &pCurrentObject->Fcb);
1650
1651                             AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1652
1653                             AFSDeleteObjectInfo( pCurrentObject);
1654                         }
1655                         else
1656                         {
1657
1658                             AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1659                         }
1660
1661                         AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1662
1663                         pCurrentObject = pNextObject;
1664
1665                         continue;
1666                     }
1667
1668                     pCurrentObject = pNextObject;
1669                 }
1670
1671                 if( bReleaseVolumeLock)
1672                 {
1673
1674                     AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1675                 }
1676             }
1677
1678             //
1679             // Next volume cb
1680             //
1681
1682             AFSReleaseResource( pVolumeCB->VolumeLock);
1683
1684             AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1685                               TRUE);
1686
1687             pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1688         }
1689
1690         AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1691
1692     } // worker thread loop
1693
1694     KeCancelTimer( &Timer);
1695
1696     ClearFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
1697
1698     AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1699                   AFS_TRACE_LEVEL_VERBOSE,
1700                   "AFSPrimaryVolumeWorkerThread Exiting\n");
1701
1702     lCount = InterlockedDecrement( &pControlDeviceExt->Specific.Control.VolumeWorkerThreadCount);
1703
1704     if( lCount == 0)
1705     {
1706
1707         KeSetEvent( &pControlDeviceExt->Specific.Control.VolumeWorkerCloseEvent,
1708                     0,
1709                     FALSE);
1710     }
1711
1712     PsTerminateSystemThread( 0);
1713
1714     return;
1715 }
1716
1717 NTSTATUS
1718 AFSInsertWorkitem( IN AFSWorkItem *WorkItem)
1719 {
1720
1721     NTSTATUS ntStatus = STATUS_SUCCESS;
1722     AFSDeviceExt *pDevExt = NULL;
1723     LONG lCount;
1724
1725     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1726
1727     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1728                   AFS_TRACE_LEVEL_VERBOSE,
1729                   "AFSInsertWorkitem Acquiring Control QueueLock lock %p EXCL %08lX\n",
1730                   &pDevExt->Specific.Library.QueueLock,
1731                   PsGetCurrentThread());
1732
1733     AFSAcquireExcl( &pDevExt->Specific.Library.QueueLock,
1734                     TRUE);
1735
1736     lCount = InterlockedIncrement( &pDevExt->Specific.Library.QueueItemCount);
1737
1738     AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
1739                   AFS_TRACE_LEVEL_VERBOSE,
1740                   "AFSInsertWorkitem Inserting work item %p Count %d\n",
1741                   WorkItem,
1742                   lCount);
1743
1744     if( pDevExt->Specific.Library.QueueTail != NULL) // queue already has nodes
1745     {
1746
1747         pDevExt->Specific.Library.QueueTail->next = WorkItem;
1748     }
1749     else // first node
1750     {
1751
1752         pDevExt->Specific.Library.QueueHead = WorkItem;
1753     }
1754
1755     WorkItem->next = NULL;
1756     pDevExt->Specific.Library.QueueTail = WorkItem;
1757
1758     // indicate that the queue has nodes
1759     KeSetEvent( &(pDevExt->Specific.Library.WorkerQueueHasItems),
1760                 0,
1761                 FALSE);
1762
1763     AFSReleaseResource( &pDevExt->Specific.Library.QueueLock);
1764
1765     return ntStatus;
1766 }
1767
1768 NTSTATUS
1769 AFSInsertIOWorkitem( IN AFSWorkItem *WorkItem)
1770 {
1771
1772     NTSTATUS ntStatus = STATUS_SUCCESS;
1773     AFSDeviceExt *pDevExt = NULL;
1774     LONG lCount;
1775
1776     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1777
1778     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1779                   AFS_TRACE_LEVEL_VERBOSE,
1780                   "AFSInsertIOWorkitem Acquiring Control QueueLock lock %p EXCL %08lX\n",
1781                   &pDevExt->Specific.Library.IOQueueLock,
1782                   PsGetCurrentThread());
1783
1784     AFSAcquireExcl( &pDevExt->Specific.Library.IOQueueLock,
1785                     TRUE);
1786
1787     lCount = InterlockedIncrement( &pDevExt->Specific.Library.IOQueueItemCount);
1788
1789     AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
1790                   AFS_TRACE_LEVEL_VERBOSE,
1791                   "AFSInsertWorkitem Inserting IO work item %p Count %d\n",
1792                   WorkItem,
1793                   lCount);
1794
1795     if( pDevExt->Specific.Library.IOQueueTail != NULL) // queue already has nodes
1796     {
1797
1798         pDevExt->Specific.Library.IOQueueTail->next = WorkItem;
1799     }
1800     else // first node
1801     {
1802
1803         pDevExt->Specific.Library.IOQueueHead = WorkItem;
1804     }
1805
1806     WorkItem->next = NULL;
1807     pDevExt->Specific.Library.IOQueueTail = WorkItem;
1808
1809     // indicate that the queue has nodes
1810     KeSetEvent( &(pDevExt->Specific.Library.IOWorkerQueueHasItems),
1811                 0,
1812                 FALSE);
1813
1814     AFSReleaseResource( &pDevExt->Specific.Library.IOQueueLock);
1815
1816     return ntStatus;
1817 }
1818
1819 NTSTATUS
1820 AFSInsertWorkitemAtHead( IN AFSWorkItem *WorkItem)
1821 {
1822
1823     NTSTATUS ntStatus = STATUS_SUCCESS;
1824     AFSDeviceExt *pDevExt = NULL;
1825     LONG lCount;
1826
1827     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1828
1829     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1830                   AFS_TRACE_LEVEL_VERBOSE,
1831                   "AFSInsertWorkitemAtHead Acquiring Control QueueLock lock %p EXCL %08lX\n",
1832                   &pDevExt->Specific.Library.QueueLock,
1833                   PsGetCurrentThread());
1834
1835     AFSAcquireExcl( &pDevExt->Specific.Library.QueueLock,
1836                     TRUE);
1837
1838     WorkItem->next = pDevExt->Specific.Library.QueueHead;
1839
1840     pDevExt->Specific.Library.QueueHead = WorkItem;
1841
1842     lCount = InterlockedIncrement( &pDevExt->Specific.Library.QueueItemCount);
1843
1844     AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
1845                   AFS_TRACE_LEVEL_VERBOSE,
1846                   "AFSInsertWorkitemAtHead Inserting work item %p Count %d\n",
1847                   WorkItem,
1848                   lCount);
1849
1850     //
1851     // indicate that the queue has nodes
1852     //
1853
1854     KeSetEvent( &(pDevExt->Specific.Library.WorkerQueueHasItems),
1855                 0,
1856                 FALSE);
1857
1858     AFSReleaseResource( &pDevExt->Specific.Library.QueueLock);
1859
1860     return ntStatus;
1861 }
1862
1863 AFSWorkItem *
1864 AFSRemoveWorkItem()
1865 {
1866
1867     AFSWorkItem        *pWorkItem = NULL;
1868     AFSDeviceExt *pDevExt = NULL;
1869     LONG lCount;
1870
1871     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1872
1873     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1874                   AFS_TRACE_LEVEL_VERBOSE,
1875                   "AFSRemoveWorkItem Acquiring Control QueueLock lock %p EXCL %08lX\n",
1876                   &pDevExt->Specific.Library.QueueLock,
1877                   PsGetCurrentThread());
1878
1879     AFSAcquireExcl( &pDevExt->Specific.Library.QueueLock,
1880                     TRUE);
1881
1882     if( pDevExt->Specific.Library.QueueHead != NULL) // queue has nodes
1883     {
1884
1885         pWorkItem = pDevExt->Specific.Library.QueueHead;
1886
1887         lCount = InterlockedDecrement( &pDevExt->Specific.Library.QueueItemCount);
1888
1889         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
1890                       AFS_TRACE_LEVEL_VERBOSE,
1891                       "AFSRemoveWorkItem Removing work item %p Count %d Thread %08lX\n",
1892                       pWorkItem,
1893                       lCount,
1894                       PsGetCurrentThreadId());
1895
1896         pDevExt->Specific.Library.QueueHead = pDevExt->Specific.Library.QueueHead->next;
1897
1898         if( pDevExt->Specific.Library.QueueHead == NULL) // if queue just became empty
1899         {
1900
1901             pDevExt->Specific.Library.QueueTail = NULL;
1902         }
1903         else
1904         {
1905
1906             //
1907             // Wake up another worker
1908             //
1909
1910             KeSetEvent( &(pDevExt->Specific.Library.WorkerQueueHasItems),
1911                         0,
1912                         FALSE);
1913         }
1914     }
1915
1916     AFSReleaseResource( &pDevExt->Specific.Library.QueueLock);
1917
1918     return pWorkItem;
1919 }
1920
1921 AFSWorkItem *
1922 AFSRemoveIOWorkItem()
1923 {
1924
1925     AFSWorkItem        *pWorkItem = NULL;
1926     AFSDeviceExt *pDevExt = NULL;
1927     LONG lCount;
1928
1929     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1930
1931     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1932                   AFS_TRACE_LEVEL_VERBOSE,
1933                   "AFSRemoveIOWorkItem Acquiring Control QueueLock lock %p EXCL %08lX\n",
1934                   &pDevExt->Specific.Library.IOQueueLock,
1935                   PsGetCurrentThread());
1936
1937     AFSAcquireExcl( &pDevExt->Specific.Library.IOQueueLock,
1938                     TRUE);
1939
1940     if( pDevExt->Specific.Library.IOQueueHead != NULL) // queue has nodes
1941     {
1942
1943         pWorkItem = pDevExt->Specific.Library.IOQueueHead;
1944
1945         lCount = InterlockedDecrement( &pDevExt->Specific.Library.IOQueueItemCount);
1946
1947         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
1948                       AFS_TRACE_LEVEL_VERBOSE,
1949                       "AFSRemoveWorkItem Removing work item %p Count %d Thread %08lX\n",
1950                       pWorkItem,
1951                       lCount,
1952                       PsGetCurrentThreadId());
1953
1954         pDevExt->Specific.Library.IOQueueHead = pDevExt->Specific.Library.IOQueueHead->next;
1955
1956         if( pDevExt->Specific.Library.IOQueueHead == NULL) // if queue just became empty
1957         {
1958
1959             pDevExt->Specific.Library.IOQueueTail = NULL;
1960         }
1961         else
1962         {
1963
1964             //
1965             // Wake up another worker
1966             //
1967
1968             KeSetEvent( &(pDevExt->Specific.Library.IOWorkerQueueHasItems),
1969                         0,
1970                         FALSE);
1971         }
1972     }
1973
1974     AFSReleaseResource( &pDevExt->Specific.Library.IOQueueLock);
1975
1976     return pWorkItem;
1977 }
1978
1979 NTSTATUS
1980 AFSQueueWorkerRequest( IN AFSWorkItem *WorkItem)
1981 {
1982
1983     NTSTATUS ntStatus = STATUS_SUCCESS;
1984     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
1985
1986     //
1987     // Submit the work item to the worker
1988     //
1989
1990     ntStatus = AFSInsertWorkitem( WorkItem);
1991
1992     if( bWait)
1993     {
1994
1995         //
1996         // Sync request so block on the work item event
1997         //
1998
1999         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2000                                           Executive,
2001                                           KernelMode,
2002                                           FALSE,
2003                                           NULL);
2004     }
2005
2006     return ntStatus;
2007 }
2008
2009 NTSTATUS
2010 AFSQueueIOWorkerRequest( IN AFSWorkItem *WorkItem)
2011 {
2012
2013     NTSTATUS ntStatus = STATUS_SUCCESS;
2014     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
2015
2016     //
2017     // Submit the work item to the worker
2018     //
2019
2020     ntStatus = AFSInsertIOWorkitem( WorkItem);
2021
2022     if( bWait)
2023     {
2024
2025         //
2026         // Sync request so block on the work item event
2027         //
2028
2029         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2030                                           Executive,
2031                                           KernelMode,
2032                                           FALSE,
2033                                           NULL);
2034     }
2035
2036     return ntStatus;
2037 }
2038
2039 NTSTATUS
2040 AFSQueueWorkerRequestAtHead( IN AFSWorkItem *WorkItem)
2041 {
2042
2043     NTSTATUS ntStatus = STATUS_SUCCESS;
2044     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
2045
2046     //
2047     // Submit the work item to the worker
2048     //
2049
2050     ntStatus = AFSInsertWorkitemAtHead( WorkItem);
2051
2052     if( bWait)
2053     {
2054
2055         //
2056         // Sync request so block on the work item event
2057         //
2058
2059         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2060                                           Executive,
2061                                           KernelMode,
2062                                           FALSE,
2063                                           NULL);
2064     }
2065
2066     return ntStatus;
2067 }
2068
2069 NTSTATUS
2070 AFSQueueFlushExtents( IN AFSFcb *Fcb,
2071                       IN GUID *AuthGroup)
2072 {
2073
2074     NTSTATUS ntStatus = STATUS_SUCCESS;
2075     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
2076     AFSWorkItem *pWorkItem = NULL;
2077     LONG lCount;
2078
2079     __try
2080     {
2081
2082         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2083                       AFS_TRACE_LEVEL_VERBOSE,
2084                       "AFSQueueFlushExtents Queuing request for FID %08lX-%08lX-%08lX-%08lX\n",
2085                       Fcb->ObjectInformation->FileId.Cell,
2086                       Fcb->ObjectInformation->FileId.Volume,
2087                       Fcb->ObjectInformation->FileId.Vnode,
2088                       Fcb->ObjectInformation->FileId.Unique);
2089
2090         //
2091         // Increment our flush count here just to keep the number of items in the
2092         // queue down. We'll decrement it just below.
2093         //
2094
2095         lCount = InterlockedIncrement( &Fcb->Specific.File.QueuedFlushCount);
2096
2097         if( lCount > 3)
2098         {
2099
2100             AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2101                           AFS_TRACE_LEVEL_VERBOSE,
2102                           "AFSQueueFlushExtents Max queued items for FID %08lX-%08lX-%08lX-%08lX\n",
2103                           Fcb->ObjectInformation->FileId.Cell,
2104                           Fcb->ObjectInformation->FileId.Volume,
2105                           Fcb->ObjectInformation->FileId.Vnode,
2106                           Fcb->ObjectInformation->FileId.Unique);
2107
2108             try_return( ntStatus);
2109         }
2110
2111         if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
2112         {
2113
2114             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2115                           AFS_TRACE_LEVEL_ERROR,
2116                           "AFSQueueFlushExtents Failing request, in shutdown\n");
2117
2118             try_return( ntStatus = STATUS_TOO_LATE);
2119         }
2120
2121         //
2122         // Allocate our request structure and send it to the worker
2123         //
2124
2125         pWorkItem = (AFSWorkItem *)AFSLibExAllocatePoolWithTag( NonPagedPool,
2126                                                                 sizeof( AFSWorkItem),
2127                                                                 AFS_WORK_ITEM_TAG);
2128
2129         if( pWorkItem == NULL)
2130         {
2131
2132             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2133                           AFS_TRACE_LEVEL_ERROR,
2134                           "AFSQueueFlushExtents Failed to allocate work item\n");
2135
2136             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2137         }
2138
2139         RtlZeroMemory( pWorkItem,
2140                        sizeof( AFSWorkItem));
2141
2142         pWorkItem->Size = sizeof( AFSWorkItem);
2143
2144         pWorkItem->ProcessID = (ULONGLONG)PsGetCurrentProcessId();
2145
2146         pWorkItem->RequestType = AFS_WORK_FLUSH_FCB;
2147
2148         if ( AuthGroup == NULL)
2149         {
2150
2151             RtlZeroMemory( &pWorkItem->AuthGroup,
2152                            sizeof( GUID));
2153
2154             ntStatus = AFSRetrieveValidAuthGroup( Fcb,
2155                                                   NULL,
2156                                                   TRUE,
2157                                                   &pWorkItem->AuthGroup);
2158         }
2159         else
2160         {
2161             RtlCopyMemory( &pWorkItem->AuthGroup,
2162                            AuthGroup,
2163                            sizeof( GUID));
2164         }
2165
2166         pWorkItem->Specific.Fcb.Fcb = Fcb;
2167
2168         lCount = InterlockedIncrement( &Fcb->OpenReferenceCount);
2169
2170         AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
2171                       AFS_TRACE_LEVEL_VERBOSE,
2172                       "AFSQueueFlushExtents Increment count on Fcb %p Cnt %d\n",
2173                       Fcb,
2174                       lCount);
2175
2176         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2177                       AFS_TRACE_LEVEL_VERBOSE,
2178                       "AFSQueueFlushExtents Workitem %p for FID %08lX-%08lX-%08lX-%08lX\n",
2179                       pWorkItem,
2180                       Fcb->ObjectInformation->FileId.Cell,
2181                       Fcb->ObjectInformation->FileId.Volume,
2182                       Fcb->ObjectInformation->FileId.Vnode,
2183                       Fcb->ObjectInformation->FileId.Unique);
2184
2185         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2186
2187 try_exit:
2188
2189         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2190                       AFS_TRACE_LEVEL_VERBOSE,
2191                       "AFSQueueFlushExtents Request complete Status %08lX FID %08lX-%08lX-%08lX-%08lX\n",
2192                       Fcb->ObjectInformation->FileId.Cell,
2193                       Fcb->ObjectInformation->FileId.Volume,
2194                       Fcb->ObjectInformation->FileId.Vnode,
2195                       Fcb->ObjectInformation->FileId.Unique,
2196                       ntStatus);
2197
2198         //
2199         // Remove the count we added above
2200         //
2201
2202         lCount = InterlockedDecrement( &Fcb->Specific.File.QueuedFlushCount);
2203
2204         ASSERT( lCount >= 0);
2205
2206         if( lCount == 0)
2207         {
2208
2209             KeSetEvent( &Fcb->NPFcb->Specific.File.QueuedFlushEvent,
2210                         0,
2211                         FALSE);
2212         }
2213
2214         if( !NT_SUCCESS( ntStatus))
2215         {
2216
2217             if( pWorkItem != NULL)
2218             {
2219
2220                 lCount = InterlockedDecrement( &Fcb->OpenReferenceCount);
2221
2222                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2223             }
2224
2225             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2226                           AFS_TRACE_LEVEL_ERROR,
2227                           "AFSQueueFlushExtents Failed to queue request Status %08lX\n", ntStatus);
2228         }
2229     }
2230     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2231     {
2232
2233         AFSDbgLogMsg( 0,
2234                       0,
2235                       "EXCEPTION - AFSQueueFlushExtents\n");
2236
2237         AFSDumpTraceFilesFnc();
2238     }
2239
2240     return ntStatus;
2241 }
2242
2243 NTSTATUS
2244 AFSQueueGlobalRootEnumeration()
2245 {
2246
2247     NTSTATUS ntStatus = STATUS_SUCCESS;
2248     AFSWorkItem *pWorkItem = NULL;
2249
2250     __try
2251     {
2252
2253         pWorkItem = (AFSWorkItem *) AFSLibExAllocatePoolWithTag( NonPagedPool,
2254                                                                  sizeof(AFSWorkItem),
2255                                                                  AFS_WORK_ITEM_TAG);
2256         if (NULL == pWorkItem)
2257         {
2258
2259             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2260                           AFS_TRACE_LEVEL_ERROR,
2261                           "AFSQueueGlobalRootEnumeration Failed to allocate work item\n");
2262
2263             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2264         }
2265
2266         RtlZeroMemory( pWorkItem,
2267                        sizeof(AFSWorkItem));
2268
2269         pWorkItem->Size = sizeof( AFSWorkItem);
2270
2271         pWorkItem->RequestType = AFS_WORK_ENUMERATE_GLOBAL_ROOT;
2272
2273         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2274                       AFS_TRACE_LEVEL_VERBOSE,
2275                       "AFSQueueGlobalRootEnumeration Workitem %p\n",
2276                       pWorkItem);
2277
2278         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2279
2280 try_exit:
2281
2282         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2283                       AFS_TRACE_LEVEL_VERBOSE,
2284                       "AFSQueueGlobalRootEnumeration Request complete Status %08lX\n",
2285                       ntStatus);
2286
2287         if( !NT_SUCCESS( ntStatus))
2288         {
2289
2290             if( pWorkItem != NULL)
2291             {
2292
2293                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2294             }
2295
2296             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2297                           AFS_TRACE_LEVEL_ERROR,
2298                           "AFSQueueGlobalRootEnumeration Failed to queue request Status %08lX\n",
2299                           ntStatus);
2300         }
2301     }
2302     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2303     {
2304
2305         AFSDbgLogMsg( 0,
2306                       0,
2307                       "EXCEPTION - AFSQueueGlobalRootEnumeration\n");
2308
2309         AFSDumpTraceFilesFnc();
2310     }
2311
2312     return ntStatus;
2313 }
2314
2315 NTSTATUS
2316 AFSQueueStartIos( IN PFILE_OBJECT CacheFileObject,
2317                   IN UCHAR FunctionCode,
2318                   IN ULONG RequestFlags,
2319                   IN AFSIoRun *IoRuns,
2320                   IN ULONG RunCount,
2321                   IN AFSGatherIo *GatherIo)
2322 {
2323
2324     NTSTATUS ntStatus = STATUS_SUCCESS;
2325     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
2326     AFSWorkItem *pWorkItem = NULL;
2327
2328     __try
2329     {
2330
2331         if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
2332         {
2333
2334             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2335                           AFS_TRACE_LEVEL_ERROR,
2336                           "AFSQueueStartIos Failing request, in shutdown\n");
2337
2338             try_return( ntStatus = STATUS_TOO_LATE);
2339         }
2340
2341         //
2342         // Allocate our request structure and send it to the worker
2343         //
2344
2345         pWorkItem = (AFSWorkItem *)AFSLibExAllocatePoolWithTag( NonPagedPool,
2346                                                                 sizeof( AFSWorkItem),
2347                                                                 AFS_WORK_ITEM_TAG);
2348
2349         if( pWorkItem == NULL)
2350         {
2351
2352             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2353                           AFS_TRACE_LEVEL_ERROR,
2354                           "AFSQueueStartIos Failed to allocate work item\n");
2355
2356             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2357         }
2358
2359         RtlZeroMemory( pWorkItem,
2360                        sizeof( AFSWorkItem));
2361
2362         KeInitializeEvent( &pWorkItem->Event,
2363                            NotificationEvent,
2364                            FALSE);
2365
2366         pWorkItem->Size = sizeof( AFSWorkItem);
2367
2368         pWorkItem->ProcessID = (ULONGLONG)PsGetCurrentProcessId();
2369
2370         pWorkItem->RequestType = AFS_WORK_START_IOS;
2371
2372         pWorkItem->Specific.CacheAccess.CacheFileObject = CacheFileObject;
2373
2374         pWorkItem->Specific.CacheAccess.FunctionCode = FunctionCode;
2375
2376         pWorkItem->Specific.CacheAccess.RequestFlags = RequestFlags;
2377
2378         pWorkItem->Specific.CacheAccess.IoRuns = IoRuns;
2379
2380         pWorkItem->Specific.CacheAccess.RunCount = RunCount;
2381
2382         pWorkItem->Specific.CacheAccess.GatherIo = GatherIo;
2383
2384         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2385                       AFS_TRACE_LEVEL_VERBOSE,
2386                       "AFSQueueStartIos Queuing IO Workitem %p\n",
2387                       pWorkItem);
2388
2389         ntStatus = AFSQueueIOWorkerRequest( pWorkItem);
2390
2391 try_exit:
2392
2393         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2394                       AFS_TRACE_LEVEL_VERBOSE,
2395                       "AFSQueueStartIos Request complete Status %08lX\n",
2396                       ntStatus);
2397
2398         if( !NT_SUCCESS( ntStatus))
2399         {
2400
2401             if( pWorkItem != NULL)
2402             {
2403
2404                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2405             }
2406         }
2407     }
2408     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2409     {
2410
2411         AFSDbgLogMsg( 0,
2412                       0,
2413                       "EXCEPTION - AFSQueueStartIos\n");
2414
2415         AFSDumpTraceFilesFnc();
2416     }
2417
2418     return ntStatus;
2419 }
2420
2421 NTSTATUS
2422 AFSQueueInvalidateObject( IN AFSObjectInfoCB *ObjectInfo,
2423                           IN ULONG InvalidateReason)
2424 {
2425
2426     NTSTATUS ntStatus = STATUS_SUCCESS;
2427     AFSWorkItem *pWorkItem = NULL;
2428
2429     __try
2430     {
2431
2432         pWorkItem = (AFSWorkItem *) AFSLibExAllocatePoolWithTag( NonPagedPool,
2433                                                                  sizeof(AFSWorkItem),
2434                                                                  AFS_WORK_ITEM_TAG);
2435         if (NULL == pWorkItem)
2436         {
2437
2438             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2439                           AFS_TRACE_LEVEL_ERROR,
2440                           "AFSQueueInvalidateObject Failed to allocate work item\n");
2441
2442             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2443         }
2444
2445         RtlZeroMemory( pWorkItem,
2446                        sizeof(AFSWorkItem));
2447
2448         pWorkItem->Size = sizeof( AFSWorkItem);
2449
2450         pWorkItem->RequestType = AFS_WORK_INVALIDATE_OBJECT;
2451
2452         pWorkItem->Specific.Invalidate.ObjectInfo = ObjectInfo;
2453
2454         pWorkItem->Specific.Invalidate.InvalidateReason = InvalidateReason;
2455
2456         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2457                       AFS_TRACE_LEVEL_VERBOSE,
2458                       "AFSQueueInvalidateObject Workitem %p\n",
2459                       pWorkItem);
2460
2461         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2462
2463 try_exit:
2464
2465         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2466                       AFS_TRACE_LEVEL_VERBOSE,
2467                       "AFSQueueInvalidateObject Request complete Status %08lX\n",
2468                       ntStatus);
2469
2470         if( !NT_SUCCESS( ntStatus))
2471         {
2472
2473             if( pWorkItem != NULL)
2474             {
2475                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2476             }
2477
2478             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2479                           AFS_TRACE_LEVEL_ERROR,
2480                           "AFSQueueInvalidateObject Failed to queue request Status %08lX\n",
2481                           ntStatus);
2482         }
2483     }
2484     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2485     {
2486
2487         AFSDbgLogMsg( 0,
2488                       0,
2489                       "EXCEPTION - AFSQueueInvalidateObject\n");
2490
2491         AFSDumpTraceFilesFnc();
2492     }
2493
2494     return ntStatus;
2495 }