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