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