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