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