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