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