869e1456c7f037c066bd2e5a0df459d81b2d13d5
[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                                                         FALSE);
744                         }
745
746                         ASSERT( pWorkItem->Specific.Fcb.Fcb->OpenReferenceCount != 0);
747
748                         lCount = InterlockedDecrement( &pWorkItem->Specific.Fcb.Fcb->OpenReferenceCount);
749
750                         break;
751                     }
752
753                     case AFS_WORK_ENUMERATE_GLOBAL_ROOT:
754                     {
755
756                         AFSEnumerateGlobalRoot( NULL);
757
758                         break;
759                     }
760
761                     case AFS_WORK_INVALIDATE_OBJECT:
762                     {
763
764                         AFSPerformObjectInvalidate( pWorkItem->Specific.Invalidate.ObjectInfo,
765                                                     pWorkItem->Specific.Invalidate.InvalidateReason);
766
767                         freeWorkItem = TRUE;
768
769                         break;
770                     }
771
772                     case AFS_WORK_START_IOS:
773                     {
774
775                         freeWorkItem = TRUE;
776
777                         break;
778                     }
779
780                     default:
781
782                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
783                                       AFS_TRACE_LEVEL_ERROR,
784                                       "AFSWorkerThread Unknown request type %d\n", pWorkItem->RequestType);
785
786                         break;
787                 }
788
789                 if( freeWorkItem)
790                 {
791
792                     ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
793                 }
794
795                 ntStatus = STATUS_SUCCESS;
796             }
797         }
798     } // worker thread loop
799
800     ClearFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
801
802     // Wake up another worker so they too can exit
803
804     KeSetEvent( &pLibraryDevExt->Specific.Library.WorkerQueueHasItems,
805                 0,
806                 FALSE);
807
808     PsTerminateSystemThread( 0);
809
810     return;
811 }
812
813 void
814 AFSIOWorkerThread( IN PVOID Context)
815 {
816
817     NTSTATUS ntStatus = STATUS_SUCCESS;
818     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)Context;
819     AFSWorkItem *pWorkItem;
820     BOOLEAN freeWorkItem = TRUE;
821     AFSDeviceExt *pLibraryDevExt = NULL, *pRdrDevExt = NULL;
822
823     pLibraryDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
824
825     //
826     // Indicate that we are initialized and ready
827     //
828
829     KeSetEvent( &pPoolContext->WorkerThreadReady,
830                 0,
831                 FALSE);
832
833
834     //
835     // Indicate we are initialized
836     //
837
838     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
839
840     ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.IOWorkerQueueHasItems,
841                                       Executive,
842                                       KernelMode,
843                                       FALSE,
844                                       NULL);
845
846     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
847     {
848
849         if( !NT_SUCCESS( ntStatus))
850         {
851
852             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
853                           AFS_TRACE_LEVEL_ERROR,
854                           "AFSIOWorkerThread Wait for queue items failed Status %08lX\n", ntStatus);
855
856             ntStatus = STATUS_SUCCESS;
857         }
858         else
859         {
860
861             pWorkItem = AFSRemoveIOWorkItem();
862
863             if( pWorkItem == NULL)
864             {
865
866                 ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.IOWorkerQueueHasItems,
867                                                   Executive,
868                                                   KernelMode,
869                                                   FALSE,
870                                                   NULL);
871             }
872             else
873             {
874
875                 freeWorkItem = TRUE;
876
877                 //
878                 // Switch on the type of work item to process
879                 //
880
881                 switch( pWorkItem->RequestType)
882                 {
883
884                     case AFS_WORK_START_IOS:
885                     {
886
887                         pRdrDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
888
889                         //
890                         // The final status is in the gather io
891                         //
892
893                         ntStatus = AFSStartIos( pWorkItem->Specific.CacheAccess.CacheFileObject,
894                                                 pWorkItem->Specific.CacheAccess.FunctionCode,
895                                                 pWorkItem->Specific.CacheAccess.RequestFlags,
896                                                 pWorkItem->Specific.CacheAccess.IoRuns,
897                                                 pWorkItem->Specific.CacheAccess.RunCount,
898                                                 pWorkItem->Specific.CacheAccess.GatherIo);
899
900                         //
901                         // Regardless of the status we we do the complete - there may
902                         // be IOs in flight
903                         // Decrement the count - setting the event if we were told
904                         // to. This may trigger completion.
905                         //
906
907                         AFSCompleteIo( pWorkItem->Specific.CacheAccess.GatherIo, ntStatus );
908
909                         freeWorkItem = TRUE;
910
911                         break;
912                     }
913
914                     default:
915
916                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
917                                       AFS_TRACE_LEVEL_ERROR,
918                                       "AFSWorkerThread Unknown request type %d\n", pWorkItem->RequestType);
919
920                         break;
921                 }
922
923                 if( freeWorkItem)
924                 {
925
926                     ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
927                 }
928
929                 ntStatus = STATUS_SUCCESS;
930             }
931         }
932     } // worker thread loop
933
934     ClearFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
935
936     // Wake up another IOWorker so they too can exit
937
938     KeSetEvent( &pLibraryDevExt->Specific.Library.IOWorkerQueueHasItems,
939                 0,
940                 FALSE);
941
942     PsTerminateSystemThread( 0);
943
944     return;
945 }
946
947 void
948 AFSPrimaryVolumeWorkerThread( IN PVOID Context)
949 {
950
951     NTSTATUS ntStatus = STATUS_SUCCESS;
952     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)&AFSGlobalRoot->VolumeWorkerContext;
953     AFSDeviceExt *pControlDeviceExt = NULL;
954     AFSDeviceExt *pRDRDeviceExt = NULL;
955     LARGE_INTEGER DueTime;
956     LONG TimeOut;
957     KTIMER Timer;
958     BOOLEAN bFoundOpenEntry = FALSE;
959     AFSObjectInfoCB *pCurrentObject = NULL, *pNextObject = NULL, *pCurrentChildObject = NULL;
960     AFSDirectoryCB *pCurrentDirEntry = NULL, *pNextDirEntry = NULL;
961     BOOLEAN bReleaseVolumeLock = FALSE;
962     AFSVolumeCB *pVolumeCB = NULL, *pNextVolume = NULL;
963     AFSFcb *pFcb = NULL;
964     LONG lFileType;
965     LARGE_INTEGER liCurrentTime;
966     BOOLEAN bVolumeObject = FALSE;
967     LONG lCount;
968
969     pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
970
971     pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
972
973     AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
974                   AFS_TRACE_LEVEL_VERBOSE,
975                   "AFSPrimaryVolumeWorkerThread Initialized\n");
976
977     //
978     // Initialize the timer for the worker thread
979     //
980
981     DueTime.QuadPart = -(5000);
982
983     TimeOut = 5000;
984
985     KeInitializeTimerEx( &Timer,
986                          SynchronizationTimer);
987
988     KeSetTimerEx( &Timer,
989                   DueTime,
990                   TimeOut,
991                   NULL);
992
993     //
994     // Indicate that we are initialized and ready
995     //
996
997     KeSetEvent( &pPoolContext->WorkerThreadReady,
998                 0,
999                 FALSE);
1000
1001     //
1002     // Indicate we are initialized
1003     //
1004
1005     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
1006
1007     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
1008     {
1009
1010         KeWaitForSingleObject( &Timer,
1011                                Executive,
1012                                KernelMode,
1013                                FALSE,
1014                                NULL);
1015
1016         //
1017         // This is the primary volume worker so it will traverse the volume list
1018         // looking for cleanup or volumes requiring private workers
1019         //
1020
1021         AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1022                           TRUE);
1023
1024         pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead;
1025
1026         while( pVolumeCB != NULL)
1027         {
1028
1029             if( pVolumeCB == AFSGlobalRoot ||
1030                 !AFSAcquireExcl( pVolumeCB->VolumeLock,
1031                                  FALSE))
1032             {
1033
1034                 pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1035
1036                 continue;
1037             }
1038
1039             if( pVolumeCB->ObjectInfoListHead == NULL)
1040             {
1041
1042                 AFSReleaseResource( pVolumeCB->VolumeLock);
1043
1044                 AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1045
1046                 AFSAcquireExcl( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock,
1047                                 TRUE);
1048
1049                 AFSAcquireExcl( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1050                                 TRUE);
1051
1052                 if( !AFSAcquireExcl( pVolumeCB->VolumeLock,
1053                                      FALSE))
1054                 {
1055
1056                     AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1057
1058                     AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
1059
1060                     pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1061
1062                     continue;
1063                 }
1064
1065                 KeQueryTickCount( &liCurrentTime);
1066
1067                 pNextVolume = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1068
1069                 if( pVolumeCB->ObjectInfoListHead == NULL &&
1070                     pVolumeCB->DirectoryCB->OpenReferenceCount == 0 &&
1071                     pVolumeCB->VolumeReferenceCount == 1 &&
1072                     ( pVolumeCB->RootFcb == NULL ||
1073                       pVolumeCB->RootFcb->OpenReferenceCount == 0) &&
1074                     pVolumeCB->ObjectInformation.ObjectReferenceCount <= 0)
1075                 {
1076
1077                     if( pVolumeCB->RootFcb != NULL)
1078                     {
1079
1080                         AFSRemoveRootFcb( pVolumeCB->RootFcb);
1081                     }
1082
1083                     AFSRemoveVolume( pVolumeCB);
1084                 }
1085                 else
1086                 {
1087
1088                     AFSReleaseResource( pVolumeCB->VolumeLock);
1089                 }
1090
1091                 AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1092
1093                 AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
1094
1095                 pVolumeCB = pNextVolume;
1096
1097                 continue;
1098             }
1099
1100             //
1101             // Don't need this lock anymore now that we have a volume cb to work with
1102             //
1103
1104             AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1105
1106             //
1107             // For now we only need the volume lock shared
1108             //
1109
1110             AFSConvertToShared( pVolumeCB->VolumeLock);
1111
1112             if( AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1113                                   FALSE))
1114             {
1115
1116                 pCurrentObject = pVolumeCB->ObjectInfoListHead;
1117
1118                 pNextObject = NULL;
1119
1120                 bReleaseVolumeLock = TRUE;
1121
1122                 while( pCurrentObject != NULL)
1123                 {
1124
1125                     if( pCurrentObject != &pVolumeCB->ObjectInformation)
1126                     {
1127
1128                         pNextObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1129
1130                         if( pNextObject == NULL &&
1131                             pVolumeCB != AFSGlobalRoot)  // Don't free up the root of the global
1132                         {
1133
1134                             pNextObject = &pVolumeCB->ObjectInformation;
1135                         }
1136
1137                         bVolumeObject = FALSE;
1138                     }
1139                     else
1140                     {
1141
1142                         pNextObject = NULL;
1143
1144                         bVolumeObject = TRUE;
1145                     }
1146
1147                     if( pCurrentObject->FileType == AFS_FILE_TYPE_DIRECTORY &&
1148                         !BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))  // If we are in shutdown mode skip directories
1149                     {
1150
1151                         //
1152                         // If this object is deleted then remove it from the parent, if we can
1153                         //
1154
1155                         if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DELETED) &&
1156                             pCurrentObject->ObjectReferenceCount <= 0 &&
1157                             ( pCurrentObject->Fcb == NULL ||
1158                               pCurrentObject->Fcb->OpenReferenceCount == 0) &&
1159                             pCurrentObject->Specific.Directory.DirectoryNodeListHead == NULL &&
1160                             pCurrentObject->Specific.Directory.ChildOpenReferenceCount == 0)
1161                         {
1162
1163                             AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1164
1165                             //
1166                             // Dropping the TreeLock permits the
1167                             // pCurrentObject->ObjectReferenceCount to change
1168                             //
1169
1170                             if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1171                                                 FALSE))
1172                             {
1173
1174                                 if ( pCurrentObject->ObjectReferenceCount <= 0 &&
1175                                      ( pCurrentObject->Fcb == NULL ||
1176                                        pCurrentObject->Fcb->OpenReferenceCount == 0 &&
1177                                        pCurrentObject->Fcb->Specific.File.ExtentCount == 0))
1178                                 {
1179
1180                                     AFSRemoveFcb( &pCurrentObject->Fcb);
1181
1182                                     if( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
1183                                     {
1184
1185                                         AFSRemoveFcb( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
1186
1187                                         AFSDeleteObjectInfo( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
1188
1189                                         ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
1190
1191                                         AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
1192
1193                                         AFSExFreePoolWithTag( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
1194                                     }
1195
1196                                     AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1197                                                   AFS_TRACE_LEVEL_VERBOSE,
1198                                                   "AFSPrimaryVolumeWorkerThread Deleting deleted object %08lX\n",
1199                                                   pCurrentObject);
1200
1201                                     AFSDeleteObjectInfo( pCurrentObject);
1202                                 }
1203
1204                                 AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1205
1206                                 pCurrentObject = pNextObject;
1207
1208                                 continue;
1209                             }
1210                             else
1211                             {
1212
1213                                 bReleaseVolumeLock = FALSE;
1214
1215                                 break;
1216                             }
1217                         }
1218
1219                         if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0 ||
1220                             ( pCurrentObject->Fcb != NULL &&
1221                               pCurrentObject->Fcb->OpenReferenceCount > 0) ||
1222                             pCurrentObject->Specific.Directory.DirectoryNodeListHead == NULL)
1223                         {
1224
1225                             pCurrentObject = pNextObject;
1226
1227                             continue;
1228                         }
1229
1230                         if( !AFSAcquireShared( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
1231                                                FALSE))
1232                         {
1233
1234                             pCurrentObject = pNextObject;
1235
1236                             continue;
1237                         }
1238
1239                         KeQueryTickCount( &liCurrentTime);
1240
1241                         pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
1242
1243                         while( pCurrentDirEntry != NULL)
1244                         {
1245
1246                             if( pCurrentDirEntry->OpenReferenceCount > 0 ||
1247                                 ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1248                                   pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0) ||
1249                                 liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart ||
1250                                 liCurrentTime.QuadPart - pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart <
1251                                                                         pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart ||
1252                                 ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY &&
1253                                    ( pCurrentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL ||
1254                                      pCurrentDirEntry->ObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)) ||
1255                                 ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE &&
1256                                   pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1257                                   pCurrentDirEntry->ObjectInformation->Fcb->Specific.File.ExtentsDirtyCount > 0))
1258                             {
1259
1260                                 break;
1261                             }
1262
1263                             pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
1264                         }
1265
1266                         if( pCurrentDirEntry != NULL)
1267                         {
1268
1269                             AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1270
1271                             pCurrentObject = pNextObject;
1272
1273                             continue;
1274                         }
1275
1276                         AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1277
1278                         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1279
1280                         //
1281                         // Now acquire the locks excl
1282                         //
1283
1284                         if( AFSAcquireExcl( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
1285                                             FALSE))
1286                         {
1287
1288                             if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1289                                                 FALSE))
1290                             {
1291
1292                                 if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0)
1293                                 {
1294
1295                                     AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1296
1297                                     AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1298
1299                                     pCurrentObject = pNextObject;
1300
1301                                     continue;
1302                                 }
1303
1304                                 KeQueryTickCount( &liCurrentTime);
1305
1306                                 pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
1307
1308                                 while( pCurrentDirEntry != NULL)
1309                                 {
1310
1311                                     if( pCurrentDirEntry->OpenReferenceCount > 0 ||
1312                                         ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1313                                           pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0) ||
1314                                         liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart ||
1315                                         liCurrentTime.QuadPart - pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart <
1316                                                                                 pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart ||
1317                                         ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY &&
1318                                           ( pCurrentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL ||
1319                                             pCurrentDirEntry->ObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)) ||
1320                                         ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE &&
1321                                           pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1322                                           pCurrentDirEntry->ObjectInformation->Fcb->Specific.File.ExtentsDirtyCount > 0))
1323                                     {
1324
1325                                         break;
1326                                     }
1327
1328                                     pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
1329                                 }
1330
1331                                 if( pCurrentDirEntry != NULL)
1332                                 {
1333
1334                                     AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1335
1336                                     AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1337
1338                                     pCurrentObject = pNextObject;
1339
1340                                     continue;
1341                                 }
1342
1343                                 pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
1344
1345                                 while( pCurrentDirEntry != NULL)
1346                                 {
1347
1348                                     pNextDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
1349
1350                                     pCurrentChildObject = pCurrentDirEntry->ObjectInformation;
1351
1352                                     pFcb = NULL;
1353
1354                                     AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1355                                                   AFS_TRACE_LEVEL_VERBOSE,
1356                                                   "AFSPrimaryVolumeWorkerThread Deleting DE %wZ Object %08lX\n",
1357                                                   &pCurrentDirEntry->NameInformation.FileName,
1358                                                   pCurrentChildObject);
1359
1360                                     AFSDeleteDirEntry( pCurrentObject,
1361                                                        pCurrentDirEntry);
1362
1363                                     if( pCurrentChildObject->ObjectReferenceCount <= 0 &&
1364                                         pCurrentChildObject->Fcb != NULL &&
1365                                         pCurrentChildObject->FileType == AFS_FILE_TYPE_FILE)
1366                                     {
1367
1368                                         //
1369                                         // We must not hold pVolumeCB->ObjectInfoTree.TreeLock exclusive
1370                                         // across an AFSCleanupFcb call since it can deadlock with an
1371                                         // invalidation call from the service.
1372                                         //
1373
1374                                         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1375
1376                                         //
1377                                         // Dropping the TreeLock permits the
1378                                         // pCurrentObject->ObjectReferenceCount to change
1379                                         //
1380
1381                                         AFSCleanupFcb( pCurrentChildObject->Fcb,
1382                                                        TRUE);
1383
1384                                         AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1385                                                         TRUE);
1386                                     }
1387
1388                                     if( pCurrentChildObject->ObjectReferenceCount <= 0 &&
1389                                         ( pCurrentChildObject->Fcb == NULL ||
1390                                           pCurrentChildObject->Fcb->OpenReferenceCount == 0 &&
1391                                           pCurrentChildObject->Fcb->Specific.File.ExtentCount == 0))
1392                                     {
1393
1394                                         AFSRemoveFcb( &pCurrentChildObject->Fcb);
1395
1396                                         if( pCurrentChildObject->FileType == AFS_FILE_TYPE_DIRECTORY &&
1397                                             pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
1398                                         {
1399
1400                                             AFSRemoveFcb( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
1401
1402                                             AFSDeleteObjectInfo( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
1403
1404                                             ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
1405
1406                                             AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
1407
1408                                             AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
1409                                         }
1410
1411                                         AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1412                                                       AFS_TRACE_LEVEL_VERBOSE,
1413                                                       "AFSPrimaryVolumeWorkerThread Deleting object %08lX\n",
1414                                                       pCurrentChildObject);
1415
1416                                         AFSDeleteObjectInfo( pCurrentChildObject);
1417                                     }
1418
1419                                     pCurrentDirEntry = pNextDirEntry;
1420
1421                                 }
1422
1423                                 pCurrentObject->Specific.Directory.DirectoryNodeListHead = NULL;
1424
1425                                 pCurrentObject->Specific.Directory.DirectoryNodeListTail = NULL;
1426
1427                                 pCurrentObject->Specific.Directory.ShortNameTree = NULL;
1428
1429                                 pCurrentObject->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead = NULL;
1430
1431                                 pCurrentObject->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead = NULL;
1432
1433                                 pCurrentObject->Specific.Directory.DirectoryNodeCount = 0;
1434
1435                                 AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NODE_COUNT,
1436                                               AFS_TRACE_LEVEL_VERBOSE,
1437                                               "AFSPrimaryVolumeWorkerThread Reset count to 0 on parent FID %08lX-%08lX-%08lX-%08lX\n",
1438                                               pCurrentObject->FileId.Cell,
1439                                               pCurrentObject->FileId.Volume,
1440                                               pCurrentObject->FileId.Vnode,
1441                                               pCurrentObject->FileId.Unique);
1442
1443                                 //
1444                                 // Clear our enumerated flag on this object so we retrieve info again on next access
1445                                 //
1446
1447                                 ClearFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED);
1448
1449                                 AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1450
1451                                 AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1452                             }
1453                             else
1454                             {
1455
1456                                 AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1457
1458                                 bReleaseVolumeLock = FALSE;
1459
1460                                 break;
1461                             }
1462                         }
1463                         else
1464                         {
1465
1466                             //
1467                             // Try to grab the volume lock again ... no problem if we don't
1468                             //
1469
1470                             if( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1471                                                  FALSE))
1472                             {
1473
1474                                 bReleaseVolumeLock = FALSE;
1475
1476                                 break;
1477                             }
1478                         }
1479
1480                         if( pCurrentObject != &pVolumeCB->ObjectInformation)
1481                         {
1482
1483                             pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1484
1485                             if( pCurrentObject == NULL &&
1486                                 pVolumeCB != AFSGlobalRoot)
1487                             {
1488
1489                                 pCurrentObject = &pVolumeCB->ObjectInformation;
1490                             }
1491                         }
1492                         else
1493                         {
1494
1495                             pCurrentObject = NULL;
1496                         }
1497
1498                         continue;
1499                     }
1500                     else if( pCurrentObject->FileType == AFS_FILE_TYPE_FILE)
1501                     {
1502
1503                         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1504
1505                         if( pCurrentObject->Fcb != NULL)
1506                         {
1507
1508                             //
1509                             // Dropping the TreeLock permits the
1510                             // pCurrentObject->ObjectReferenceCount to change
1511                             //
1512
1513                             AFSCleanupFcb( pCurrentObject->Fcb,
1514                                            TRUE);
1515                         }
1516
1517                         if( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1518                                              FALSE))
1519                         {
1520
1521                             bReleaseVolumeLock = FALSE;
1522
1523                             break;
1524                         }
1525
1526                         if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DELETED) &&
1527                             pCurrentObject->ObjectReferenceCount <= 0 &&
1528                             ( pCurrentObject->Fcb == NULL ||
1529                               pCurrentObject->Fcb->OpenReferenceCount == 0 &&
1530                               pCurrentObject->Fcb->Specific.File.ExtentCount == 0))
1531                         {
1532
1533                             AFSRemoveFcb( &pCurrentObject->Fcb);
1534
1535                             AFSDeleteObjectInfo( pCurrentObject);
1536                         }
1537
1538                         AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
1539
1540                         pCurrentObject = pNextObject;
1541
1542                         continue;
1543                     }
1544
1545                     pCurrentObject = pNextObject;
1546                 }
1547
1548                 if( bReleaseVolumeLock)
1549                 {
1550
1551                     AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1552                 }
1553             }
1554
1555             //
1556             // Next volume cb
1557             //
1558
1559             AFSReleaseResource( pVolumeCB->VolumeLock);
1560
1561             AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1562                               TRUE);
1563
1564             pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1565         }
1566
1567         AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1568
1569     } // worker thread loop
1570
1571     KeCancelTimer( &Timer);
1572
1573     AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1574                   AFS_TRACE_LEVEL_VERBOSE,
1575                   "AFSPrimaryVolumeWorkerThread Exiting\n");
1576
1577     lCount = InterlockedDecrement( &pControlDeviceExt->Specific.Control.VolumeWorkerThreadCount);
1578
1579     if( lCount == 0)
1580     {
1581
1582         KeSetEvent( &pControlDeviceExt->Specific.Control.VolumeWorkerCloseEvent,
1583                     0,
1584                     FALSE);
1585     }
1586
1587     PsTerminateSystemThread( 0);
1588
1589     return;
1590 }
1591
1592 void
1593 AFSVolumeWorkerThread( IN PVOID Context)
1594 {
1595
1596     NTSTATUS ntStatus = STATUS_SUCCESS;
1597     AFSVolumeCB *pVolumeCB = (AFSVolumeCB * )Context;
1598     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)&pVolumeCB->VolumeWorkerContext;
1599     AFSDeviceExt *pControlDeviceExt = NULL;
1600     AFSDeviceExt *pRDRDeviceExt = NULL;
1601     BOOLEAN exitThread = FALSE;
1602     LARGE_INTEGER DueTime;
1603     LONG TimeOut;
1604     KTIMER Timer;
1605     LONG lCount;
1606
1607     pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1608
1609     pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1610
1611     //
1612     // Initialize the timer for the worker thread
1613     //
1614
1615     DueTime.QuadPart = -(5000);
1616
1617     TimeOut = 5000;
1618
1619     KeInitializeTimerEx( &Timer,
1620                          SynchronizationTimer);
1621
1622     KeSetTimerEx( &Timer,
1623                   DueTime,
1624                   TimeOut,
1625                   NULL);
1626
1627     //
1628     // Indicate that we are initialized and ready
1629     //
1630
1631     KeSetEvent( &pPoolContext->WorkerThreadReady,
1632                 0,
1633                 FALSE);
1634
1635     //
1636     // Indicate we are initialized
1637     //
1638
1639     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
1640
1641     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
1642     {
1643
1644         ntStatus = KeWaitForSingleObject( &Timer,
1645                                           Executive,
1646                                           KernelMode,
1647                                           FALSE,
1648                                           NULL);
1649
1650         if( !NT_SUCCESS( ntStatus))
1651         {
1652
1653             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1654                           AFS_TRACE_LEVEL_ERROR,
1655                           "AFSVolumeWorkerThread Wait for queue items failed Status %08lX\n", ntStatus);
1656         }
1657         else
1658         {
1659
1660             //
1661             // If we are in shutdown mode and the dirty flag is clear then get out now
1662             //
1663
1664             if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
1665             {
1666
1667                 break;
1668             }
1669         }
1670     } // worker thread loop
1671
1672     KeCancelTimer( &Timer);
1673
1674     lCount = InterlockedDecrement( &pControlDeviceExt->Specific.Control.VolumeWorkerThreadCount);
1675
1676     if( lCount == 0)
1677     {
1678
1679         KeSetEvent( &pControlDeviceExt->Specific.Control.VolumeWorkerCloseEvent,
1680                     0,
1681                     FALSE);
1682     }
1683
1684     PsTerminateSystemThread( 0);
1685
1686     return;
1687 }
1688
1689 NTSTATUS
1690 AFSInsertWorkitem( IN AFSWorkItem *WorkItem)
1691 {
1692
1693     NTSTATUS ntStatus = STATUS_SUCCESS;
1694     AFSDeviceExt *pDevExt = NULL;
1695     LONG lCount;
1696
1697     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1698
1699     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1700                   AFS_TRACE_LEVEL_VERBOSE,
1701                   "AFSInsertWorkitem Acquiring Control QueueLock lock %08lX EXCL %08lX\n",
1702                   &pDevExt->Specific.Library.QueueLock,
1703                   PsGetCurrentThread());
1704
1705     AFSAcquireExcl( &pDevExt->Specific.Library.QueueLock,
1706                     TRUE);
1707
1708     lCount = InterlockedIncrement( &pDevExt->Specific.Library.QueueItemCount);
1709
1710     AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
1711                   AFS_TRACE_LEVEL_VERBOSE,
1712                   "AFSInsertWorkitem Inserting work item %08lX Count %08lX\n",
1713                   WorkItem,
1714                   lCount);
1715
1716     if( pDevExt->Specific.Library.QueueTail != NULL) // queue already has nodes
1717     {
1718
1719         pDevExt->Specific.Library.QueueTail->next = WorkItem;
1720     }
1721     else // first node
1722     {
1723
1724         pDevExt->Specific.Library.QueueHead = WorkItem;
1725     }
1726
1727     WorkItem->next = NULL;
1728     pDevExt->Specific.Library.QueueTail = WorkItem;
1729
1730     // indicate that the queue has nodes
1731     KeSetEvent( &(pDevExt->Specific.Library.WorkerQueueHasItems),
1732                 0,
1733                 FALSE);
1734
1735     AFSReleaseResource( &pDevExt->Specific.Library.QueueLock);
1736
1737     return ntStatus;
1738 }
1739
1740 NTSTATUS
1741 AFSInsertIOWorkitem( IN AFSWorkItem *WorkItem)
1742 {
1743
1744     NTSTATUS ntStatus = STATUS_SUCCESS;
1745     AFSDeviceExt *pDevExt = NULL;
1746     LONG lCount;
1747
1748     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1749
1750     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1751                   AFS_TRACE_LEVEL_VERBOSE,
1752                   "AFSInsertIOWorkitem Acquiring Control QueueLock lock %08lX EXCL %08lX\n",
1753                   &pDevExt->Specific.Library.IOQueueLock,
1754                   PsGetCurrentThread());
1755
1756     AFSAcquireExcl( &pDevExt->Specific.Library.IOQueueLock,
1757                     TRUE);
1758
1759     lCount = InterlockedIncrement( &pDevExt->Specific.Library.IOQueueItemCount);
1760
1761     AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
1762                   AFS_TRACE_LEVEL_VERBOSE,
1763                   "AFSInsertWorkitem Inserting IO work item %08lX Count %08lX\n",
1764                   WorkItem,
1765                   lCount);
1766
1767     if( pDevExt->Specific.Library.IOQueueTail != NULL) // queue already has nodes
1768     {
1769
1770         pDevExt->Specific.Library.IOQueueTail->next = WorkItem;
1771     }
1772     else // first node
1773     {
1774
1775         pDevExt->Specific.Library.IOQueueHead = WorkItem;
1776     }
1777
1778     WorkItem->next = NULL;
1779     pDevExt->Specific.Library.IOQueueTail = WorkItem;
1780
1781     // indicate that the queue has nodes
1782     KeSetEvent( &(pDevExt->Specific.Library.IOWorkerQueueHasItems),
1783                 0,
1784                 FALSE);
1785
1786     AFSReleaseResource( &pDevExt->Specific.Library.IOQueueLock);
1787
1788     return ntStatus;
1789 }
1790
1791 NTSTATUS
1792 AFSInsertWorkitemAtHead( IN AFSWorkItem *WorkItem)
1793 {
1794
1795     NTSTATUS ntStatus = STATUS_SUCCESS;
1796     AFSDeviceExt *pDevExt = NULL;
1797     LONG lCount;
1798
1799     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1800
1801     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1802                   AFS_TRACE_LEVEL_VERBOSE,
1803                   "AFSInsertWorkitemAtHead Acquiring Control QueueLock lock %08lX EXCL %08lX\n",
1804                   &pDevExt->Specific.Library.QueueLock,
1805                   PsGetCurrentThread());
1806
1807     AFSAcquireExcl( &pDevExt->Specific.Library.QueueLock,
1808                     TRUE);
1809
1810     WorkItem->next = pDevExt->Specific.Library.QueueHead;
1811
1812     pDevExt->Specific.Library.QueueHead = WorkItem;
1813
1814     lCount = InterlockedIncrement( &pDevExt->Specific.Library.QueueItemCount);
1815
1816     AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
1817                   AFS_TRACE_LEVEL_VERBOSE,
1818                   "AFSInsertWorkitemAtHead Inserting work item %08lX Count %08lX\n",
1819                   WorkItem,
1820                   lCount);
1821
1822     //
1823     // indicate that the queue has nodes
1824     //
1825
1826     KeSetEvent( &(pDevExt->Specific.Library.WorkerQueueHasItems),
1827                 0,
1828                 FALSE);
1829
1830     AFSReleaseResource( &pDevExt->Specific.Library.QueueLock);
1831
1832     return ntStatus;
1833 }
1834
1835 AFSWorkItem *
1836 AFSRemoveWorkItem()
1837 {
1838
1839     NTSTATUS ntStatus = STATUS_SUCCESS;
1840     AFSWorkItem        *pWorkItem = NULL;
1841     AFSDeviceExt *pDevExt = NULL;
1842     LONG lCount;
1843
1844     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1845
1846     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1847                   AFS_TRACE_LEVEL_VERBOSE,
1848                   "AFSRemoveWorkItem Acquiring Control QueueLock lock %08lX EXCL %08lX\n",
1849                   &pDevExt->Specific.Library.QueueLock,
1850                   PsGetCurrentThread());
1851
1852     AFSAcquireExcl( &pDevExt->Specific.Library.QueueLock,
1853                     TRUE);
1854
1855     if( pDevExt->Specific.Library.QueueHead != NULL) // queue has nodes
1856     {
1857
1858         pWorkItem = pDevExt->Specific.Library.QueueHead;
1859
1860         lCount = InterlockedDecrement( &pDevExt->Specific.Library.QueueItemCount);
1861
1862         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
1863                       AFS_TRACE_LEVEL_VERBOSE,
1864                       "AFSRemoveWorkItem Removing work item %08lX Count %08lX Thread %08lX\n",
1865                       pWorkItem,
1866                       lCount,
1867                       PsGetCurrentThreadId());
1868
1869         pDevExt->Specific.Library.QueueHead = pDevExt->Specific.Library.QueueHead->next;
1870
1871         if( pDevExt->Specific.Library.QueueHead == NULL) // if queue just became empty
1872         {
1873
1874             pDevExt->Specific.Library.QueueTail = NULL;
1875         }
1876         else
1877         {
1878
1879             //
1880             // Wake up another worker
1881             //
1882
1883             KeSetEvent( &(pDevExt->Specific.Library.WorkerQueueHasItems),
1884                         0,
1885                         FALSE);
1886         }
1887     }
1888
1889     AFSReleaseResource( &pDevExt->Specific.Library.QueueLock);
1890
1891     return pWorkItem;
1892 }
1893
1894 AFSWorkItem *
1895 AFSRemoveIOWorkItem()
1896 {
1897
1898     NTSTATUS ntStatus = STATUS_SUCCESS;
1899     AFSWorkItem        *pWorkItem = NULL;
1900     AFSDeviceExt *pDevExt = NULL;
1901     LONG lCount;
1902
1903     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
1904
1905     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1906                   AFS_TRACE_LEVEL_VERBOSE,
1907                   "AFSRemoveIOWorkItem Acquiring Control QueueLock lock %08lX EXCL %08lX\n",
1908                   &pDevExt->Specific.Library.IOQueueLock,
1909                   PsGetCurrentThread());
1910
1911     AFSAcquireExcl( &pDevExt->Specific.Library.IOQueueLock,
1912                     TRUE);
1913
1914     if( pDevExt->Specific.Library.IOQueueHead != NULL) // queue has nodes
1915     {
1916
1917         pWorkItem = pDevExt->Specific.Library.IOQueueHead;
1918
1919         lCount = InterlockedDecrement( &pDevExt->Specific.Library.IOQueueItemCount);
1920
1921         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
1922                       AFS_TRACE_LEVEL_VERBOSE,
1923                       "AFSRemoveWorkItem Removing work item %08lX Count %08lX Thread %08lX\n",
1924                       pWorkItem,
1925                       lCount,
1926                       PsGetCurrentThreadId());
1927
1928         pDevExt->Specific.Library.IOQueueHead = pDevExt->Specific.Library.IOQueueHead->next;
1929
1930         if( pDevExt->Specific.Library.IOQueueHead == NULL) // if queue just became empty
1931         {
1932
1933             pDevExt->Specific.Library.IOQueueTail = NULL;
1934         }
1935         else
1936         {
1937
1938             //
1939             // Wake up another worker
1940             //
1941
1942             KeSetEvent( &(pDevExt->Specific.Library.IOWorkerQueueHasItems),
1943                         0,
1944                         FALSE);
1945         }
1946     }
1947
1948     AFSReleaseResource( &pDevExt->Specific.Library.IOQueueLock);
1949
1950     return pWorkItem;
1951 }
1952
1953 NTSTATUS
1954 AFSQueueWorkerRequest( IN AFSWorkItem *WorkItem)
1955 {
1956
1957     NTSTATUS ntStatus = STATUS_SUCCESS;
1958     AFSDeviceExt *pDevExt = NULL;
1959     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
1960
1961     //
1962     // Submit the work item to the worker
1963     //
1964
1965     ntStatus = AFSInsertWorkitem( WorkItem);
1966
1967     if( bWait)
1968     {
1969
1970         //
1971         // Sync request so block on the work item event
1972         //
1973
1974         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
1975                                           Executive,
1976                                           KernelMode,
1977                                           FALSE,
1978                                           NULL);
1979     }
1980
1981     return ntStatus;
1982 }
1983
1984 NTSTATUS
1985 AFSQueueIOWorkerRequest( IN AFSWorkItem *WorkItem)
1986 {
1987
1988     NTSTATUS ntStatus = STATUS_SUCCESS;
1989     AFSDeviceExt *pDevExt = NULL;
1990     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
1991
1992     //
1993     // Submit the work item to the worker
1994     //
1995
1996     ntStatus = AFSInsertIOWorkitem( WorkItem);
1997
1998     if( bWait)
1999     {
2000
2001         //
2002         // Sync request so block on the work item event
2003         //
2004
2005         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2006                                           Executive,
2007                                           KernelMode,
2008                                           FALSE,
2009                                           NULL);
2010     }
2011
2012     return ntStatus;
2013 }
2014
2015 NTSTATUS
2016 AFSQueueWorkerRequestAtHead( IN AFSWorkItem *WorkItem)
2017 {
2018
2019     NTSTATUS ntStatus = STATUS_SUCCESS;
2020     AFSDeviceExt *pDevExt = NULL;
2021     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
2022
2023     //
2024     // Submit the work item to the worker
2025     //
2026
2027     ntStatus = AFSInsertWorkitemAtHead( WorkItem);
2028
2029     if( bWait)
2030     {
2031
2032         //
2033         // Sync request so block on the work item event
2034         //
2035
2036         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2037                                           Executive,
2038                                           KernelMode,
2039                                           FALSE,
2040                                           NULL);
2041     }
2042
2043     return ntStatus;
2044 }
2045
2046 NTSTATUS
2047 AFSQueueFlushExtents( IN AFSFcb *Fcb,
2048                       IN GUID *AuthGroup)
2049 {
2050
2051     NTSTATUS ntStatus = STATUS_SUCCESS;
2052     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
2053     AFSWorkItem *pWorkItem = NULL;
2054     LONG lCount;
2055
2056     __try
2057     {
2058
2059         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2060                       AFS_TRACE_LEVEL_VERBOSE,
2061                       "AFSQueueFlushExtents Queuing request for FID %08lX-%08lX-%08lX-%08lX\n",
2062                       Fcb->ObjectInformation->FileId.Cell,
2063                       Fcb->ObjectInformation->FileId.Volume,
2064                       Fcb->ObjectInformation->FileId.Vnode,
2065                       Fcb->ObjectInformation->FileId.Unique);
2066
2067         //
2068         // Increment our flush count here just to keep the number of items in the
2069         // queue down. We'll decrement it just below.
2070         //
2071
2072         lCount = InterlockedIncrement( &Fcb->Specific.File.QueuedFlushCount);
2073
2074         if( lCount > 3)
2075         {
2076
2077             AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2078                           AFS_TRACE_LEVEL_VERBOSE,
2079                           "AFSQueueFlushExtents Max queued items for FID %08lX-%08lX-%08lX-%08lX\n",
2080                           Fcb->ObjectInformation->FileId.Cell,
2081                           Fcb->ObjectInformation->FileId.Volume,
2082                           Fcb->ObjectInformation->FileId.Vnode,
2083                           Fcb->ObjectInformation->FileId.Unique);
2084
2085             try_return( ntStatus);
2086         }
2087
2088         if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
2089         {
2090
2091             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2092                           AFS_TRACE_LEVEL_ERROR,
2093                           "AFSQueueFlushExtents Failing request, in shutdown\n");
2094
2095             try_return( ntStatus = STATUS_TOO_LATE);
2096         }
2097
2098         //
2099         // Allocate our request structure and send it to the worker
2100         //
2101
2102         pWorkItem = (AFSWorkItem *)AFSLibExAllocatePoolWithTag( NonPagedPool,
2103                                                                 sizeof( AFSWorkItem),
2104                                                                 AFS_WORK_ITEM_TAG);
2105
2106         if( pWorkItem == NULL)
2107         {
2108
2109             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2110                           AFS_TRACE_LEVEL_ERROR,
2111                           "AFSQueueFlushExtents Failed to allocate work item\n");
2112
2113             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2114         }
2115
2116         RtlZeroMemory( pWorkItem,
2117                        sizeof( AFSWorkItem));
2118
2119         pWorkItem->Size = sizeof( AFSWorkItem);
2120
2121         pWorkItem->ProcessID = (ULONGLONG)PsGetCurrentProcessId();
2122
2123         pWorkItem->RequestType = AFS_WORK_FLUSH_FCB;
2124
2125         if ( AuthGroup == NULL)
2126         {
2127
2128             RtlZeroMemory( &pWorkItem->AuthGroup,
2129                            sizeof( GUID));
2130
2131             ntStatus = AFSRetrieveValidAuthGroup( Fcb,
2132                                                   NULL,
2133                                                   TRUE,
2134                                                   &pWorkItem->AuthGroup);
2135         }
2136         else
2137         {
2138             RtlCopyMemory( &pWorkItem->AuthGroup,
2139                            AuthGroup,
2140                            sizeof( GUID));
2141         }
2142
2143         pWorkItem->Specific.Fcb.Fcb = Fcb;
2144
2145         lCount = InterlockedIncrement( &Fcb->OpenReferenceCount);
2146
2147         AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
2148                       AFS_TRACE_LEVEL_VERBOSE,
2149                       "AFSQueueFlushExtents Increment count on Fcb %08lX Cnt %d\n",
2150                       Fcb,
2151                       lCount);
2152
2153         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2154                       AFS_TRACE_LEVEL_VERBOSE,
2155                       "AFSQueueFlushExtents Workitem %08lX for FID %08lX-%08lX-%08lX-%08lX\n",
2156                       pWorkItem,
2157                       Fcb->ObjectInformation->FileId.Cell,
2158                       Fcb->ObjectInformation->FileId.Volume,
2159                       Fcb->ObjectInformation->FileId.Vnode,
2160                       Fcb->ObjectInformation->FileId.Unique);
2161
2162         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2163
2164 try_exit:
2165
2166         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2167                       AFS_TRACE_LEVEL_VERBOSE,
2168                       "AFSQueueFlushExtents Request complete Status %08lX FID %08lX-%08lX-%08lX-%08lX\n",
2169                       Fcb->ObjectInformation->FileId.Cell,
2170                       Fcb->ObjectInformation->FileId.Volume,
2171                       Fcb->ObjectInformation->FileId.Vnode,
2172                       Fcb->ObjectInformation->FileId.Unique,
2173                       ntStatus);
2174
2175         //
2176         // Remove the count we added above
2177         //
2178
2179         lCount = InterlockedDecrement( &Fcb->Specific.File.QueuedFlushCount);
2180
2181         if( lCount == 0)
2182         {
2183
2184             KeSetEvent( &Fcb->NPFcb->Specific.File.QueuedFlushEvent,
2185                         0,
2186                         FALSE);
2187         }
2188
2189         if( !NT_SUCCESS( ntStatus))
2190         {
2191
2192             if( pWorkItem != NULL)
2193             {
2194
2195                 lCount = InterlockedDecrement( &Fcb->OpenReferenceCount);
2196
2197                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2198             }
2199
2200             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2201                           AFS_TRACE_LEVEL_ERROR,
2202                           "AFSQueueFlushExtents Failed to queue request Status %08lX\n", ntStatus);
2203         }
2204     }
2205     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2206     {
2207
2208         AFSDbgLogMsg( 0,
2209                       0,
2210                       "EXCEPTION - AFSQueueFlushExtents\n");
2211
2212         AFSDumpTraceFilesFnc();
2213     }
2214
2215     return ntStatus;
2216 }
2217
2218 NTSTATUS
2219 AFSQueueGlobalRootEnumeration()
2220 {
2221
2222     NTSTATUS ntStatus = STATUS_SUCCESS;
2223     AFSWorkItem *pWorkItem = NULL;
2224
2225     __try
2226     {
2227
2228         pWorkItem = (AFSWorkItem *) AFSLibExAllocatePoolWithTag( NonPagedPool,
2229                                                                  sizeof(AFSWorkItem),
2230                                                                  AFS_WORK_ITEM_TAG);
2231         if (NULL == pWorkItem)
2232         {
2233
2234             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2235                           AFS_TRACE_LEVEL_ERROR,
2236                           "AFSQueueGlobalRootEnumeration Failed to allocate work item\n");
2237
2238             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2239         }
2240
2241         RtlZeroMemory( pWorkItem,
2242                        sizeof(AFSWorkItem));
2243
2244         pWorkItem->Size = sizeof( AFSWorkItem);
2245
2246         pWorkItem->RequestType = AFS_WORK_ENUMERATE_GLOBAL_ROOT;
2247
2248         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2249                       AFS_TRACE_LEVEL_VERBOSE,
2250                       "AFSQueueGlobalRootEnumeration Workitem %08lX\n",
2251                       pWorkItem);
2252
2253         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2254
2255 try_exit:
2256
2257         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2258                       AFS_TRACE_LEVEL_VERBOSE,
2259                       "AFSQueueGlobalRootEnumeration Request complete Status %08lX\n",
2260                       ntStatus);
2261
2262         if( !NT_SUCCESS( ntStatus))
2263         {
2264
2265             if( pWorkItem != NULL)
2266             {
2267
2268                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2269             }
2270
2271             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2272                           AFS_TRACE_LEVEL_ERROR,
2273                           "AFSQueueGlobalRootEnumeration Failed to queue request Status %08lX\n",
2274                           ntStatus);
2275         }
2276     }
2277     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2278     {
2279
2280         AFSDbgLogMsg( 0,
2281                       0,
2282                       "EXCEPTION - AFSQueueGlobalRootEnumeration\n");
2283
2284         AFSDumpTraceFilesFnc();
2285     }
2286
2287     return ntStatus;
2288 }
2289
2290 NTSTATUS
2291 AFSQueueStartIos( IN PFILE_OBJECT CacheFileObject,
2292                   IN UCHAR FunctionCode,
2293                   IN ULONG RequestFlags,
2294                   IN AFSIoRun *IoRuns,
2295                   IN ULONG RunCount,
2296                   IN AFSGatherIo *GatherIo)
2297 {
2298
2299     NTSTATUS ntStatus = STATUS_SUCCESS;
2300     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
2301     AFSWorkItem *pWorkItem = NULL;
2302
2303     __try
2304     {
2305
2306         if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
2307         {
2308
2309             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2310                           AFS_TRACE_LEVEL_ERROR,
2311                           "AFSQueueStartIos Failing request, in shutdown\n");
2312
2313             try_return( ntStatus = STATUS_TOO_LATE);
2314         }
2315
2316         //
2317         // Allocate our request structure and send it to the worker
2318         //
2319
2320         pWorkItem = (AFSWorkItem *)AFSLibExAllocatePoolWithTag( NonPagedPool,
2321                                                                 sizeof( AFSWorkItem),
2322                                                                 AFS_WORK_ITEM_TAG);
2323
2324         if( pWorkItem == NULL)
2325         {
2326
2327             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2328                           AFS_TRACE_LEVEL_ERROR,
2329                           "AFSQueueStartIos Failed to allocate work item\n");
2330
2331             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2332         }
2333
2334         RtlZeroMemory( pWorkItem,
2335                        sizeof( AFSWorkItem));
2336
2337         KeInitializeEvent( &pWorkItem->Event,
2338                            NotificationEvent,
2339                            FALSE);
2340
2341         pWorkItem->Size = sizeof( AFSWorkItem);
2342
2343         pWorkItem->ProcessID = (ULONGLONG)PsGetCurrentProcessId();
2344
2345         pWorkItem->RequestType = AFS_WORK_START_IOS;
2346
2347         pWorkItem->Specific.CacheAccess.CacheFileObject = CacheFileObject;
2348
2349         pWorkItem->Specific.CacheAccess.FunctionCode = FunctionCode;
2350
2351         pWorkItem->Specific.CacheAccess.RequestFlags = RequestFlags;
2352
2353         pWorkItem->Specific.CacheAccess.IoRuns = IoRuns;
2354
2355         pWorkItem->Specific.CacheAccess.RunCount = RunCount;
2356
2357         pWorkItem->Specific.CacheAccess.GatherIo = GatherIo;
2358
2359         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2360                       AFS_TRACE_LEVEL_VERBOSE,
2361                       "AFSQueueStartIos Queuing IO Workitem %08lX\n",
2362                       pWorkItem);
2363
2364         ntStatus = AFSQueueIOWorkerRequest( pWorkItem);
2365
2366 try_exit:
2367
2368         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2369                       AFS_TRACE_LEVEL_VERBOSE,
2370                       "AFSQueueStartIos Request complete Status %08lX\n",
2371                       ntStatus);
2372
2373         if( !NT_SUCCESS( ntStatus))
2374         {
2375
2376             if( pWorkItem != NULL)
2377             {
2378
2379                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2380             }
2381         }
2382     }
2383     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2384     {
2385
2386         AFSDbgLogMsg( 0,
2387                       0,
2388                       "EXCEPTION - AFSQueueStartIos\n");
2389
2390         AFSDumpTraceFilesFnc();
2391     }
2392
2393     return ntStatus;
2394 }
2395
2396 NTSTATUS
2397 AFSQueueInvalidateObject( IN AFSObjectInfoCB *ObjectInfo,
2398                           IN ULONG InvalidateReason)
2399 {
2400
2401     NTSTATUS ntStatus = STATUS_SUCCESS;
2402     AFSWorkItem *pWorkItem = NULL;
2403
2404     __try
2405     {
2406
2407         pWorkItem = (AFSWorkItem *) AFSLibExAllocatePoolWithTag( NonPagedPool,
2408                                                                  sizeof(AFSWorkItem),
2409                                                                  AFS_WORK_ITEM_TAG);
2410         if (NULL == pWorkItem)
2411         {
2412
2413             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2414                           AFS_TRACE_LEVEL_ERROR,
2415                           "AFSQueueInvalidateObject Failed to allocate work item\n");
2416
2417             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2418         }
2419
2420         RtlZeroMemory( pWorkItem,
2421                        sizeof(AFSWorkItem));
2422
2423         pWorkItem->Size = sizeof( AFSWorkItem);
2424
2425         pWorkItem->RequestType = AFS_WORK_INVALIDATE_OBJECT;
2426
2427         pWorkItem->Specific.Invalidate.ObjectInfo = ObjectInfo;
2428
2429         pWorkItem->Specific.Invalidate.InvalidateReason = InvalidateReason;
2430
2431         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2432                       AFS_TRACE_LEVEL_VERBOSE,
2433                       "AFSQueueInvalidateObject Workitem %08lX\n",
2434                       pWorkItem);
2435
2436         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2437
2438 try_exit:
2439
2440         AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
2441                       AFS_TRACE_LEVEL_VERBOSE,
2442                       "AFSQueueInvalidateObject Request complete Status %08lX\n",
2443                       ntStatus);
2444
2445         if( !NT_SUCCESS( ntStatus))
2446         {
2447
2448             if( pWorkItem != NULL)
2449             {
2450                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2451             }
2452
2453             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2454                           AFS_TRACE_LEVEL_ERROR,
2455                           "AFSQueueInvalidateObject Failed to queue request Status %08lX\n",
2456                           ntStatus);
2457         }
2458     }
2459     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2460     {
2461
2462         AFSDbgLogMsg( 0,
2463                       0,
2464                       "EXCEPTION - AFSQueueInvalidateObject\n");
2465
2466         AFSDumpTraceFilesFnc();
2467     }
2468
2469     return ntStatus;
2470 }