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