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