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