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