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