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