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