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