Windows: Wait for all worker threads to exit
[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->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             pStartRoutine = AFSPrimaryVolumeWorkerThread;
396         }
397         else
398         {
399
400             pStartRoutine = AFSVolumeWorkerThread;
401         }
402
403         //
404         // Initialize the worker thread
405         //
406
407         KeInitializeEvent( &pWorker->WorkerThreadReady,
408                            NotificationEvent,
409                            FALSE);
410
411         //
412         // Set the worker to process requests
413         //
414
415         pWorker->State = AFS_WORKER_PROCESS_REQUESTS;
416
417         //
418         // Launch the thread
419         //
420
421         ntStatus =  PsCreateSystemThread( &hThread,
422                                           0,
423                                           NULL,
424                                           NULL,
425                                           NULL,
426                                           pStartRoutine,
427                                           (void *)VolumeCB);
428
429         if( NT_SUCCESS( ntStatus))
430         {
431
432             ObReferenceObjectByHandle( hThread,
433                                        GENERIC_READ | GENERIC_WRITE,
434                                        NULL,
435                                        KernelMode,
436                                        (PVOID *)&pWorker->WorkerThreadObject,
437                                        NULL);
438
439             ntStatus = KeWaitForSingleObject( &pWorker->WorkerThreadReady,
440                                               Executive,
441                                               KernelMode,
442                                               FALSE,
443                                               NULL);
444
445             lCount = InterlockedIncrement( &pControlDeviceExt->Specific.Control.VolumeWorkerThreadCount);
446
447             if( lCount > 0)
448             {
449
450                 KeClearEvent( &pControlDeviceExt->Specific.Control.VolumeWorkerCloseEvent);
451             }
452
453             ZwClose( hThread);
454         }
455     }
456
457     return ntStatus;
458 }
459
460 //
461 // Function: AFSInitWorkerThread
462 //
463 // Description:
464 //
465 //      This function initializes a worker thread in the pool
466 //
467 // Return:
468 //
469 //      A status is returned for the function
470 //
471
472 NTSTATUS
473 AFSInitWorkerThread( IN AFSWorkQueueContext *PoolContext,
474                      IN PKSTART_ROUTINE WorkerRoutine)
475 {
476
477     NTSTATUS ntStatus = STATUS_SUCCESS;
478     HANDLE Handle;
479
480     //
481     // INitialize the worker signal thread
482     //
483
484     KeInitializeEvent( &PoolContext->WorkerThreadReady,
485                        NotificationEvent,
486                        FALSE);
487
488     //
489     // Set the worker to process requests
490     //
491
492     PoolContext->State = AFS_WORKER_PROCESS_REQUESTS;
493
494     //
495     // Launch the thread
496     //
497
498     ntStatus =  PsCreateSystemThread( &Handle,
499                                       0,
500                                       NULL,
501                                       NULL,
502                                       NULL,
503                                       WorkerRoutine,
504                                       (void *)PoolContext);
505
506     if( NT_SUCCESS( ntStatus))
507     {
508
509         ObReferenceObjectByHandle( Handle,
510                                    GENERIC_READ | GENERIC_WRITE,
511                                    NULL,
512                                    KernelMode,
513                                    (PVOID *)&PoolContext->WorkerThreadObject,
514                                    NULL);
515
516         ntStatus = KeWaitForSingleObject( &PoolContext->WorkerThreadReady,
517                                           Executive,
518                                           KernelMode,
519                                           FALSE,
520                                           NULL);
521
522         ZwClose( Handle);
523     }
524
525     return ntStatus;
526 }
527
528 NTSTATUS
529 AFSShutdownVolumeWorker( IN AFSVolumeCB *VolumeCB)
530 {
531
532     NTSTATUS ntStatus = STATUS_SUCCESS;
533     AFSWorkQueueContext *pWorker = &VolumeCB->VolumeWorkerContext;
534
535     //
536     // Clear the 'keep processing' flag
537     //
538
539     ClearFlag( pWorker->State, AFS_WORKER_PROCESS_REQUESTS);
540
541     if( pWorker->WorkerThreadObject != NULL)
542     {
543         while ( BooleanFlagOn( pWorker->State, AFS_WORKER_INITIALIZED) )
544         {
545
546             ntStatus = KeWaitForSingleObject( pWorker->WorkerThreadObject,
547                                               Executive,
548                                               KernelMode,
549                                               FALSE,
550                                               NULL);
551         }
552
553         ObDereferenceObject( pWorker->WorkerThreadObject);
554
555         pWorker->WorkerThreadObject = NULL;
556     }
557
558     return ntStatus;
559 }
560
561 //
562 // Function: AFSShutdownWorkerThread
563 //
564 // Description:
565 //
566 //      This function shutsdown a worker thread in the pool
567 //
568 // Return:
569 //
570 //      A status is returned for the function
571 //
572
573 NTSTATUS
574 AFSShutdownWorkerThread( IN AFSWorkQueueContext *PoolContext)
575 {
576
577     NTSTATUS ntStatus = STATUS_SUCCESS;
578     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
579
580     if( PoolContext->WorkerThreadObject != NULL)
581     {
582
583         while ( BooleanFlagOn( PoolContext->State, AFS_WORKER_INITIALIZED) )
584         {
585
586             //
587             // Wake up the thread if it is a sleep
588             //
589
590             KeSetEvent( &pDeviceExt->Specific.Library.WorkerQueueHasItems,
591                         0,
592                         FALSE);
593
594             ntStatus = KeWaitForSingleObject( PoolContext->WorkerThreadObject,
595                                               Executive,
596                                               KernelMode,
597                                               FALSE,
598                                               NULL);
599         }
600
601         ObDereferenceObject( PoolContext->WorkerThreadObject);
602
603         PoolContext->WorkerThreadObject = NULL;
604     }
605
606     return ntStatus;
607 }
608
609 //
610 // Function: AFSShutdownIOWorkerThread
611 //
612 // Description:
613 //
614 //      This function shutsdown an IO worker thread in the pool
615 //
616 // Return:
617 //
618 //      A status is returned for the function
619 //
620
621 NTSTATUS
622 AFSShutdownIOWorkerThread( IN AFSWorkQueueContext *PoolContext)
623 {
624
625     NTSTATUS ntStatus = STATUS_SUCCESS;
626     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
627
628     if( PoolContext->WorkerThreadObject != NULL)
629     {
630
631         while ( BooleanFlagOn( PoolContext->State, AFS_WORKER_INITIALIZED) )
632         {
633
634             //
635             // Wake up the thread if it is a sleep
636             //
637
638             KeSetEvent( &pDeviceExt->Specific.Library.IOWorkerQueueHasItems,
639                         0,
640                         FALSE);
641
642             ntStatus = KeWaitForSingleObject( PoolContext->WorkerThreadObject,
643                                               Executive,
644                                               KernelMode,
645                                               FALSE,
646                                               NULL);
647         }
648
649         ObDereferenceObject( PoolContext->WorkerThreadObject);
650
651         PoolContext->WorkerThreadObject = NULL;
652     }
653
654     return ntStatus;
655 }
656
657 //
658 // Function: AFSWorkerThread
659 //
660 // Description:
661 //
662 //      This is the worker thread entry point.
663 //
664 // Return:
665 //
666 //      A status is returned for the function
667 //
668
669 void
670 AFSWorkerThread( IN PVOID Context)
671 {
672
673     NTSTATUS ntStatus = STATUS_SUCCESS;
674     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)Context;
675     AFSWorkItem *pWorkItem;
676     BOOLEAN freeWorkItem = TRUE;
677     AFSDeviceExt *pLibraryDevExt = NULL;
678     LONG lCount;
679
680     pLibraryDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
681
682     //
683     // Indicate that we are initialized and ready
684     //
685
686     KeSetEvent( &pPoolContext->WorkerThreadReady,
687                 0,
688                 FALSE);
689
690     //
691     // Indicate we are initialized
692     //
693
694     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
695
696     ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.WorkerQueueHasItems,
697                                       Executive,
698                                       KernelMode,
699                                       FALSE,
700                                       NULL);
701
702     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
703     {
704
705         if( !NT_SUCCESS( ntStatus))
706         {
707
708             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
709                           AFS_TRACE_LEVEL_ERROR,
710                           "AFSWorkerThread Wait for queue items failed Status %08lX\n", ntStatus);
711
712             ntStatus = STATUS_SUCCESS;
713         }
714         else
715         {
716
717             pWorkItem = AFSRemoveWorkItem();
718
719             if( pWorkItem == NULL)
720             {
721
722                 ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.WorkerQueueHasItems,
723                                                   Executive,
724                                                   KernelMode,
725                                                   FALSE,
726                                                   NULL);
727             }
728             else
729             {
730
731                 freeWorkItem = TRUE;
732
733                 //
734                 // Switch on the type of work item to process
735                 //
736
737                 switch( pWorkItem->RequestType)
738                 {
739
740                     case AFS_WORK_FLUSH_FCB:
741                     {
742
743                         ntStatus = AFSFlushExtents( pWorkItem->Specific.Fcb.Fcb,
744                                                     &pWorkItem->AuthGroup);
745
746                         if( !NT_SUCCESS( ntStatus))
747                         {
748
749                             AFSReleaseExtentsWithFlush( pWorkItem->Specific.Fcb.Fcb,
750                                                         &pWorkItem->AuthGroup,
751                                                         FALSE);
752                         }
753
754                         ASSERT( pWorkItem->Specific.Fcb.Fcb->OpenReferenceCount != 0);
755
756                         lCount = InterlockedDecrement( &pWorkItem->Specific.Fcb.Fcb->OpenReferenceCount);
757
758                         break;
759                     }
760
761                     case AFS_WORK_ENUMERATE_GLOBAL_ROOT:
762                     {
763
764                         AFSEnumerateGlobalRoot( NULL);
765
766                         break;
767                     }
768
769                     case AFS_WORK_INVALIDATE_OBJECT:
770                     {
771
772                         AFSPerformObjectInvalidate( pWorkItem->Specific.Invalidate.ObjectInfo,
773                                                     pWorkItem->Specific.Invalidate.InvalidateReason);
774
775                         freeWorkItem = TRUE;
776
777                         break;
778                     }
779
780                     case AFS_WORK_START_IOS:
781                     {
782
783                         freeWorkItem = TRUE;
784
785                         break;
786                     }
787
788                     default:
789
790                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
791                                       AFS_TRACE_LEVEL_ERROR,
792                                       "AFSWorkerThread Unknown request type %d\n", pWorkItem->RequestType);
793
794                         break;
795                 }
796
797                 if( freeWorkItem)
798                 {
799
800                     ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
801                 }
802
803                 ntStatus = STATUS_SUCCESS;
804             }
805         }
806     } // worker thread loop
807
808     ClearFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
809
810     // Wake up another worker so they too can exit
811
812     KeSetEvent( &pLibraryDevExt->Specific.Library.WorkerQueueHasItems,
813                 0,
814                 FALSE);
815
816     PsTerminateSystemThread( 0);
817
818     return;
819 }
820
821 void
822 AFSIOWorkerThread( IN PVOID Context)
823 {
824
825     NTSTATUS ntStatus = STATUS_SUCCESS;
826     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)Context;
827     AFSWorkItem *pWorkItem;
828     BOOLEAN freeWorkItem = TRUE;
829     AFSDeviceExt *pLibraryDevExt = NULL, *pRdrDevExt = NULL;
830
831     pLibraryDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
832
833     //
834     // Indicate that we are initialized and ready
835     //
836
837     KeSetEvent( &pPoolContext->WorkerThreadReady,
838                 0,
839                 FALSE);
840
841
842     //
843     // Indicate we are initialized
844     //
845
846     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
847
848     ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.IOWorkerQueueHasItems,
849                                       Executive,
850                                       KernelMode,
851                                       FALSE,
852                                       NULL);
853
854     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
855     {
856
857         if( !NT_SUCCESS( ntStatus))
858         {
859
860             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
861                           AFS_TRACE_LEVEL_ERROR,
862                           "AFSIOWorkerThread Wait for queue items failed Status %08lX\n", ntStatus);
863
864             ntStatus = STATUS_SUCCESS;
865         }
866         else
867         {
868
869             pWorkItem = AFSRemoveIOWorkItem();
870
871             if( pWorkItem == NULL)
872             {
873
874                 ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.IOWorkerQueueHasItems,
875                                                   Executive,
876                                                   KernelMode,
877                                                   FALSE,
878                                                   NULL);
879             }
880             else
881             {
882
883                 freeWorkItem = TRUE;
884
885                 //
886                 // Switch on the type of work item to process
887                 //
888
889                 switch( pWorkItem->RequestType)
890                 {
891
892                     case AFS_WORK_START_IOS:
893                     {
894
895                         pRdrDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
896
897                         //
898                         // The final status is in the gather io
899                         //
900
901                         ntStatus = AFSStartIos( pWorkItem->Specific.CacheAccess.CacheFileObject,
902                                                 pWorkItem->Specific.CacheAccess.FunctionCode,
903                                                 pWorkItem->Specific.CacheAccess.RequestFlags,
904                                                 pWorkItem->Specific.CacheAccess.IoRuns,
905                                                 pWorkItem->Specific.CacheAccess.RunCount,
906                                                 pWorkItem->Specific.CacheAccess.GatherIo);
907
908                         //
909                         // Regardless of the status we we do the complete - there may
910                         // be IOs in flight
911                         // Decrement the count - setting the event if we were told
912                         // to. This may trigger completion.
913                         //
914
915                         AFSCompleteIo( pWorkItem->Specific.CacheAccess.GatherIo, ntStatus );
916
917                         freeWorkItem = TRUE;
918
919                         break;
920                     }
921
922                     default:
923
924                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
925                                       AFS_TRACE_LEVEL_ERROR,
926                                       "AFSWorkerThread Unknown request type %d\n", pWorkItem->RequestType);
927
928                         break;
929                 }
930
931                 if( freeWorkItem)
932                 {
933
934                     ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
935                 }
936
937                 ntStatus = STATUS_SUCCESS;
938             }
939         }
940     } // worker thread loop
941
942     ClearFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
943
944     // Wake up another IOWorker so they too can exit
945
946     KeSetEvent( &pLibraryDevExt->Specific.Library.IOWorkerQueueHasItems,
947                 0,
948                 FALSE);
949
950     PsTerminateSystemThread( 0);
951
952     return;
953 }
954
955 void
956 AFSPrimaryVolumeWorkerThread( IN PVOID Context)
957 {
958
959     UNREFERENCED_PARAMETER(Context);
960     NTSTATUS ntStatus = STATUS_SUCCESS;
961     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)&AFSGlobalRoot->VolumeWorkerContext;
962     AFSDeviceExt *pControlDeviceExt = NULL;
963     AFSDeviceExt *pRDRDeviceExt = NULL;
964     LARGE_INTEGER DueTime;
965     LONG TimeOut;
966     KTIMER Timer;
967     AFSObjectInfoCB *pCurrentObject = NULL, *pNextObject = NULL, *pCurrentChildObject = NULL;
968     AFSDirectoryCB *pCurrentDirEntry = NULL, *pNextDirEntry = NULL;
969     BOOLEAN bReleaseVolumeLock = FALSE;
970     AFSVolumeCB *pVolumeCB = NULL, *pNextVolume = NULL;
971     AFSFcb *pFcb = NULL;
972     LARGE_INTEGER liCurrentTime;
973     BOOLEAN bVolumeObject = FALSE;
974     BOOLEAN bFcbBusy = FALSE;
975     LONG lCount;
976
977     pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
978
979     pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
980
981     AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
982                   AFS_TRACE_LEVEL_VERBOSE,
983                   "AFSPrimaryVolumeWorkerThread Initialized\n");
984
985     //
986     // Initialize the timer for the worker thread
987     //
988
989     DueTime.QuadPart = -(5000);
990
991     TimeOut = 5000;
992
993     KeInitializeTimerEx( &Timer,
994                          SynchronizationTimer);
995
996     KeSetTimerEx( &Timer,
997                   DueTime,
998                   TimeOut,
999                   NULL);
1000
1001     //
1002     // Indicate that we are initialized and ready
1003     //
1004
1005     KeSetEvent( &pPoolContext->WorkerThreadReady,
1006                 0,
1007                 FALSE);
1008
1009     //
1010     // Indicate we are initialized
1011     //
1012
1013     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
1014
1015     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
1016     {
1017
1018         if ( bFcbBusy == FALSE)
1019         {
1020
1021             KeWaitForSingleObject( &Timer,
1022                                    Executive,
1023                                    KernelMode,
1024                                    FALSE,
1025                                    NULL);
1026         }
1027         else
1028         {
1029
1030             bFcbBusy = FALSE;
1031         }
1032
1033         //
1034         // This is the primary volume worker so it will traverse the volume list
1035         // looking for cleanup or volumes requiring private workers
1036         //
1037
1038         AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1039                           TRUE);
1040
1041         pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead;
1042
1043         while( pVolumeCB != NULL)
1044         {
1045
1046             if( pVolumeCB == AFSGlobalRoot ||
1047                 !AFSAcquireExcl( pVolumeCB->VolumeLock,
1048                                  FALSE))
1049             {
1050
1051                 pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1052
1053                 continue;
1054             }
1055
1056             if( pVolumeCB->ObjectInfoListHead == NULL)
1057             {
1058
1059                 AFSReleaseResource( pVolumeCB->VolumeLock);
1060
1061                 AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1062
1063                 AFSAcquireExcl( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock,
1064                                 TRUE);
1065
1066                 AFSAcquireExcl( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1067                                 TRUE);
1068
1069                 if( !AFSAcquireExcl( pVolumeCB->VolumeLock,
1070                                      FALSE))
1071                 {
1072
1073                     AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1074
1075                     AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
1076
1077                     pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1078
1079                     continue;
1080                 }
1081
1082                 KeQueryTickCount( &liCurrentTime);
1083
1084                 pNextVolume = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1085
1086                 AFSAcquireShared( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock,
1087                                   TRUE);
1088
1089                 if( pVolumeCB->ObjectInfoListHead == NULL &&
1090                     pVolumeCB->DirectoryCB->DirOpenReferenceCount <= 0 &&
1091                     pVolumeCB->VolumeReferenceCount == 1 &&
1092                     ( pVolumeCB->RootFcb == NULL ||
1093                       pVolumeCB->RootFcb->OpenReferenceCount == 0) &&
1094                     pVolumeCB->ObjectInformation.ObjectReferenceCount <= 0)
1095                 {
1096
1097                     if( pVolumeCB->RootFcb != NULL)
1098                     {
1099
1100                         AFSRemoveRootFcb( pVolumeCB->RootFcb);
1101                     }
1102
1103                     AFSReleaseResource( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
1104
1105                     AFSRemoveVolume( pVolumeCB);
1106                 }
1107                 else
1108                 {
1109
1110                     AFSReleaseResource( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
1111
1112                     AFSReleaseResource( pVolumeCB->VolumeLock);
1113                 }
1114
1115                 AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1116
1117                 AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
1118
1119                 pVolumeCB = pNextVolume;
1120
1121                 continue;
1122             }
1123
1124             //
1125             // Don't need this lock anymore now that we have a volume cb to work with
1126             //
1127
1128             AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1129
1130             //
1131             // For now we only need the volume lock shared
1132             //
1133
1134             AFSConvertToShared( pVolumeCB->VolumeLock);
1135
1136             if( AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1137                                   FALSE))
1138             {
1139
1140                 pCurrentObject = pVolumeCB->ObjectInfoListHead;
1141
1142                 pNextObject = NULL;
1143
1144                 bReleaseVolumeLock = TRUE;
1145
1146                 while( pCurrentObject != NULL)
1147                 {
1148
1149                     if( pCurrentObject != &pVolumeCB->ObjectInformation)
1150                     {
1151
1152                         pNextObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1153
1154                         if( pNextObject == NULL &&
1155                             pVolumeCB != AFSGlobalRoot)  // Don't free up the root of the global
1156                         {
1157
1158                             pNextObject = &pVolumeCB->ObjectInformation;
1159                         }
1160
1161                         bVolumeObject = FALSE;
1162                     }
1163                     else
1164                     {
1165
1166                         pNextObject = NULL;
1167
1168                         bVolumeObject = TRUE;
1169                     }
1170
1171                     if( pCurrentObject->FileType == AFS_FILE_TYPE_DIRECTORY &&
1172                         !BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))  // If we are in shutdown mode skip directories
1173                     {
1174
1175                         //
1176                         // If this object is deleted then remove it from the parent, if we can
1177                         //
1178
1179                         if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DELETED) &&
1180                             pCurrentObject->ObjectReferenceCount <= 0 &&
1181                             ( pCurrentObject->Fcb == NULL ||
1182                               pCurrentObject->Fcb->OpenReferenceCount == 0) &&
1183                             pCurrentObject->Specific.Directory.DirectoryNodeListHead == NULL &&
1184                             pCurrentObject->Specific.Directory.ChildOpenReferenceCount == 0)
1185                         {
1186
1187                             AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1188
1189                             //
1190                             // Dropping the TreeLock permits the
1191                             // pCurrentObject->ObjectReferenceCount to change
1192                             //
1193
1194                             if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1195                                                 FALSE))
1196                             {
1197
1198                                 AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
1199                                                 TRUE);
1200
1201                                 if ( pCurrentObject->ObjectReferenceCount <= 0)
1202                                 {
1203
1204                                     AFSRemoveFcb( &pCurrentObject->Fcb);
1205
1206                                     if( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
1207                                     {
1208
1209                                         AFSAcquireExcl( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock,
1210                                                         TRUE);
1211
1212                                         AFSRemoveFcb( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
1213
1214                                         AFSReleaseResource( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
1215
1216                                         AFSDeleteObjectInfo( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
1217
1218                                         ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
1219
1220                                         AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
1221
1222                                         AFSExFreePoolWithTag( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
1223                                     }
1224
1225                                     AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1226
1227                                     AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1228                                                   AFS_TRACE_LEVEL_VERBOSE,
1229                                                   "AFSPrimaryVolumeWorkerThread Deleting deleted object %08lX\n",
1230                                                   pCurrentObject);
1231
1232                                     AFSDeleteObjectInfo( pCurrentObject);
1233                                 }
1234                                 else
1235                                 {
1236
1237                                     AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1238                                 }
1239
1240                                 AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1241
1242                                 pCurrentObject = pNextObject;
1243
1244                                 continue;
1245                             }
1246                             else
1247                             {
1248
1249                                 bReleaseVolumeLock = FALSE;
1250
1251                                 break;
1252                             }
1253                         }
1254
1255                         if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0 ||
1256                             ( pCurrentObject->Fcb != NULL &&
1257                               pCurrentObject->Fcb->OpenReferenceCount > 0) ||
1258                             pCurrentObject->Specific.Directory.DirectoryNodeListHead == NULL)
1259                         {
1260
1261                             pCurrentObject = pNextObject;
1262
1263                             continue;
1264                         }
1265
1266                         if( !AFSAcquireShared( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
1267                                                FALSE))
1268                         {
1269
1270                             pCurrentObject = pNextObject;
1271
1272                             continue;
1273                         }
1274
1275                         KeQueryTickCount( &liCurrentTime);
1276
1277                         pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
1278
1279                         while( pCurrentDirEntry != NULL)
1280                         {
1281
1282                             if( pCurrentDirEntry->DirOpenReferenceCount > 0 ||
1283                                 ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1284                                   pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0) ||
1285                                 liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart ||
1286                                 liCurrentTime.QuadPart - pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart <
1287                                                                         pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart ||
1288                                 ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY &&
1289                                    ( pCurrentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL ||
1290                                      pCurrentDirEntry->ObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)) ||
1291                                 ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE &&
1292                                   pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1293                                   pCurrentDirEntry->ObjectInformation->Fcb->Specific.File.ExtentsDirtyCount > 0))
1294                             {
1295
1296                                 break;
1297                             }
1298
1299                             pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
1300                         }
1301
1302                         if( pCurrentDirEntry != NULL)
1303                         {
1304
1305                             AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1306
1307                             pCurrentObject = pNextObject;
1308
1309                             continue;
1310                         }
1311
1312                         AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1313
1314                         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1315
1316                         //
1317                         // Now acquire the locks excl
1318                         //
1319
1320                         if( AFSAcquireExcl( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
1321                                             FALSE))
1322                         {
1323
1324                             if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1325                                                 FALSE))
1326                             {
1327
1328                                 if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0)
1329                                 {
1330
1331                                     AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1332
1333                                     AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1334
1335                                     pCurrentObject = pNextObject;
1336
1337                                     continue;
1338                                 }
1339
1340                                 KeQueryTickCount( &liCurrentTime);
1341
1342                                 pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
1343
1344                                 while( pCurrentDirEntry != NULL)
1345                                 {
1346
1347                                     if( pCurrentDirEntry->DirOpenReferenceCount > 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 %08lX\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
1407                                     if( lCount == 1 &&
1408                                         pCurrentChildObject->Fcb != NULL &&
1409                                         pCurrentChildObject->FileType == AFS_FILE_TYPE_FILE)
1410                                     {
1411
1412                                         //
1413                                         // We must not hold pVolumeCB->ObjectInfoTree.TreeLock exclusive
1414                                         // across an AFSCleanupFcb call since it can deadlock with an
1415                                         // invalidation call from the service.
1416                                         //
1417
1418                                         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1419
1420                                         //
1421                                         // Cannot hold a TreeLock across an AFSCleanupFcb call
1422                                         // as it can deadlock with an invalidation ioctl initiated
1423                                         // from the service.
1424                                         //
1425                                         // Dropping the TreeLock permits the
1426                                         // pCurrentObject->ObjectReferenceCount to change
1427                                         //
1428
1429                                         ntStatus = AFSCleanupFcb( pCurrentChildObject->Fcb,
1430                                                                   TRUE);
1431
1432                                         if ( ntStatus == STATUS_RETRY)
1433                                         {
1434
1435                                             bFcbBusy = TRUE;
1436                                         }
1437
1438                                         AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1439                                                         TRUE);
1440                                     }
1441
1442                                     lCount = AFSObjectInfoDecrement( pCurrentChildObject);
1443
1444                                     AFSAcquireExcl( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock,
1445                                                     TRUE);
1446
1447                                     if( pCurrentChildObject->ObjectReferenceCount <= 0)
1448                                     {
1449
1450                                         AFSRemoveFcb( &pCurrentChildObject->Fcb);
1451
1452                                         if( pCurrentChildObject->FileType == AFS_FILE_TYPE_DIRECTORY &&
1453                                             pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
1454                                         {
1455
1456                                             AFSAcquireExcl( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock,
1457                                                             TRUE);
1458
1459                                             AFSRemoveFcb( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
1460
1461                                             AFSReleaseResource( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
1462
1463                                             AFSDeleteObjectInfo( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
1464
1465                                             ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
1466
1467                                             AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
1468
1469                                             AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
1470                                         }
1471
1472                                         AFSReleaseResource( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock);
1473
1474                                         AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1475                                                       AFS_TRACE_LEVEL_VERBOSE,
1476                                                       "AFSPrimaryVolumeWorkerThread Deleting object %08lX\n",
1477                                                       pCurrentChildObject);
1478
1479                                         AFSDeleteObjectInfo( pCurrentChildObject);
1480                                     }
1481                                     else
1482                                     {
1483
1484                                         AFSReleaseResource( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock);
1485                                     }
1486
1487                                     pCurrentDirEntry = pNextDirEntry;
1488
1489                                 }
1490
1491                                 pCurrentObject->Specific.Directory.DirectoryNodeListHead = NULL;
1492
1493                                 pCurrentObject->Specific.Directory.DirectoryNodeListTail = NULL;
1494
1495                                 pCurrentObject->Specific.Directory.ShortNameTree = NULL;
1496
1497                                 pCurrentObject->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead = NULL;
1498
1499                                 pCurrentObject->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead = NULL;
1500
1501                                 pCurrentObject->Specific.Directory.DirectoryNodeCount = 0;
1502
1503                                 AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NODE_COUNT,
1504                                               AFS_TRACE_LEVEL_VERBOSE,
1505                                               "AFSPrimaryVolumeWorkerThread Reset count to 0 on parent FID %08lX-%08lX-%08lX-%08lX\n",
1506                                               pCurrentObject->FileId.Cell,
1507                                               pCurrentObject->FileId.Volume,
1508                                               pCurrentObject->FileId.Vnode,
1509                                               pCurrentObject->FileId.Unique);
1510
1511                                 //
1512                                 // Clear our enumerated flag on this object so we retrieve info again on next access
1513                                 //
1514
1515                                 ClearFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED);
1516
1517                                 AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1518
1519                                 AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1520                             }
1521                             else
1522                             {
1523
1524                                 AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1525
1526                                 bReleaseVolumeLock = FALSE;
1527
1528                                 break;
1529                             }
1530                         }
1531                         else
1532                         {
1533
1534                             //
1535                             // Try to grab the volume lock again ... no problem if we don't
1536                             //
1537
1538                             if( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1539                                                  FALSE))
1540                             {
1541
1542                                 bReleaseVolumeLock = FALSE;
1543
1544                                 break;
1545                             }
1546                         }
1547
1548                         if( pCurrentObject != &pVolumeCB->ObjectInformation)
1549                         {
1550
1551                             pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1552
1553                             if( pCurrentObject == NULL &&
1554                                 pVolumeCB != AFSGlobalRoot)
1555                             {
1556
1557                                 pCurrentObject = &pVolumeCB->ObjectInformation;
1558                             }
1559                         }
1560                         else
1561                         {
1562
1563                             pCurrentObject = NULL;
1564                         }
1565
1566                         continue;
1567                     }
1568                     else if( pCurrentObject->FileType == AFS_FILE_TYPE_FILE)
1569                     {
1570
1571                         lCount = AFSObjectInfoIncrement( pCurrentObject);
1572
1573                         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1574
1575                         if( pCurrentObject->Fcb != NULL)
1576                         {
1577
1578                             //
1579                             // Dropping the TreeLock permits the
1580                             // pCurrentObject->ObjectReferenceCount to change
1581                             //
1582
1583                             ntStatus = AFSCleanupFcb( pCurrentObject->Fcb,
1584                                                       FALSE);
1585
1586                             if ( ntStatus == STATUS_RETRY)
1587                             {
1588
1589                                 bFcbBusy = TRUE;
1590                             }
1591                         }
1592
1593                         lCount = AFSObjectInfoDecrement( pCurrentObject);
1594
1595                         if( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1596                                              FALSE))
1597                         {
1598
1599                             bReleaseVolumeLock = FALSE;
1600
1601                             break;
1602                         }
1603
1604                         AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
1605                                         TRUE);
1606
1607                         if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DELETED) &&
1608                             pCurrentObject->ObjectReferenceCount <= 0)
1609                         {
1610
1611                             AFSRemoveFcb( &pCurrentObject->Fcb);
1612
1613                             AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1614
1615                             AFSDeleteObjectInfo( pCurrentObject);
1616                         }
1617                         else
1618                         {
1619
1620                             AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1621                         }
1622
1623                         AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1624
1625                         pCurrentObject = pNextObject;
1626
1627                         continue;
1628                     }
1629
1630                     pCurrentObject = pNextObject;
1631                 }
1632
1633                 if( bReleaseVolumeLock)
1634                 {
1635
1636                     AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1637                 }
1638             }
1639
1640             //
1641             // Next volume cb
1642             //
1643
1644             AFSReleaseResource( pVolumeCB->VolumeLock);
1645
1646             AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1647                               TRUE);
1648
1649             pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1650         }
1651
1652         AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1653
1654     } // worker thread loop
1655
1656     KeCancelTimer( &Timer);
1657
1658     ClearFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
1659
1660     AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1661                   AFS_TRACE_LEVEL_VERBOSE,
1662                   "AFSPrimaryVolumeWorkerThread Exiting\n");
1663
1664     lCount = InterlockedDecrement( &pControlDeviceExt->Specific.Control.VolumeWorkerThreadCount);
1665
1666     if( lCount == 0)
1667     {
1668
1669         KeSetEvent( &pControlDeviceExt->Specific.Control.VolumeWorkerCloseEvent,
1670                     0,
1671                     FALSE);
1672     }
1673
1674     PsTerminateSystemThread( 0);
1675
1676     return;
1677 }
1678
1679 void
1680 AFSVolumeWorkerThread( IN PVOID Context)
1681 {
1682
1683     NTSTATUS ntStatus = STATUS_SUCCESS;
1684     AFSVolumeCB *pVolumeCB = (AFSVolumeCB * )Context;
1685     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)&pVolumeCB->VolumeWorkerContext;
1686     AFSDeviceExt *pControlDeviceExt = NULL;
1687     AFSDeviceExt *pRDRDeviceExt = NULL;
1688     LARGE_INTEGER DueTime;
1689     LONG TimeOut;
1690     KTIMER Timer;
1691     LONG lCount;
1692
1693     pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1694
1695     pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1696
1697     //
1698     // Initialize the timer for the worker thread
1699     //
1700
1701     DueTime.QuadPart = -(5000);
1702
1703     TimeOut = 5000;
1704
1705     KeInitializeTimerEx( &Timer,
1706                          SynchronizationTimer);
1707
1708     KeSetTimerEx( &Timer,
1709                   DueTime,
1710                   TimeOut,
1711                   NULL);
1712
1713     //
1714     // Indicate that we are initialized and ready
1715     //
1716
1717     KeSetEvent( &pPoolContext->WorkerThreadReady,
1718                 0,
1719                 FALSE);
1720
1721     //
1722     // Indicate we are initialized
1723     //
1724
1725     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
1726
1727     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
1728     {
1729
1730         ntStatus = KeWaitForSingleObject( &Timer,
1731                                           Executive,
1732                                           KernelMode,
1733                                           FALSE,
1734                                           NULL);
1735
1736         if( !NT_SUCCESS( ntStatus))
1737         {
1738
1739             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1740                           AFS_TRACE_LEVEL_ERROR,
1741                           "AFSVolumeWorkerThread Wait for queue items failed Status %08lX\n", ntStatus);
1742         }
1743         else
1744         {
1745
1746             //
1747             // If we are in shutdown mode and the dirty flag is clear then get out now
1748             //
1749
1750             if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
1751             {
1752
1753                 break;
1754             }
1755         }
1756     } // worker thread loop
1757
1758     KeCancelTimer( &Timer);
1759
1760     lCount = InterlockedDecrement( &pControlDeviceExt->Specific.Control.VolumeWorkerThreadCount);
1761
1762     if( lCount == 0)
1763     {
1764
1765         KeSetEvent( &pControlDeviceExt->Specific.Control.VolumeWorkerCloseEvent,
1766                     0,
1767                     FALSE);
1768     }
1769
1770     PsTerminateSystemThread( 0);
1771
1772     return;
1773 }
1774
1775 NTSTATUS
1776 AFSInsertWorkitem( IN AFSWorkItem *WorkItem)
1777 {
1778
1779     NTSTATUS ntStatus = STATUS_SUCCESS;
1780     AFSDeviceExt *pDevExt = NULL;
1781     LONG lCount;
1782
1783     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1784
1785     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1786                   AFS_TRACE_LEVEL_VERBOSE,
1787                   "AFSInsertWorkitem Acquiring Control QueueLock lock %08lX EXCL %08lX\n",
1788                   &pDevExt->Specific.Library.QueueLock,
1789                   PsGetCurrentThread());
1790
1791     AFSAcquireExcl( &pDevExt->Specific.Library.QueueLock,
1792                     TRUE);
1793
1794     lCount = InterlockedIncrement( &pDevExt->Specific.Library.QueueItemCount);
1795
1796     AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
1797                   AFS_TRACE_LEVEL_VERBOSE,
1798                   "AFSInsertWorkitem Inserting work item %08lX Count %08lX\n",
1799                   WorkItem,
1800                   lCount);
1801
1802     if( pDevExt->Specific.Library.QueueTail != NULL) // queue already has nodes
1803     {
1804
1805         pDevExt->Specific.Library.QueueTail->next = WorkItem;
1806     }
1807     else // first node
1808     {
1809
1810         pDevExt->Specific.Library.QueueHead = WorkItem;
1811     }
1812
1813     WorkItem->next = NULL;
1814     pDevExt->Specific.Library.QueueTail = WorkItem;
1815
1816     // indicate that the queue has nodes
1817     KeSetEvent( &(pDevExt->Specific.Library.WorkerQueueHasItems),
1818                 0,
1819                 FALSE);
1820
1821     AFSReleaseResource( &pDevExt->Specific.Library.QueueLock);
1822
1823     return ntStatus;
1824 }
1825
1826 NTSTATUS
1827 AFSInsertIOWorkitem( IN AFSWorkItem *WorkItem)
1828 {
1829
1830     NTSTATUS ntStatus = STATUS_SUCCESS;
1831     AFSDeviceExt *pDevExt = NULL;
1832     LONG lCount;
1833
1834     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1835
1836     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1837                   AFS_TRACE_LEVEL_VERBOSE,
1838                   "AFSInsertIOWorkitem Acquiring Control QueueLock lock %08lX EXCL %08lX\n",
1839                   &pDevExt->Specific.Library.IOQueueLock,
1840                   PsGetCurrentThread());
1841
1842     AFSAcquireExcl( &pDevExt->Specific.Library.IOQueueLock,
1843                     TRUE);
1844
1845     lCount = InterlockedIncrement( &pDevExt->Specific.Library.IOQueueItemCount);
1846
1847     AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
1848                   AFS_TRACE_LEVEL_VERBOSE,
1849                   "AFSInsertWorkitem Inserting IO work item %08lX Count %08lX\n",
1850                   WorkItem,
1851                   lCount);
1852
1853     if( pDevExt->Specific.Library.IOQueueTail != NULL) // queue already has nodes
1854     {
1855
1856         pDevExt->Specific.Library.IOQueueTail->next = WorkItem;
1857     }
1858     else // first node
1859     {
1860
1861         pDevExt->Specific.Library.IOQueueHead = WorkItem;
1862     }
1863
1864     WorkItem->next = NULL;
1865     pDevExt->Specific.Library.IOQueueTail = WorkItem;
1866
1867     // indicate that the queue has nodes
1868     KeSetEvent( &(pDevExt->Specific.Library.IOWorkerQueueHasItems),
1869                 0,
1870                 FALSE);
1871
1872     AFSReleaseResource( &pDevExt->Specific.Library.IOQueueLock);
1873
1874     return ntStatus;
1875 }
1876
1877 NTSTATUS
1878 AFSInsertWorkitemAtHead( IN AFSWorkItem *WorkItem)
1879 {
1880
1881     NTSTATUS ntStatus = STATUS_SUCCESS;
1882     AFSDeviceExt *pDevExt = NULL;
1883     LONG lCount;
1884
1885     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1886
1887     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1888                   AFS_TRACE_LEVEL_VERBOSE,
1889                   "AFSInsertWorkitemAtHead Acquiring Control QueueLock lock %08lX EXCL %08lX\n",
1890                   &pDevExt->Specific.Library.QueueLock,
1891                   PsGetCurrentThread());
1892
1893     AFSAcquireExcl( &pDevExt->Specific.Library.QueueLock,
1894                     TRUE);
1895
1896     WorkItem->next = pDevExt->Specific.Library.QueueHead;
1897
1898     pDevExt->Specific.Library.QueueHead = WorkItem;
1899
1900     lCount = InterlockedIncrement( &pDevExt->Specific.Library.QueueItemCount);
1901
1902     AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
1903                   AFS_TRACE_LEVEL_VERBOSE,
1904                   "AFSInsertWorkitemAtHead Inserting work item %08lX Count %08lX\n",
1905                   WorkItem,
1906                   lCount);
1907
1908     //
1909     // indicate that the queue has nodes
1910     //
1911
1912     KeSetEvent( &(pDevExt->Specific.Library.WorkerQueueHasItems),
1913                 0,
1914                 FALSE);
1915
1916     AFSReleaseResource( &pDevExt->Specific.Library.QueueLock);
1917
1918     return ntStatus;
1919 }
1920
1921 AFSWorkItem *
1922 AFSRemoveWorkItem()
1923 {
1924
1925     AFSWorkItem        *pWorkItem = NULL;
1926     AFSDeviceExt *pDevExt = NULL;
1927     LONG lCount;
1928
1929     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1930
1931     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1932                   AFS_TRACE_LEVEL_VERBOSE,
1933                   "AFSRemoveWorkItem Acquiring Control QueueLock lock %08lX EXCL %08lX\n",
1934                   &pDevExt->Specific.Library.QueueLock,
1935                   PsGetCurrentThread());
1936
1937     AFSAcquireExcl( &pDevExt->Specific.Library.QueueLock,
1938                     TRUE);
1939
1940     if( pDevExt->Specific.Library.QueueHead != NULL) // queue has nodes
1941     {
1942
1943         pWorkItem = pDevExt->Specific.Library.QueueHead;
1944
1945         lCount = InterlockedDecrement( &pDevExt->Specific.Library.QueueItemCount);
1946
1947         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
1948                       AFS_TRACE_LEVEL_VERBOSE,
1949                       "AFSRemoveWorkItem Removing work item %08lX Count %08lX Thread %08lX\n",
1950                       pWorkItem,
1951                       lCount,
1952                       PsGetCurrentThreadId());
1953
1954         pDevExt->Specific.Library.QueueHead = pDevExt->Specific.Library.QueueHead->next;
1955
1956         if( pDevExt->Specific.Library.QueueHead == NULL) // if queue just became empty
1957         {
1958
1959             pDevExt->Specific.Library.QueueTail = NULL;
1960         }
1961         else
1962         {
1963
1964             //
1965             // Wake up another worker
1966             //
1967
1968             KeSetEvent( &(pDevExt->Specific.Library.WorkerQueueHasItems),
1969                         0,
1970                         FALSE);
1971         }
1972     }
1973
1974     AFSReleaseResource( &pDevExt->Specific.Library.QueueLock);
1975
1976     return pWorkItem;
1977 }
1978
1979 AFSWorkItem *
1980 AFSRemoveIOWorkItem()
1981 {
1982
1983     AFSWorkItem        *pWorkItem = NULL;
1984     AFSDeviceExt *pDevExt = NULL;
1985     LONG lCount;
1986
1987     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1988
1989     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1990                   AFS_TRACE_LEVEL_VERBOSE,
1991                   "AFSRemoveIOWorkItem Acquiring Control QueueLock lock %08lX EXCL %08lX\n",
1992                   &pDevExt->Specific.Library.IOQueueLock,
1993                   PsGetCurrentThread());
1994
1995     AFSAcquireExcl( &pDevExt->Specific.Library.IOQueueLock,
1996                     TRUE);
1997
1998     if( pDevExt->Specific.Library.IOQueueHead != NULL) // queue has nodes
1999     {
2000
2001         pWorkItem = pDevExt->Specific.Library.IOQueueHead;
2002
2003         lCount = InterlockedDecrement( &pDevExt->Specific.Library.IOQueueItemCount);
2004
2005         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2006                       AFS_TRACE_LEVEL_VERBOSE,
2007                       "AFSRemoveWorkItem Removing work item %08lX Count %08lX Thread %08lX\n",
2008                       pWorkItem,
2009                       lCount,
2010                       PsGetCurrentThreadId());
2011
2012         pDevExt->Specific.Library.IOQueueHead = pDevExt->Specific.Library.IOQueueHead->next;
2013
2014         if( pDevExt->Specific.Library.IOQueueHead == NULL) // if queue just became empty
2015         {
2016
2017             pDevExt->Specific.Library.IOQueueTail = NULL;
2018         }
2019         else
2020         {
2021
2022             //
2023             // Wake up another worker
2024             //
2025
2026             KeSetEvent( &(pDevExt->Specific.Library.IOWorkerQueueHasItems),
2027                         0,
2028                         FALSE);
2029         }
2030     }
2031
2032     AFSReleaseResource( &pDevExt->Specific.Library.IOQueueLock);
2033
2034     return pWorkItem;
2035 }
2036
2037 NTSTATUS
2038 AFSQueueWorkerRequest( IN AFSWorkItem *WorkItem)
2039 {
2040
2041     NTSTATUS ntStatus = STATUS_SUCCESS;
2042     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
2043
2044     //
2045     // Submit the work item to the worker
2046     //
2047
2048     ntStatus = AFSInsertWorkitem( WorkItem);
2049
2050     if( bWait)
2051     {
2052
2053         //
2054         // Sync request so block on the work item event
2055         //
2056
2057         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2058                                           Executive,
2059                                           KernelMode,
2060                                           FALSE,
2061                                           NULL);
2062     }
2063
2064     return ntStatus;
2065 }
2066
2067 NTSTATUS
2068 AFSQueueIOWorkerRequest( IN AFSWorkItem *WorkItem)
2069 {
2070
2071     NTSTATUS ntStatus = STATUS_SUCCESS;
2072     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
2073
2074     //
2075     // Submit the work item to the worker
2076     //
2077
2078     ntStatus = AFSInsertIOWorkitem( WorkItem);
2079
2080     if( bWait)
2081     {
2082
2083         //
2084         // Sync request so block on the work item event
2085         //
2086
2087         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2088                                           Executive,
2089                                           KernelMode,
2090                                           FALSE,
2091                                           NULL);
2092     }
2093
2094     return ntStatus;
2095 }
2096
2097 NTSTATUS
2098 AFSQueueWorkerRequestAtHead( IN AFSWorkItem *WorkItem)
2099 {
2100
2101     NTSTATUS ntStatus = STATUS_SUCCESS;
2102     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
2103
2104     //
2105     // Submit the work item to the worker
2106     //
2107
2108     ntStatus = AFSInsertWorkitemAtHead( WorkItem);
2109
2110     if( bWait)
2111     {
2112
2113         //
2114         // Sync request so block on the work item event
2115         //
2116
2117         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2118                                           Executive,
2119                                           KernelMode,
2120                                           FALSE,
2121                                           NULL);
2122     }
2123
2124     return ntStatus;
2125 }
2126
2127 NTSTATUS
2128 AFSQueueFlushExtents( IN AFSFcb *Fcb,
2129                       IN GUID *AuthGroup)
2130 {
2131
2132     NTSTATUS ntStatus = STATUS_SUCCESS;
2133     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
2134     AFSWorkItem *pWorkItem = NULL;
2135     LONG lCount;
2136
2137     __try
2138     {
2139
2140         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2141                       AFS_TRACE_LEVEL_VERBOSE,
2142                       "AFSQueueFlushExtents Queuing request for FID %08lX-%08lX-%08lX-%08lX\n",
2143                       Fcb->ObjectInformation->FileId.Cell,
2144                       Fcb->ObjectInformation->FileId.Volume,
2145                       Fcb->ObjectInformation->FileId.Vnode,
2146                       Fcb->ObjectInformation->FileId.Unique);
2147
2148         //
2149         // Increment our flush count here just to keep the number of items in the
2150         // queue down. We'll decrement it just below.
2151         //
2152
2153         lCount = InterlockedIncrement( &Fcb->Specific.File.QueuedFlushCount);
2154
2155         if( lCount > 3)
2156         {
2157
2158             AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2159                           AFS_TRACE_LEVEL_VERBOSE,
2160                           "AFSQueueFlushExtents Max queued items for FID %08lX-%08lX-%08lX-%08lX\n",
2161                           Fcb->ObjectInformation->FileId.Cell,
2162                           Fcb->ObjectInformation->FileId.Volume,
2163                           Fcb->ObjectInformation->FileId.Vnode,
2164                           Fcb->ObjectInformation->FileId.Unique);
2165
2166             try_return( ntStatus);
2167         }
2168
2169         if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
2170         {
2171
2172             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2173                           AFS_TRACE_LEVEL_ERROR,
2174                           "AFSQueueFlushExtents Failing request, in shutdown\n");
2175
2176             try_return( ntStatus = STATUS_TOO_LATE);
2177         }
2178
2179         //
2180         // Allocate our request structure and send it to the worker
2181         //
2182
2183         pWorkItem = (AFSWorkItem *)AFSLibExAllocatePoolWithTag( NonPagedPool,
2184                                                                 sizeof( AFSWorkItem),
2185                                                                 AFS_WORK_ITEM_TAG);
2186
2187         if( pWorkItem == NULL)
2188         {
2189
2190             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2191                           AFS_TRACE_LEVEL_ERROR,
2192                           "AFSQueueFlushExtents Failed to allocate work item\n");
2193
2194             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2195         }
2196
2197         RtlZeroMemory( pWorkItem,
2198                        sizeof( AFSWorkItem));
2199
2200         pWorkItem->Size = sizeof( AFSWorkItem);
2201
2202         pWorkItem->ProcessID = (ULONGLONG)PsGetCurrentProcessId();
2203
2204         pWorkItem->RequestType = AFS_WORK_FLUSH_FCB;
2205
2206         if ( AuthGroup == NULL)
2207         {
2208
2209             RtlZeroMemory( &pWorkItem->AuthGroup,
2210                            sizeof( GUID));
2211
2212             ntStatus = AFSRetrieveValidAuthGroup( Fcb,
2213                                                   NULL,
2214                                                   TRUE,
2215                                                   &pWorkItem->AuthGroup);
2216         }
2217         else
2218         {
2219             RtlCopyMemory( &pWorkItem->AuthGroup,
2220                            AuthGroup,
2221                            sizeof( GUID));
2222         }
2223
2224         pWorkItem->Specific.Fcb.Fcb = Fcb;
2225
2226         lCount = InterlockedIncrement( &Fcb->OpenReferenceCount);
2227
2228         AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
2229                       AFS_TRACE_LEVEL_VERBOSE,
2230                       "AFSQueueFlushExtents Increment count on Fcb %08lX Cnt %d\n",
2231                       Fcb,
2232                       lCount);
2233
2234         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2235                       AFS_TRACE_LEVEL_VERBOSE,
2236                       "AFSQueueFlushExtents Workitem %08lX for FID %08lX-%08lX-%08lX-%08lX\n",
2237                       pWorkItem,
2238                       Fcb->ObjectInformation->FileId.Cell,
2239                       Fcb->ObjectInformation->FileId.Volume,
2240                       Fcb->ObjectInformation->FileId.Vnode,
2241                       Fcb->ObjectInformation->FileId.Unique);
2242
2243         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2244
2245 try_exit:
2246
2247         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2248                       AFS_TRACE_LEVEL_VERBOSE,
2249                       "AFSQueueFlushExtents Request complete Status %08lX FID %08lX-%08lX-%08lX-%08lX\n",
2250                       Fcb->ObjectInformation->FileId.Cell,
2251                       Fcb->ObjectInformation->FileId.Volume,
2252                       Fcb->ObjectInformation->FileId.Vnode,
2253                       Fcb->ObjectInformation->FileId.Unique,
2254                       ntStatus);
2255
2256         //
2257         // Remove the count we added above
2258         //
2259
2260         lCount = InterlockedDecrement( &Fcb->Specific.File.QueuedFlushCount);
2261
2262         ASSERT( lCount >= 0);
2263
2264         if( lCount == 0)
2265         {
2266
2267             KeSetEvent( &Fcb->NPFcb->Specific.File.QueuedFlushEvent,
2268                         0,
2269                         FALSE);
2270         }
2271
2272         if( !NT_SUCCESS( ntStatus))
2273         {
2274
2275             if( pWorkItem != NULL)
2276             {
2277
2278                 lCount = InterlockedDecrement( &Fcb->OpenReferenceCount);
2279
2280                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2281             }
2282
2283             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2284                           AFS_TRACE_LEVEL_ERROR,
2285                           "AFSQueueFlushExtents Failed to queue request Status %08lX\n", ntStatus);
2286         }
2287     }
2288     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2289     {
2290
2291         AFSDbgLogMsg( 0,
2292                       0,
2293                       "EXCEPTION - AFSQueueFlushExtents\n");
2294
2295         AFSDumpTraceFilesFnc();
2296     }
2297
2298     return ntStatus;
2299 }
2300
2301 NTSTATUS
2302 AFSQueueGlobalRootEnumeration()
2303 {
2304
2305     NTSTATUS ntStatus = STATUS_SUCCESS;
2306     AFSWorkItem *pWorkItem = NULL;
2307
2308     __try
2309     {
2310
2311         pWorkItem = (AFSWorkItem *) AFSLibExAllocatePoolWithTag( NonPagedPool,
2312                                                                  sizeof(AFSWorkItem),
2313                                                                  AFS_WORK_ITEM_TAG);
2314         if (NULL == pWorkItem)
2315         {
2316
2317             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2318                           AFS_TRACE_LEVEL_ERROR,
2319                           "AFSQueueGlobalRootEnumeration Failed to allocate work item\n");
2320
2321             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2322         }
2323
2324         RtlZeroMemory( pWorkItem,
2325                        sizeof(AFSWorkItem));
2326
2327         pWorkItem->Size = sizeof( AFSWorkItem);
2328
2329         pWorkItem->RequestType = AFS_WORK_ENUMERATE_GLOBAL_ROOT;
2330
2331         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2332                       AFS_TRACE_LEVEL_VERBOSE,
2333                       "AFSQueueGlobalRootEnumeration Workitem %08lX\n",
2334                       pWorkItem);
2335
2336         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2337
2338 try_exit:
2339
2340         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2341                       AFS_TRACE_LEVEL_VERBOSE,
2342                       "AFSQueueGlobalRootEnumeration Request complete Status %08lX\n",
2343                       ntStatus);
2344
2345         if( !NT_SUCCESS( ntStatus))
2346         {
2347
2348             if( pWorkItem != NULL)
2349             {
2350
2351                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2352             }
2353
2354             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2355                           AFS_TRACE_LEVEL_ERROR,
2356                           "AFSQueueGlobalRootEnumeration Failed to queue request Status %08lX\n",
2357                           ntStatus);
2358         }
2359     }
2360     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2361     {
2362
2363         AFSDbgLogMsg( 0,
2364                       0,
2365                       "EXCEPTION - AFSQueueGlobalRootEnumeration\n");
2366
2367         AFSDumpTraceFilesFnc();
2368     }
2369
2370     return ntStatus;
2371 }
2372
2373 NTSTATUS
2374 AFSQueueStartIos( IN PFILE_OBJECT CacheFileObject,
2375                   IN UCHAR FunctionCode,
2376                   IN ULONG RequestFlags,
2377                   IN AFSIoRun *IoRuns,
2378                   IN ULONG RunCount,
2379                   IN AFSGatherIo *GatherIo)
2380 {
2381
2382     NTSTATUS ntStatus = STATUS_SUCCESS;
2383     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
2384     AFSWorkItem *pWorkItem = NULL;
2385
2386     __try
2387     {
2388
2389         if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
2390         {
2391
2392             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2393                           AFS_TRACE_LEVEL_ERROR,
2394                           "AFSQueueStartIos Failing request, in shutdown\n");
2395
2396             try_return( ntStatus = STATUS_TOO_LATE);
2397         }
2398
2399         //
2400         // Allocate our request structure and send it to the worker
2401         //
2402
2403         pWorkItem = (AFSWorkItem *)AFSLibExAllocatePoolWithTag( NonPagedPool,
2404                                                                 sizeof( AFSWorkItem),
2405                                                                 AFS_WORK_ITEM_TAG);
2406
2407         if( pWorkItem == NULL)
2408         {
2409
2410             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2411                           AFS_TRACE_LEVEL_ERROR,
2412                           "AFSQueueStartIos Failed to allocate work item\n");
2413
2414             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2415         }
2416
2417         RtlZeroMemory( pWorkItem,
2418                        sizeof( AFSWorkItem));
2419
2420         KeInitializeEvent( &pWorkItem->Event,
2421                            NotificationEvent,
2422                            FALSE);
2423
2424         pWorkItem->Size = sizeof( AFSWorkItem);
2425
2426         pWorkItem->ProcessID = (ULONGLONG)PsGetCurrentProcessId();
2427
2428         pWorkItem->RequestType = AFS_WORK_START_IOS;
2429
2430         pWorkItem->Specific.CacheAccess.CacheFileObject = CacheFileObject;
2431
2432         pWorkItem->Specific.CacheAccess.FunctionCode = FunctionCode;
2433
2434         pWorkItem->Specific.CacheAccess.RequestFlags = RequestFlags;
2435
2436         pWorkItem->Specific.CacheAccess.IoRuns = IoRuns;
2437
2438         pWorkItem->Specific.CacheAccess.RunCount = RunCount;
2439
2440         pWorkItem->Specific.CacheAccess.GatherIo = GatherIo;
2441
2442         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2443                       AFS_TRACE_LEVEL_VERBOSE,
2444                       "AFSQueueStartIos Queuing IO Workitem %08lX\n",
2445                       pWorkItem);
2446
2447         ntStatus = AFSQueueIOWorkerRequest( pWorkItem);
2448
2449 try_exit:
2450
2451         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2452                       AFS_TRACE_LEVEL_VERBOSE,
2453                       "AFSQueueStartIos Request complete Status %08lX\n",
2454                       ntStatus);
2455
2456         if( !NT_SUCCESS( ntStatus))
2457         {
2458
2459             if( pWorkItem != NULL)
2460             {
2461
2462                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2463             }
2464         }
2465     }
2466     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2467     {
2468
2469         AFSDbgLogMsg( 0,
2470                       0,
2471                       "EXCEPTION - AFSQueueStartIos\n");
2472
2473         AFSDumpTraceFilesFnc();
2474     }
2475
2476     return ntStatus;
2477 }
2478
2479 NTSTATUS
2480 AFSQueueInvalidateObject( IN AFSObjectInfoCB *ObjectInfo,
2481                           IN ULONG InvalidateReason)
2482 {
2483
2484     NTSTATUS ntStatus = STATUS_SUCCESS;
2485     AFSWorkItem *pWorkItem = NULL;
2486
2487     __try
2488     {
2489
2490         pWorkItem = (AFSWorkItem *) AFSLibExAllocatePoolWithTag( NonPagedPool,
2491                                                                  sizeof(AFSWorkItem),
2492                                                                  AFS_WORK_ITEM_TAG);
2493         if (NULL == pWorkItem)
2494         {
2495
2496             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2497                           AFS_TRACE_LEVEL_ERROR,
2498                           "AFSQueueInvalidateObject Failed to allocate work item\n");
2499
2500             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2501         }
2502
2503         RtlZeroMemory( pWorkItem,
2504                        sizeof(AFSWorkItem));
2505
2506         pWorkItem->Size = sizeof( AFSWorkItem);
2507
2508         pWorkItem->RequestType = AFS_WORK_INVALIDATE_OBJECT;
2509
2510         pWorkItem->Specific.Invalidate.ObjectInfo = ObjectInfo;
2511
2512         pWorkItem->Specific.Invalidate.InvalidateReason = InvalidateReason;
2513
2514         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2515                       AFS_TRACE_LEVEL_VERBOSE,
2516                       "AFSQueueInvalidateObject Workitem %08lX\n",
2517                       pWorkItem);
2518
2519         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2520
2521 try_exit:
2522
2523         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2524                       AFS_TRACE_LEVEL_VERBOSE,
2525                       "AFSQueueInvalidateObject Request complete Status %08lX\n",
2526                       ntStatus);
2527
2528         if( !NT_SUCCESS( ntStatus))
2529         {
2530
2531             if( pWorkItem != NULL)
2532             {
2533                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2534             }
2535
2536             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2537                           AFS_TRACE_LEVEL_ERROR,
2538                           "AFSQueueInvalidateObject Failed to queue request Status %08lX\n",
2539                           ntStatus);
2540         }
2541     }
2542     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2543     {
2544
2545         AFSDbgLogMsg( 0,
2546                       0,
2547                       "EXCEPTION - AFSQueueInvalidateObject\n");
2548
2549         AFSDumpTraceFilesFnc();
2550     }
2551
2552     return ntStatus;
2553 }