Windows: AFSExamineVolume drop TreeLock if waiters
[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, 2012, 2013 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, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
16  *   nor the names of their contributors may be used to endorse or promote
17  *   products derived from this software without specific prior written
18  *   permission from Kernel Drivers, LLC and Your File System, Inc.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
24  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 //
34 // File: AFSWorker.cpp
35 //
36
37 #include "AFSCommon.h"
38
39 static
40 VOID
41 AFSPostedDeferredWrite( IN PVOID Context1,
42                         IN PVOID Context2);
43
44 //
45 // Function: AFSInitializeWorkerPool
46 //
47 // Description:
48 //
49 //      This function initializes the worker thread pool
50 //
51 // Return:
52 //
53 //      A status is returned for the function
54 //
55
56 NTSTATUS
57 AFSInitializeWorkerPool()
58 {
59
60     NTSTATUS ntStatus = STATUS_SUCCESS;
61     AFSWorkQueueContext        *pCurrentWorker = NULL, *pLastWorker = NULL;
62     AFSDeviceExt *pDevExt = NULL;
63
64     __Enter
65     {
66
67         pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
68
69         //
70         // Initialize the worker threads.
71         //
72
73         while( pDevExt->Specific.Library.WorkerCount < AFS_WORKER_COUNT)
74         {
75
76             pCurrentWorker = (AFSWorkQueueContext *)AFSLibExAllocatePoolWithTag( NonPagedPool,
77                                                                                  sizeof( AFSWorkQueueContext),
78                                                                                  AFS_WORKER_CB_TAG);
79
80             if( pCurrentWorker == NULL)
81             {
82
83                 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
84                               AFS_TRACE_LEVEL_ERROR,
85                               "AFSInitializeWorkerPool Failed to allocate worker context\n"));
86
87                 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
88
89                 break;
90             }
91
92             RtlZeroMemory( pCurrentWorker,
93                            sizeof( AFSWorkQueueContext));
94
95             ntStatus = AFSInitWorkerThread( pCurrentWorker,
96                                             (PKSTART_ROUTINE)AFSWorkerThread);
97
98             if( !NT_SUCCESS( ntStatus))
99             {
100
101                 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
102                               AFS_TRACE_LEVEL_ERROR,
103                               "AFSInitializeWorkerPool Failed to initialize worker thread Status %08lX\n",
104                               ntStatus));
105
106                 ExFreePool( pCurrentWorker);
107
108                 break;
109             }
110
111             if( pDevExt->Specific.Library.PoolHead == NULL)
112             {
113
114                 pDevExt->Specific.Library.PoolHead = pCurrentWorker;
115             }
116             else
117             {
118
119                 pLastWorker->fLink = pCurrentWorker;
120             }
121
122             pLastWorker = pCurrentWorker;
123
124             pDevExt->Specific.Library.WorkerCount++;
125         }
126
127         //
128         // If there was a failure but there is at least one worker, then go with it.
129         //
130
131         if( !NT_SUCCESS( ntStatus) &&
132             pDevExt->Specific.Library.WorkerCount == 0)
133         {
134
135             try_return( ntStatus);
136         }
137
138         ntStatus = STATUS_SUCCESS;
139
140         //
141         // Now our IO Worker queue
142         //
143
144         while( pDevExt->Specific.Library.IOWorkerCount < AFS_IO_WORKER_COUNT)
145         {
146
147             pCurrentWorker = (AFSWorkQueueContext *)AFSLibExAllocatePoolWithTag( NonPagedPool,
148                                                                                  sizeof( AFSWorkQueueContext),
149                                                                                  AFS_WORKER_CB_TAG);
150
151             if( pCurrentWorker == NULL)
152             {
153
154                 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
155                               AFS_TRACE_LEVEL_ERROR,
156                               "AFSInitializeWorkerPool Failed to allocate IO worker context\n"));
157
158                 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
159
160                 break;
161             }
162
163             RtlZeroMemory( pCurrentWorker,
164                            sizeof( AFSWorkQueueContext));
165
166             ntStatus = AFSInitWorkerThread( pCurrentWorker,
167                                             (PKSTART_ROUTINE)AFSIOWorkerThread);
168
169             if( !NT_SUCCESS( ntStatus))
170             {
171
172                 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
173                               AFS_TRACE_LEVEL_ERROR,
174                               "AFSInitializeWorkerPool Failed to initialize IO worker thread Status %08lX\n",
175                               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             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
683                           AFS_TRACE_LEVEL_ERROR,
684                           "AFSWorkerThread Wait for queue items failed Status %08lX\n",
685                           ntStatus));
686
687             ntStatus = STATUS_SUCCESS;
688         }
689         else
690         {
691
692             pWorkItem = AFSRemoveWorkItem();
693
694             if( pWorkItem == NULL)
695             {
696
697                 ntStatus = KeWaitForSingleObject( &pControlDevExt->Specific.Control.WorkerQueueHasItems,
698                                                   Executive,
699                                                   KernelMode,
700                                                   FALSE,
701                                                   NULL);
702             }
703             else
704             {
705
706                 freeWorkItem = TRUE;
707
708                 //
709                 // Switch on the type of work item to process
710                 //
711
712                 switch( pWorkItem->RequestType)
713                 {
714
715                     case AFS_WORK_FLUSH_FCB:
716                     {
717
718                         ntStatus = AFSFlushExtents( pWorkItem->Specific.Fcb.Fcb,
719                                                     &pWorkItem->AuthGroup);
720
721                         if( !NT_SUCCESS( ntStatus))
722                         {
723
724                             AFSReleaseExtentsWithFlush( pWorkItem->Specific.Fcb.Fcb,
725                                                         &pWorkItem->AuthGroup,
726                                                         FALSE);
727                         }
728
729                         ASSERT( pWorkItem->Specific.Fcb.Fcb->OpenReferenceCount != 0);
730
731                         lCount = InterlockedDecrement( &pWorkItem->Specific.Fcb.Fcb->OpenReferenceCount);
732
733                         break;
734                     }
735
736                     case AFS_WORK_ENUMERATE_GLOBAL_ROOT:
737                     {
738
739                         AFSEnumerateGlobalRoot( NULL);
740
741                         break;
742                     }
743
744                     case AFS_WORK_INVALIDATE_OBJECT:
745                     {
746
747                         AFSPerformObjectInvalidate( pWorkItem->Specific.Invalidate.ObjectInfo,
748                                                     pWorkItem->Specific.Invalidate.InvalidateReason);
749
750                         freeWorkItem = TRUE;
751
752                         break;
753                     }
754
755                     case AFS_WORK_START_IOS:
756                     {
757
758                         freeWorkItem = TRUE;
759
760                         break;
761                     }
762
763                     default:
764
765                         AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
766                                       AFS_TRACE_LEVEL_ERROR,
767                                       "AFSWorkerThread Unknown request type %d\n",
768                                       pWorkItem->RequestType));
769
770                         break;
771                 }
772
773                 if( freeWorkItem)
774                 {
775
776                     ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
777                 }
778
779                 ntStatus = STATUS_SUCCESS;
780             }
781         }
782     } // worker thread loop
783
784     ClearFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
785
786     // Wake up another worker so they too can exit
787
788     KeSetEvent( &pControlDevExt->Specific.Control.WorkerQueueHasItems,
789                 0,
790                 FALSE);
791
792     PsTerminateSystemThread( 0);
793
794     return;
795 }
796
797 void
798 AFSIOWorkerThread( IN PVOID Context)
799 {
800
801     NTSTATUS ntStatus = STATUS_SUCCESS;
802     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)Context;
803     AFSWorkItem *pWorkItem;
804     BOOLEAN freeWorkItem = TRUE;
805     AFSDeviceExt *pControlDevExt = NULL, *pRdrDevExt = NULL;
806
807     pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
808
809     //
810     // Indicate that we are initialized and ready
811     //
812
813     KeSetEvent( &pPoolContext->WorkerThreadReady,
814                 0,
815                 FALSE);
816
817
818     //
819     // Indicate we are initialized
820     //
821
822     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
823
824     ntStatus = KeWaitForSingleObject( &pControlDevExt->Specific.Control.IOWorkerQueueHasItems,
825                                       Executive,
826                                       KernelMode,
827                                       FALSE,
828                                       NULL);
829
830     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
831     {
832
833         if( !NT_SUCCESS( ntStatus))
834         {
835
836             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
837                           AFS_TRACE_LEVEL_ERROR,
838                           "AFSIOWorkerThread Wait for queue items failed Status %08lX\n",
839                           ntStatus));
840
841             ntStatus = STATUS_SUCCESS;
842         }
843         else
844         {
845
846             pWorkItem = AFSRemoveIOWorkItem();
847
848             if( pWorkItem == NULL)
849             {
850
851                 ntStatus = KeWaitForSingleObject( &pControlDevExt->Specific.Control.IOWorkerQueueHasItems,
852                                                   Executive,
853                                                   KernelMode,
854                                                   FALSE,
855                                                   NULL);
856             }
857             else
858             {
859
860                 freeWorkItem = TRUE;
861
862                 //
863                 // Switch on the type of work item to process
864                 //
865
866                 switch( pWorkItem->RequestType)
867                 {
868
869                     case AFS_WORK_START_IOS:
870                     {
871
872                         pRdrDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
873
874                         //
875                         // The final status is in the gather io
876                         //
877
878                         ntStatus = AFSStartIos( pWorkItem->Specific.CacheAccess.CacheFileObject,
879                                                 pWorkItem->Specific.CacheAccess.FunctionCode,
880                                                 pWorkItem->Specific.CacheAccess.RequestFlags,
881                                                 pWorkItem->Specific.CacheAccess.IoRuns,
882                                                 pWorkItem->Specific.CacheAccess.RunCount,
883                                                 pWorkItem->Specific.CacheAccess.GatherIo);
884
885                         //
886                         // Regardless of the status we we do the complete - there may
887                         // be IOs in flight
888                         // Decrement the count - setting the event if we were told
889                         // to. This may trigger completion.
890                         //
891
892                         AFSCompleteIo( pWorkItem->Specific.CacheAccess.GatherIo, ntStatus );
893
894                         freeWorkItem = TRUE;
895
896                         break;
897                     }
898
899                     case AFS_WORK_DEFERRED_WRITE:
900                     {
901
902                         ntStatus = AFSCommonWrite( pWorkItem->Specific.AsynchIo.Device,
903                                                    pWorkItem->Specific.AsynchIo.Irp,
904                                                    pWorkItem->Specific.AsynchIo.CallingProcess,
905                                                    TRUE);
906
907                         freeWorkItem = TRUE;
908
909                         break;
910                     }
911
912                     default:
913
914                         AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
915                                       AFS_TRACE_LEVEL_ERROR,
916                                       "AFSIOWorkerThread Unknown request type %d\n",
917                                       pWorkItem->RequestType));
918
919                         break;
920                 }
921
922                 if( freeWorkItem)
923                 {
924
925                     ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
926                 }
927
928                 ntStatus = STATUS_SUCCESS;
929             }
930         }
931     } // worker thread loop
932
933     ClearFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
934
935     // Wake up another IOWorker so they too can exit
936
937     KeSetEvent( &pControlDevExt->Specific.Control.IOWorkerQueueHasItems,
938                 0,
939                 FALSE);
940
941     PsTerminateSystemThread( 0);
942
943     return;
944 }
945
946 //
947 // Called with VolumeCB->ObjectInfoTree.TreeLock held exclusive.
948 // pCurrentObject->ObjectReferenceCount is incremented by the caller.
949 //
950 // The *pbReleaseVolumeLock is set to FALSE if the TreeLock is dropped
951 // before returning.
952 //
953 // pCurrentObject must either be destroyed or the reference count
954 // decremented before returning.
955 //
956
957 static void
958 AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
959                       IN BOOLEAN           bVolumeObject,
960                       IN OUT BOOLEAN     * pbReleaseVolumeLock)
961 {
962     NTSTATUS ntStatus = STATUS_SUCCESS;
963     AFSDeviceExt *pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
964     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
965     AFSDirectoryCB *pCurrentDirEntry = NULL, *pNextDirEntry = NULL;
966     AFSObjectInfoCB *pCurrentChildObject = NULL;
967     AFSVolumeCB * pVolumeCB = pCurrentObject->VolumeCB;
968     LARGE_INTEGER liCurrentTime;
969     LONG lCount;
970     BOOLEAN bTemp;
971
972     __Enter
973     {
974
975         ASSERT( ExIsResourceAcquiredExclusiveLite( pVolumeCB->ObjectInfoTree.TreeLock));
976
977         switch ( pCurrentObject->FileType)
978         {
979
980         case AFS_FILE_TYPE_DIRECTORY:
981         {
982
983             if ( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
984             {
985
986                 try_return( ntStatus);
987             }
988
989             //
990             // If this object is deleted then remove it from the parent, if we can
991             //
992
993             if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DELETED))
994             {
995
996                 if ( pCurrentObject->ObjectReferenceCount == 1 &&
997                      ( pCurrentObject->Fcb == NULL ||
998                        pCurrentObject->Fcb->OpenReferenceCount == 0) &&
999                      pCurrentObject->Specific.Directory.DirectoryNodeListHead == NULL &&
1000                      pCurrentObject->Specific.Directory.ChildOpenReferenceCount == 0)
1001                 {
1002
1003                     AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
1004                                     TRUE);
1005
1006                     if ( pCurrentObject->Fcb != NULL)
1007                     {
1008
1009                         AFSRemoveFcb( &pCurrentObject->Fcb);
1010                     }
1011
1012                     if( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
1013                     {
1014
1015                         AFSAcquireExcl( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock,
1016                                         TRUE);
1017
1018                         AFSRemoveFcb( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
1019
1020                         AFSReleaseResource( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
1021
1022                         lCount = AFSObjectInfoDecrement( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation,
1023                                                          AFS_OBJECT_REFERENCE_PIOCTL);
1024
1025                         AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1026                                       AFS_TRACE_LEVEL_VERBOSE,
1027                                       "AFSExamineObjectInfo Decrement count on object %p Cnt %d\n",
1028                                       pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation,
1029                                       lCount));
1030
1031                         ASSERT( lCount == 0);
1032
1033                         if ( lCount == 0)
1034                         {
1035
1036                             AFSDeleteObjectInfo( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
1037                         }
1038
1039                         ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
1040
1041                         AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
1042
1043                         AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
1044                                       AFS_TRACE_LEVEL_VERBOSE,
1045                                       "AFSExamineObjectInfo (pioctl) AFS_DIR_ENTRY_TAG deallocating %p\n",
1046                                       pCurrentObject->Specific.Directory.PIOCtlDirectoryCB));
1047
1048                         AFSExFreePoolWithTag( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
1049
1050                         pCurrentObject->Specific.Directory.PIOCtlDirectoryCB = NULL;
1051                     }
1052
1053                     AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1054
1055                     lCount = AFSObjectInfoDecrement( pCurrentObject,
1056                                                      AFS_OBJECT_REFERENCE_WORKER);
1057
1058                     AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1059                                   AFS_TRACE_LEVEL_VERBOSE,
1060                                   "AFSExamineObjectInfo Decrement1 count on object %p Cnt %d\n",
1061                                   pCurrentObject,
1062                                   lCount));
1063
1064                     AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1065                                   AFS_TRACE_LEVEL_VERBOSE,
1066                                   "AFSExamineObjectInfo Deleting deleted object %p\n",
1067                                   pCurrentObject));
1068
1069                     //
1070                     // The CurrentReferenceCount must be zero or we would not
1071                     // have gotten this far.   It is safe to delete the ObjectInfoCB.
1072                     //
1073
1074                     AFSDeleteObjectInfo( &pCurrentObject);
1075                 }
1076
1077                 //
1078                 // Finished processing the AFS_OBJECT_FLAGS_DELETED case.
1079                 //
1080
1081                 try_return( ntStatus);
1082             }
1083
1084             //
1085             // pCurrentObject not marked Deleted.
1086             //
1087
1088             if ( pCurrentObject->Fcb != NULL &&
1089                  pCurrentObject->Fcb->CcbListHead != NULL)
1090             {
1091
1092                 try_return( ntStatus);
1093             }
1094
1095             if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0 ||
1096                 ( pCurrentObject->Fcb != NULL &&
1097                   pCurrentObject->Fcb->OpenReferenceCount > 0))
1098             {
1099
1100                 try_return( ntStatus);
1101             }
1102
1103             if ( pCurrentObject->FileType == AFS_FILE_TYPE_DIRECTORY &&
1104                  pCurrentObject->Specific.Directory.DirectoryNodeListHead != NULL)
1105             {
1106
1107                 //
1108                 // Directory Entry Processing
1109                 //
1110                 // First pass is performed with the TreeLock held shared.
1111                 // If we detect any objects in use, we give up quickly without
1112                 // making any changes and without blocking other threads.
1113                 // The second pass is performed with the TreeLock held exclusive
1114                 // so deletions can take place.
1115                 //
1116
1117                 if( !AFSAcquireShared( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
1118                                        FALSE))
1119                 {
1120
1121                     try_return( ntStatus);
1122                 }
1123
1124                 KeQueryTickCount( &liCurrentTime);
1125
1126                 pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
1127
1128                 while( pCurrentDirEntry != NULL)
1129                 {
1130
1131                     if( pCurrentDirEntry->DirOpenReferenceCount > 0 ||
1132                         pCurrentDirEntry->NameArrayReferenceCount > 0)
1133                     {
1134
1135                         AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1136
1137                         try_return( ntStatus);
1138                     }
1139
1140                     if ( pCurrentDirEntry->ObjectInformation != NULL)
1141                     {
1142
1143                         if ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1144                              pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0)
1145                         {
1146
1147                             AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1148
1149                             try_return( ntStatus);
1150                         }
1151
1152                         if ( liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart ||
1153                              liCurrentTime.QuadPart - pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart <
1154                              pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
1155                         {
1156
1157                             AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1158
1159                             try_return( ntStatus);
1160                         }
1161
1162                         if ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY)
1163                         {
1164
1165                             if ( pCurrentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL)
1166                             {
1167
1168                                 break;
1169                             }
1170
1171                             if ( pCurrentDirEntry->ObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)
1172                             {
1173
1174                                 break;
1175                             }
1176                         }
1177
1178                         if ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE)
1179                         {
1180
1181                             if ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1182                                  pCurrentDirEntry->ObjectInformation->Fcb->Specific.File.ExtentsDirtyCount > 0)
1183                             {
1184
1185                                 break;
1186                             }
1187                         }
1188                     }
1189
1190                     pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
1191                 }
1192
1193                 AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1194
1195                 if( pCurrentDirEntry != NULL)
1196                 {
1197
1198                     try_return( ntStatus);
1199                 }
1200
1201                 //
1202                 // Attempt the second pass with the TreeLock held exclusive.
1203                 // The the TreeLock cannot be obtained without blocking it means that
1204                 // the directory is in active use, so do nothing.
1205                 //
1206
1207                 if( AFSAcquireExcl( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
1208                                     FALSE))
1209                 {
1210
1211                     if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0)
1212                     {
1213
1214                         AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1215
1216                         try_return( ntStatus);
1217                     }
1218
1219                     KeQueryTickCount( &liCurrentTime);
1220
1221                     pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
1222
1223                     while( pCurrentDirEntry != NULL)
1224                     {
1225
1226                         if( pCurrentDirEntry->DirOpenReferenceCount > 0)
1227                         {
1228
1229                             break;
1230                         }
1231
1232                         if ( pCurrentDirEntry->NameArrayReferenceCount > 0)
1233                         {
1234
1235                             break;
1236                         }
1237
1238                         if ( pCurrentDirEntry->ObjectInformation != NULL)
1239                         {
1240
1241                             if ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1242                                  pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0)
1243                             {
1244
1245                                 break;
1246                             }
1247
1248                             if ( liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart ||
1249                                  liCurrentTime.QuadPart - pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart <
1250                                  pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
1251                             {
1252
1253                                 break;
1254                             }
1255
1256                             if ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY)
1257                             {
1258
1259                                 if ( pCurrentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL)
1260                                 {
1261
1262                                     break;
1263                                 }
1264
1265                                 if ( pCurrentDirEntry->ObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)
1266                                 {
1267
1268                                     break;
1269                                 }
1270                             }
1271
1272                             if ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE)
1273                             {
1274
1275                                 if ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
1276                                      pCurrentDirEntry->ObjectInformation->Fcb->Specific.File.ExtentsDirtyCount > 0)
1277                                 {
1278
1279                                     break;
1280                                 }
1281                             }
1282                         }
1283
1284                         pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
1285                     }
1286
1287                     if( pCurrentDirEntry != NULL)
1288                     {
1289
1290                         //
1291                         // At least one entry in the directory is actively in use.
1292                         // Drop the lock and exit without removing anything.
1293                         //
1294
1295                         AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1296
1297                         try_return( ntStatus);
1298                     }
1299
1300                     //
1301                     // Third pass, process each directory entry and remove what we can.
1302                     // The VolumeCB TreeLock and the ObjectInfo TreeLock are still held exclusive.
1303                     //
1304
1305                     pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
1306
1307                     while( pCurrentDirEntry != NULL)
1308                     {
1309
1310                         pNextDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
1311
1312                         //
1313                         // Delete the DirectoryCB which in turn removes the DIRENTRY reference
1314                         // count from the associated ObjectInfoCB.  The reference count held above
1315                         // may now be the only one left.
1316                         //
1317
1318                         AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING | AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1319                                       AFS_TRACE_LEVEL_VERBOSE,
1320                                       "AFSExamineObjectInfo Deleting DE %wZ Object %p\n",
1321                                       &pCurrentDirEntry->NameInformation.FileName,
1322                                       pCurrentDirEntry->ObjectInformation));
1323
1324                         AFSDeleteDirEntry( pCurrentObject,
1325                                            &pCurrentDirEntry);
1326
1327                         pCurrentDirEntry = pNextDirEntry;
1328                     }
1329
1330                     //
1331                     // Clear our enumerated flag on this object so we retrieve info again on next access
1332                     //
1333
1334                     ClearFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED);
1335
1336                     AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
1337                 }
1338             }
1339             else if ( bVolumeObject == FALSE)
1340             {
1341                 //
1342                 // No children
1343                 //
1344
1345                 if( pCurrentObject->ObjectReferenceCount > 1 ||
1346                     pCurrentObject->Fcb != NULL &&
1347                     pCurrentObject->Fcb->OpenReferenceCount > 0)
1348                 {
1349
1350                     try_return( ntStatus);
1351                 }
1352
1353                 AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
1354                                 TRUE);
1355
1356                 KeQueryTickCount( &liCurrentTime);
1357
1358                 if( pCurrentObject->ObjectReferenceCount == 1 &&
1359                     ( pCurrentObject->Fcb == NULL ||
1360                       pCurrentObject->Fcb->OpenReferenceCount == 0) &&
1361                     liCurrentTime.QuadPart > pCurrentObject->LastAccessCount.QuadPart &&
1362                     liCurrentTime.QuadPart - pCurrentObject->LastAccessCount.QuadPart >
1363                     pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
1364                 {
1365
1366                     AFSRemoveFcb( &pCurrentObject->Fcb);
1367
1368                     AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1369
1370                     lCount = AFSObjectInfoDecrement( pCurrentObject,
1371                                                      AFS_OBJECT_REFERENCE_WORKER);
1372
1373                     AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1374                                   AFS_TRACE_LEVEL_VERBOSE,
1375                                   "AFSExamineObjectInfo Decrement4 count on object %p Cnt %d\n",
1376                                   pCurrentObject,
1377                                   lCount));
1378
1379                     //
1380                     // The Volume TreeLock is held exclusive.  Therefore, the ObjectReferenceCount
1381                     // cannot change.  It is therefore safe to delete the ObjectInfoCB
1382                     //
1383
1384                     AFSDeleteObjectInfo( &pCurrentObject);
1385                 }
1386                 else
1387                 {
1388
1389                     AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1390                 }
1391             }
1392
1393             break;
1394         }
1395
1396         case AFS_FILE_TYPE_FILE:
1397         {
1398
1399             if( pCurrentObject->ObjectReferenceCount > 1 ||
1400                 pCurrentObject->Fcb != NULL &&
1401                 pCurrentObject->Fcb->OpenReferenceCount > 0)
1402             {
1403
1404                 try_return( ntStatus);
1405             }
1406
1407             if( pCurrentObject->Fcb != NULL)
1408             {
1409
1410                 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1411
1412                 //
1413                 // Dropping the VolumeCB TreeLock permits the
1414                 // pCurrentObject->ObjectReferenceCount to change.
1415                 // But it cannot be held across the AFSCleanupFcb
1416                 // call.
1417                 //
1418
1419                 ntStatus = AFSCleanupFcb( pCurrentObject->Fcb,
1420                                           FALSE);
1421
1422                 if (!AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1423                                      FALSE))
1424                 {
1425
1426                     *pbReleaseVolumeLock = FALSE;
1427                 }
1428
1429                 if ( ntStatus == STATUS_RETRY ||
1430                      *pbReleaseVolumeLock == FALSE)
1431                 {
1432
1433                     //
1434                     // The Fcb is in use.
1435                     //
1436
1437                     try_return( ntStatus);
1438                 }
1439             }
1440
1441             //
1442             // VolumeCB is held exclusive
1443             //
1444
1445             AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
1446                             TRUE);
1447
1448             KeQueryTickCount( &liCurrentTime);
1449
1450             if( pCurrentObject->ObjectReferenceCount == 1 &&
1451                 ( pCurrentObject->Fcb == NULL ||
1452                   ( pCurrentObject->Fcb->OpenReferenceCount == 0 &&
1453                     pCurrentObject->Fcb->Specific.File.ExtentsDirtyCount == 0)) &&
1454                 liCurrentTime.QuadPart > pCurrentObject->LastAccessCount.QuadPart &&
1455                 liCurrentTime.QuadPart - pCurrentObject->LastAccessCount.QuadPart >
1456                 pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
1457             {
1458
1459                 AFSRemoveFcb( &pCurrentObject->Fcb);
1460
1461                 AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1462
1463                 lCount = AFSObjectInfoDecrement( pCurrentObject,
1464                                                  AFS_OBJECT_REFERENCE_WORKER);
1465
1466                 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1467                               AFS_TRACE_LEVEL_VERBOSE,
1468                               "AFSExamineObjectInfo Decrement5 count on object %p Cnt %d\n",
1469                               pCurrentObject,
1470                               lCount));
1471
1472                 //
1473                 // The VolumeCB TreeLock is held exclusive so the
1474                 // ObjectReferenceCount cannot change.
1475                 //
1476
1477                 AFSDeleteObjectInfo( &pCurrentObject);
1478             }
1479             else
1480             {
1481
1482                 AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1483             }
1484
1485             break;
1486         }
1487
1488         default:
1489         {
1490
1491             AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
1492                             TRUE);
1493
1494             KeQueryTickCount( &liCurrentTime);
1495
1496             if( pCurrentObject->ObjectReferenceCount == 1 &&
1497                 ( pCurrentObject->Fcb == NULL ||
1498                   pCurrentObject->Fcb->OpenReferenceCount == 0) &&
1499                 liCurrentTime.QuadPart > pCurrentObject->LastAccessCount.QuadPart &&
1500                 liCurrentTime.QuadPart - pCurrentObject->LastAccessCount.QuadPart >
1501                 pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
1502             {
1503
1504                 AFSRemoveFcb( &pCurrentObject->Fcb);
1505
1506                 AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1507
1508                 lCount = AFSObjectInfoDecrement( pCurrentObject,
1509                                                  AFS_OBJECT_REFERENCE_WORKER);
1510
1511                 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1512                               AFS_TRACE_LEVEL_VERBOSE,
1513                               "AFSExamineObjectInfo Decrement6 count on object %p Cnt %d\n",
1514                               pCurrentObject,
1515                               lCount));
1516
1517                 //
1518                 // The VolumeCB TreeLock is held exclusive so the
1519                 // ObjectReferenceCount cannot change.
1520                 //
1521
1522                 AFSDeleteObjectInfo( &pCurrentObject);
1523             }
1524             else
1525             {
1526
1527                 AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
1528             }
1529         }
1530         }
1531
1532       try_exit:
1533
1534         if ( pCurrentObject != NULL)
1535         {
1536
1537             lCount = AFSObjectInfoDecrement( pCurrentObject,
1538                                              AFS_OBJECT_REFERENCE_WORKER);
1539
1540             AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1541                           AFS_TRACE_LEVEL_VERBOSE,
1542                           "AFSExamineObjectInfo Decrement count on object %p Cnt %d\n",
1543                           pCurrentObject,
1544                           lCount));
1545         }
1546     }
1547 }
1548
1549 //
1550 // Called with VolumeCB->VolumeLock held shared.
1551 //
1552
1553 static void
1554 AFSExamineVolume( IN AFSVolumeCB *pVolumeCB)
1555 {
1556     NTSTATUS ntStatus = STATUS_SUCCESS;
1557     AFSObjectInfoCB *pCurrentObject = NULL, *pNextObject = NULL;
1558     BOOLEAN bReleaseVolumeTreeLock = FALSE;
1559     BOOLEAN bVolumeObject = FALSE;
1560     LONG lCount;
1561
1562     //
1563     // The Volume ObjectInfoTree TreeLock must be held exclusive to
1564     // prevent other threads from obtaining a reference to an ObjectInfoCB
1565     // via AFSFindObjectInfo() while it is being deleted.  This is
1566     // annoying but the alternative is to hold the TreeLock shared during
1567     // garbage collection and exclusive during find operations.
1568     //
1569
1570     if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1571                         TRUE))
1572     {
1573
1574         bReleaseVolumeTreeLock = TRUE;
1575
1576         pCurrentObject = pVolumeCB->ObjectInfoListHead;
1577
1578         lCount = AFSObjectInfoIncrement( pCurrentObject,
1579                                          AFS_OBJECT_REFERENCE_WORKER);
1580
1581         AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1582                       AFS_TRACE_LEVEL_VERBOSE,
1583                       "AFSExamineVolume Increment count on object %p Cnt %d\n",
1584                       pCurrentObject,
1585                       lCount));
1586
1587         pNextObject = NULL;
1588
1589         while( pCurrentObject != NULL &&
1590                bReleaseVolumeTreeLock == TRUE)
1591         {
1592
1593             if( pCurrentObject != &pVolumeCB->ObjectInformation)
1594             {
1595
1596                 pNextObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1597
1598                 //
1599                 // If the end of the VolumeCB ObjectInfo List is reached, then
1600                 // the next ObjectInformationCB to examine is the one embedded within
1601                 // the VolumeCB itself except when the VolumeCB is the AFSGlobalRoot.
1602                 //
1603                 // bVolumeObject is used to indicate whether the embedded ObjectInfoCB
1604                 // is being examined.
1605                 //
1606
1607                 if( pNextObject == NULL &&
1608                     pVolumeCB != AFSGlobalRoot)  // Don't free up the root of the global
1609                 {
1610
1611                     pNextObject = &pVolumeCB->ObjectInformation;
1612                 }
1613
1614                 bVolumeObject = FALSE;
1615
1616                 if ( pNextObject)
1617                 {
1618
1619                     lCount = AFSObjectInfoIncrement( pNextObject,
1620                                                      AFS_OBJECT_REFERENCE_WORKER);
1621
1622                     AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1623                                   AFS_TRACE_LEVEL_VERBOSE,
1624                                   "AFSExamineVolume Increment count on object %p Cnt %d\n",
1625                                   pNextObject,
1626                                   lCount));
1627                 }
1628             }
1629             else
1630             {
1631
1632                 pNextObject = NULL;
1633
1634                 bVolumeObject = TRUE;
1635             }
1636
1637             AFSExamineObjectInfo( pCurrentObject, bVolumeObject, &bReleaseVolumeTreeLock);
1638
1639             if ( bReleaseVolumeTreeLock == TRUE &&
1640                  ( ExGetExclusiveWaiterCount( pVolumeCB->ObjectInfoTree.TreeLock) > 0 ||
1641                    ExGetSharedWaiterCount( pVolumeCB->ObjectInfoTree.TreeLock) > 0))
1642             {
1643
1644                 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1645
1646                 bReleaseVolumeTreeLock = FALSE;
1647             }
1648             //
1649             // The CurrentObject is either destroyed or the reference count has been
1650             // dropped by AFSExamineObjectInfo().
1651             //
1652
1653             if ( bReleaseVolumeTreeLock == FALSE)
1654             {
1655
1656                 //
1657                 // Try to obtain the Volume's ObjectInfoTree.TreeLock after dropping
1658                 // other locks and continue.
1659                 //
1660
1661                 bReleaseVolumeTreeLock = AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1662                                                          TRUE);
1663             }
1664
1665             pCurrentObject = pNextObject;
1666
1667             pNextObject = NULL;
1668         }
1669
1670         if ( pCurrentObject != NULL)
1671         {
1672
1673             lCount = AFSObjectInfoDecrement( pCurrentObject,
1674                                              AFS_OBJECT_REFERENCE_WORKER);
1675
1676             AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1677                           AFS_TRACE_LEVEL_VERBOSE,
1678                           "AFSExamineVolume Decrement count on object %p Cnt %d\n",
1679                           pCurrentObject,
1680                           lCount));
1681         }
1682
1683         if( bReleaseVolumeTreeLock)
1684         {
1685
1686             AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1687         }
1688     }
1689 }
1690
1691 void
1692 AFSPrimaryVolumeWorkerThread( IN PVOID Context)
1693 {
1694
1695     UNREFERENCED_PARAMETER(Context);
1696     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)&AFSGlobalRoot->NonPagedVcb->VolumeWorkerContext;
1697     AFSDeviceExt *pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1698     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1699     LARGE_INTEGER DueTime;
1700     LONG TimeOut;
1701     KTIMER Timer;
1702     AFSVolumeCB *pVolumeCB = NULL, *pNextVolume = NULL;
1703     LONG lCount;
1704
1705     AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1706                   AFS_TRACE_LEVEL_VERBOSE,
1707                   "AFSPrimaryVolumeWorkerThread Initialized\n"));
1708
1709     //
1710     // Initialize the timer for the worker thread
1711     //
1712
1713     DueTime.QuadPart = -(5000);
1714
1715     TimeOut = 5000;
1716
1717     KeInitializeTimerEx( &Timer,
1718                          SynchronizationTimer);
1719
1720     KeSetTimerEx( &Timer,
1721                   DueTime,
1722                   TimeOut,
1723                   NULL);
1724
1725     //
1726     // Indicate that we are initialized and ready
1727     //
1728
1729     KeSetEvent( &pPoolContext->WorkerThreadReady,
1730                 0,
1731                 FALSE);
1732
1733     //
1734     // Indicate we are initialized
1735     //
1736
1737     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
1738
1739     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
1740     {
1741
1742         KeWaitForSingleObject( &Timer,
1743                                Executive,
1744                                KernelMode,
1745                                FALSE,
1746                                NULL);
1747
1748         //
1749         // This is the primary volume worker so it will traverse the volume list
1750         // looking for cleanup or volumes requiring private workers
1751         //
1752
1753         AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1754                           TRUE);
1755
1756         pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead;
1757
1758         while( pVolumeCB != NULL)
1759         {
1760
1761             if( pVolumeCB == AFSGlobalRoot ||
1762                 !AFSAcquireExcl( pVolumeCB->VolumeLock,
1763                                  FALSE))
1764             {
1765
1766                 pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1767
1768                 continue;
1769             }
1770
1771             if( pVolumeCB->ObjectInfoListHead == NULL)
1772             {
1773
1774                 AFSReleaseResource( pVolumeCB->VolumeLock);
1775
1776                 AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1777
1778                 AFSAcquireExcl( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock,
1779                                 TRUE);
1780
1781                 AFSAcquireExcl( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1782                                 TRUE);
1783
1784                 if( !AFSAcquireExcl( pVolumeCB->VolumeLock,
1785                                      FALSE))
1786                 {
1787
1788                     AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1789
1790                     AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
1791
1792                     pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1793
1794                     continue;
1795                 }
1796
1797                 pNextVolume = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1798
1799                 AFSAcquireExcl( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock,
1800                                 TRUE);
1801
1802                 //
1803                 // If VolumeCB is idle, the Volume can be garbage collected
1804                 //
1805
1806                 if( pVolumeCB->ObjectInfoListHead == NULL &&
1807                     pVolumeCB->DirectoryCB->DirOpenReferenceCount <= 0 &&
1808                     pVolumeCB->DirectoryCB->NameArrayReferenceCount <= 0 &&
1809                     pVolumeCB->VolumeReferenceCount == 0 &&
1810                     ( pVolumeCB->RootFcb == NULL ||
1811                       pVolumeCB->RootFcb->OpenReferenceCount == 0) &&
1812                     pVolumeCB->ObjectInformation.ObjectReferenceCount <= 0)
1813                 {
1814
1815                     AFSRemoveRootFcb( pVolumeCB);
1816
1817                     AFSReleaseResource( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
1818
1819                     AFSRemoveVolume( pVolumeCB);
1820                 }
1821                 else
1822                 {
1823
1824                     AFSReleaseResource( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
1825
1826                     AFSReleaseResource( pVolumeCB->VolumeLock);
1827                 }
1828
1829                 AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1830
1831                 AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
1832
1833                 pVolumeCB = pNextVolume;
1834
1835                 continue;
1836             }
1837
1838             //
1839             // Don't need this lock anymore now that we have a volume cb to work with
1840             //
1841
1842             AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1843
1844             //
1845             // For now we only need the volume lock shared
1846             //
1847
1848             AFSConvertToShared( pVolumeCB->VolumeLock);
1849
1850             AFSExamineVolume( pVolumeCB);
1851
1852             //
1853             // Next volume cb
1854             //
1855
1856             AFSReleaseResource( pVolumeCB->VolumeLock);
1857
1858             AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1859                               TRUE);
1860
1861             pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1862         }
1863
1864         AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1865
1866     } // worker thread loop
1867
1868     KeCancelTimer( &Timer);
1869
1870     ClearFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
1871
1872     AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1873                   AFS_TRACE_LEVEL_VERBOSE,
1874                   "AFSPrimaryVolumeWorkerThread Exiting\n"));
1875
1876     lCount = InterlockedDecrement( &pControlDeviceExt->Specific.Control.VolumeWorkerThreadCount);
1877
1878     if( lCount == 0)
1879     {
1880
1881         KeSetEvent( &pControlDeviceExt->Specific.Control.VolumeWorkerCloseEvent,
1882                     0,
1883                     FALSE);
1884     }
1885
1886     PsTerminateSystemThread( 0);
1887
1888     return;
1889 }
1890
1891 NTSTATUS
1892 AFSInsertWorkitem( IN AFSWorkItem *WorkItem)
1893 {
1894
1895     NTSTATUS ntStatus = STATUS_SUCCESS;
1896     AFSDeviceExt *pControlDevExt = NULL;
1897     LONG lCount;
1898
1899     pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1900
1901     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1902                   AFS_TRACE_LEVEL_VERBOSE,
1903                   "AFSInsertWorkitem Acquiring Control QueueLock lock %p EXCL %08lX\n",
1904                   &pControlDevExt->Specific.Control.QueueLock,
1905                   PsGetCurrentThread()));
1906
1907     AFSAcquireExcl( &pControlDevExt->Specific.Control.QueueLock,
1908                     TRUE);
1909
1910     lCount = InterlockedIncrement( &pControlDevExt->Specific.Control.QueueItemCount);
1911
1912     AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
1913                   AFS_TRACE_LEVEL_VERBOSE,
1914                   "AFSInsertWorkitem Inserting work item %p Count %d\n",
1915                   WorkItem,
1916                   lCount));
1917
1918     if( pControlDevExt->Specific.Control.QueueTail != NULL) // queue already has nodes
1919     {
1920
1921         pControlDevExt->Specific.Control.QueueTail->next = WorkItem;
1922     }
1923     else // first node
1924     {
1925
1926         pControlDevExt->Specific.Control.QueueHead = WorkItem;
1927     }
1928
1929     WorkItem->next = NULL;
1930     pControlDevExt->Specific.Control.QueueTail = WorkItem;
1931
1932     // indicate that the queue has nodes
1933     KeSetEvent( &(pControlDevExt->Specific.Control.WorkerQueueHasItems),
1934                 0,
1935                 FALSE);
1936
1937     AFSReleaseResource( &pControlDevExt->Specific.Control.QueueLock);
1938
1939     return ntStatus;
1940 }
1941
1942 NTSTATUS
1943 AFSInsertIOWorkitem( IN AFSWorkItem *WorkItem)
1944 {
1945
1946     NTSTATUS ntStatus = STATUS_SUCCESS;
1947     AFSDeviceExt *pControlDevExt = NULL;
1948     LONG lCount;
1949
1950     pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1951
1952     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1953                   AFS_TRACE_LEVEL_VERBOSE,
1954                   "AFSInsertIOWorkitem Acquiring Control QueueLock lock %p EXCL %08lX\n",
1955                   &pControlDevExt->Specific.Control.IOQueueLock,
1956                   PsGetCurrentThread()));
1957
1958     AFSAcquireExcl( &pControlDevExt->Specific.Control.IOQueueLock,
1959                     TRUE);
1960
1961     lCount = InterlockedIncrement( &pControlDevExt->Specific.Control.IOQueueItemCount);
1962
1963     AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
1964                   AFS_TRACE_LEVEL_VERBOSE,
1965                   "AFSInsertWorkitem Inserting IO work item %p Count %d\n",
1966                   WorkItem,
1967                   lCount));
1968
1969     if( pControlDevExt->Specific.Control.IOQueueTail != NULL) // queue already has nodes
1970     {
1971
1972         pControlDevExt->Specific.Control.IOQueueTail->next = WorkItem;
1973     }
1974     else // first node
1975     {
1976
1977         pControlDevExt->Specific.Control.IOQueueHead = WorkItem;
1978     }
1979
1980     WorkItem->next = NULL;
1981     pControlDevExt->Specific.Control.IOQueueTail = WorkItem;
1982
1983     // indicate that the queue has nodes
1984     KeSetEvent( &(pControlDevExt->Specific.Control.IOWorkerQueueHasItems),
1985                 0,
1986                 FALSE);
1987
1988     AFSReleaseResource( &pControlDevExt->Specific.Control.IOQueueLock);
1989
1990     return ntStatus;
1991 }
1992
1993 NTSTATUS
1994 AFSInsertWorkitemAtHead( IN AFSWorkItem *WorkItem)
1995 {
1996
1997     NTSTATUS ntStatus = STATUS_SUCCESS;
1998     AFSDeviceExt *pControlDevExt = NULL;
1999     LONG lCount;
2000
2001     pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2002
2003     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
2004                   AFS_TRACE_LEVEL_VERBOSE,
2005                   "AFSInsertWorkitemAtHead Acquiring Control QueueLock lock %p EXCL %08lX\n",
2006                   &pControlDevExt->Specific.Control.QueueLock,
2007                   PsGetCurrentThread()));
2008
2009     AFSAcquireExcl( &pControlDevExt->Specific.Control.QueueLock,
2010                     TRUE);
2011
2012     WorkItem->next = pControlDevExt->Specific.Control.QueueHead;
2013
2014     pControlDevExt->Specific.Control.QueueHead = WorkItem;
2015
2016     lCount = InterlockedIncrement( &pControlDevExt->Specific.Control.QueueItemCount);
2017
2018     AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2019                   AFS_TRACE_LEVEL_VERBOSE,
2020                   "AFSInsertWorkitemAtHead Inserting work item %p Count %d\n",
2021                   WorkItem,
2022                   lCount));
2023
2024     //
2025     // indicate that the queue has nodes
2026     //
2027
2028     KeSetEvent( &(pControlDevExt->Specific.Control.WorkerQueueHasItems),
2029                 0,
2030                 FALSE);
2031
2032     AFSReleaseResource( &pControlDevExt->Specific.Control.QueueLock);
2033
2034     return ntStatus;
2035 }
2036
2037 AFSWorkItem *
2038 AFSRemoveWorkItem()
2039 {
2040
2041     AFSWorkItem        *pWorkItem = NULL;
2042     AFSDeviceExt *pControlDevExt = NULL;
2043     LONG lCount;
2044
2045     pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2046
2047     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
2048                   AFS_TRACE_LEVEL_VERBOSE,
2049                   "AFSRemoveWorkItem Acquiring Control QueueLock lock %p EXCL %08lX\n",
2050                   &pControlDevExt->Specific.Control.QueueLock,
2051                   PsGetCurrentThread()));
2052
2053     AFSAcquireExcl( &pControlDevExt->Specific.Control.QueueLock,
2054                     TRUE);
2055
2056     if( pControlDevExt->Specific.Control.QueueHead != NULL) // queue has nodes
2057     {
2058
2059         pWorkItem = pControlDevExt->Specific.Control.QueueHead;
2060
2061         lCount = InterlockedDecrement( &pControlDevExt->Specific.Control.QueueItemCount);
2062
2063         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2064                       AFS_TRACE_LEVEL_VERBOSE,
2065                       "AFSRemoveWorkItem Removing work item %p Count %d Thread %08lX\n",
2066                       pWorkItem,
2067                       lCount,
2068                       PsGetCurrentThreadId()));
2069
2070         pControlDevExt->Specific.Control.QueueHead = pControlDevExt->Specific.Control.QueueHead->next;
2071
2072         if( pControlDevExt->Specific.Control.QueueHead == NULL) // if queue just became empty
2073         {
2074
2075             pControlDevExt->Specific.Control.QueueTail = NULL;
2076         }
2077         else
2078         {
2079
2080             //
2081             // Wake up another worker
2082             //
2083
2084             KeSetEvent( &(pControlDevExt->Specific.Control.WorkerQueueHasItems),
2085                         0,
2086                         FALSE);
2087         }
2088     }
2089
2090     AFSReleaseResource( &pControlDevExt->Specific.Control.QueueLock);
2091
2092     return pWorkItem;
2093 }
2094
2095 AFSWorkItem *
2096 AFSRemoveIOWorkItem()
2097 {
2098
2099     AFSWorkItem        *pWorkItem = NULL;
2100     AFSDeviceExt *pControlDevExt = NULL;
2101     LONG lCount;
2102
2103     pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2104
2105     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
2106                   AFS_TRACE_LEVEL_VERBOSE,
2107                   "AFSRemoveIOWorkItem Acquiring Control QueueLock lock %p EXCL %08lX\n",
2108                   &pControlDevExt->Specific.Control.IOQueueLock,
2109                   PsGetCurrentThread()));
2110
2111     AFSAcquireExcl( &pControlDevExt->Specific.Control.IOQueueLock,
2112                     TRUE);
2113
2114     if( pControlDevExt->Specific.Control.IOQueueHead != NULL) // queue has nodes
2115     {
2116
2117         pWorkItem = pControlDevExt->Specific.Control.IOQueueHead;
2118
2119         lCount = InterlockedDecrement( &pControlDevExt->Specific.Control.IOQueueItemCount);
2120
2121         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2122                       AFS_TRACE_LEVEL_VERBOSE,
2123                       "AFSRemoveWorkItem Removing work item %p Count %d Thread %08lX\n",
2124                       pWorkItem,
2125                       lCount,
2126                       PsGetCurrentThreadId()));
2127
2128         pControlDevExt->Specific.Control.IOQueueHead = pControlDevExt->Specific.Control.IOQueueHead->next;
2129
2130         if( pControlDevExt->Specific.Control.IOQueueHead == NULL) // if queue just became empty
2131         {
2132
2133             pControlDevExt->Specific.Control.IOQueueTail = NULL;
2134         }
2135         else
2136         {
2137
2138             //
2139             // Wake up another worker
2140             //
2141
2142             KeSetEvent( &(pControlDevExt->Specific.Control.IOWorkerQueueHasItems),
2143                         0,
2144                         FALSE);
2145         }
2146     }
2147
2148     AFSReleaseResource( &pControlDevExt->Specific.Control.IOQueueLock);
2149
2150     return pWorkItem;
2151 }
2152
2153 NTSTATUS
2154 AFSQueueWorkerRequest( IN AFSWorkItem *WorkItem)
2155 {
2156
2157     NTSTATUS ntStatus = STATUS_SUCCESS;
2158     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
2159
2160     //
2161     // Submit the work item to the worker
2162     //
2163
2164     ntStatus = AFSInsertWorkitem( WorkItem);
2165
2166     if( bWait)
2167     {
2168
2169         //
2170         // Sync request so block on the work item event
2171         //
2172
2173         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2174                                           Executive,
2175                                           KernelMode,
2176                                           FALSE,
2177                                           NULL);
2178     }
2179
2180     return ntStatus;
2181 }
2182
2183 NTSTATUS
2184 AFSQueueIOWorkerRequest( IN AFSWorkItem *WorkItem)
2185 {
2186
2187     NTSTATUS ntStatus = STATUS_SUCCESS;
2188     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
2189
2190     //
2191     // Submit the work item to the worker
2192     //
2193
2194     ntStatus = AFSInsertIOWorkitem( WorkItem);
2195
2196     if( bWait)
2197     {
2198
2199         //
2200         // Sync request so block on the work item event
2201         //
2202
2203         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2204                                           Executive,
2205                                           KernelMode,
2206                                           FALSE,
2207                                           NULL);
2208     }
2209
2210     return ntStatus;
2211 }
2212
2213 NTSTATUS
2214 AFSQueueWorkerRequestAtHead( IN AFSWorkItem *WorkItem)
2215 {
2216
2217     NTSTATUS ntStatus = STATUS_SUCCESS;
2218     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
2219
2220     //
2221     // Submit the work item to the worker
2222     //
2223
2224     ntStatus = AFSInsertWorkitemAtHead( WorkItem);
2225
2226     if( bWait)
2227     {
2228
2229         //
2230         // Sync request so block on the work item event
2231         //
2232
2233         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2234                                           Executive,
2235                                           KernelMode,
2236                                           FALSE,
2237                                           NULL);
2238     }
2239
2240     return ntStatus;
2241 }
2242
2243 NTSTATUS
2244 AFSQueueFlushExtents( IN AFSFcb *Fcb,
2245                       IN GUID *AuthGroup)
2246 {
2247
2248     NTSTATUS ntStatus = STATUS_SUCCESS;
2249     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
2250     AFSWorkItem *pWorkItem = NULL;
2251     LONG lCount;
2252
2253     __try
2254     {
2255
2256         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2257                       AFS_TRACE_LEVEL_VERBOSE,
2258                       "AFSQueueFlushExtents Queuing request for FID %08lX-%08lX-%08lX-%08lX\n",
2259                       Fcb->ObjectInformation->FileId.Cell,
2260                       Fcb->ObjectInformation->FileId.Volume,
2261                       Fcb->ObjectInformation->FileId.Vnode,
2262                       Fcb->ObjectInformation->FileId.Unique));
2263
2264         //
2265         // Increment our flush count here just to keep the number of items in the
2266         // queue down. We'll decrement it just below.
2267         //
2268
2269         lCount = InterlockedIncrement( &Fcb->Specific.File.QueuedFlushCount);
2270
2271         if( lCount > 3)
2272         {
2273
2274             AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2275                           AFS_TRACE_LEVEL_VERBOSE,
2276                           "AFSQueueFlushExtents Max queued items for FID %08lX-%08lX-%08lX-%08lX\n",
2277                           Fcb->ObjectInformation->FileId.Cell,
2278                           Fcb->ObjectInformation->FileId.Volume,
2279                           Fcb->ObjectInformation->FileId.Vnode,
2280                           Fcb->ObjectInformation->FileId.Unique));
2281
2282             try_return( ntStatus);
2283         }
2284
2285         if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
2286         {
2287
2288             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2289                           AFS_TRACE_LEVEL_ERROR,
2290                           "AFSQueueFlushExtents Failing request, in shutdown\n"));
2291
2292             try_return( ntStatus = STATUS_TOO_LATE);
2293         }
2294
2295         //
2296         // Allocate our request structure and send it to the worker
2297         //
2298
2299         pWorkItem = (AFSWorkItem *)AFSExAllocatePoolWithTag( NonPagedPool,
2300                                                              sizeof( AFSWorkItem),
2301                                                              AFS_WORK_ITEM_TAG);
2302
2303         if( pWorkItem == NULL)
2304         {
2305
2306             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2307                           AFS_TRACE_LEVEL_ERROR,
2308                           "AFSQueueFlushExtents Failed to allocate work item\n"));
2309
2310             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2311         }
2312
2313         RtlZeroMemory( pWorkItem,
2314                        sizeof( AFSWorkItem));
2315
2316         pWorkItem->Size = sizeof( AFSWorkItem);
2317
2318         pWorkItem->ProcessID = (ULONGLONG)PsGetCurrentProcessId();
2319
2320         pWorkItem->RequestType = AFS_WORK_FLUSH_FCB;
2321
2322         if ( AuthGroup == NULL)
2323         {
2324
2325             RtlZeroMemory( &pWorkItem->AuthGroup,
2326                            sizeof( GUID));
2327
2328             ntStatus = AFSRetrieveValidAuthGroup( Fcb,
2329                                                   NULL,
2330                                                   TRUE,
2331                                                   &pWorkItem->AuthGroup);
2332         }
2333         else
2334         {
2335             RtlCopyMemory( &pWorkItem->AuthGroup,
2336                            AuthGroup,
2337                            sizeof( GUID));
2338         }
2339
2340         pWorkItem->Specific.Fcb.Fcb = Fcb;
2341
2342         lCount = InterlockedIncrement( &Fcb->OpenReferenceCount);
2343
2344         AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
2345                       AFS_TRACE_LEVEL_VERBOSE,
2346                       "AFSQueueFlushExtents Increment count on Fcb %p Cnt %d\n",
2347                       Fcb,
2348                       lCount));
2349
2350         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2351                       AFS_TRACE_LEVEL_VERBOSE,
2352                       "AFSQueueFlushExtents Workitem %p for FID %08lX-%08lX-%08lX-%08lX\n",
2353                       pWorkItem,
2354                       Fcb->ObjectInformation->FileId.Cell,
2355                       Fcb->ObjectInformation->FileId.Volume,
2356                       Fcb->ObjectInformation->FileId.Vnode,
2357                       Fcb->ObjectInformation->FileId.Unique));
2358
2359         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2360
2361 try_exit:
2362
2363         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2364                       AFS_TRACE_LEVEL_VERBOSE,
2365                       "AFSQueueFlushExtents Request complete Status %08lX FID %08lX-%08lX-%08lX-%08lX\n",
2366                       Fcb->ObjectInformation->FileId.Cell,
2367                       Fcb->ObjectInformation->FileId.Volume,
2368                       Fcb->ObjectInformation->FileId.Vnode,
2369                       Fcb->ObjectInformation->FileId.Unique,
2370                       ntStatus));
2371
2372         //
2373         // Remove the count we added above
2374         //
2375
2376         lCount = InterlockedDecrement( &Fcb->Specific.File.QueuedFlushCount);
2377
2378         ASSERT( lCount >= 0);
2379
2380         if( lCount == 0)
2381         {
2382
2383             KeSetEvent( &Fcb->NPFcb->Specific.File.QueuedFlushEvent,
2384                         0,
2385                         FALSE);
2386         }
2387
2388         if( !NT_SUCCESS( ntStatus))
2389         {
2390
2391             if( pWorkItem != NULL)
2392             {
2393
2394                 lCount = InterlockedDecrement( &Fcb->OpenReferenceCount);
2395
2396                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2397             }
2398
2399             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2400                           AFS_TRACE_LEVEL_ERROR,
2401                           "AFSQueueFlushExtents Failed to queue request Status %08lX\n",
2402                           ntStatus));
2403         }
2404     }
2405     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2406     {
2407
2408         AFSDbgTrace(( 0,
2409                       0,
2410                       "EXCEPTION - AFSQueueFlushExtents\n"));
2411
2412         AFSDumpTraceFilesFnc();
2413     }
2414
2415     return ntStatus;
2416 }
2417
2418 NTSTATUS
2419 AFSQueueGlobalRootEnumeration()
2420 {
2421
2422     NTSTATUS ntStatus = STATUS_SUCCESS;
2423     AFSWorkItem *pWorkItem = NULL;
2424
2425     __try
2426     {
2427
2428         pWorkItem = (AFSWorkItem *) AFSExAllocatePoolWithTag( NonPagedPool,
2429                                                               sizeof(AFSWorkItem),
2430                                                               AFS_WORK_ITEM_TAG);
2431         if (NULL == pWorkItem)
2432         {
2433
2434             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
2435                           AFS_TRACE_LEVEL_ERROR,
2436                           "AFSQueueGlobalRootEnumeration Failed to allocate work item\n"));
2437
2438             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2439         }
2440
2441         RtlZeroMemory( pWorkItem,
2442                        sizeof(AFSWorkItem));
2443
2444         pWorkItem->Size = sizeof( AFSWorkItem);
2445
2446         pWorkItem->RequestType = AFS_WORK_ENUMERATE_GLOBAL_ROOT;
2447
2448         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2449                       AFS_TRACE_LEVEL_VERBOSE,
2450                       "AFSQueueGlobalRootEnumeration Workitem %p\n",
2451                       pWorkItem));
2452
2453         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2454
2455 try_exit:
2456
2457         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2458                       AFS_TRACE_LEVEL_VERBOSE,
2459                       "AFSQueueGlobalRootEnumeration Request complete Status %08lX\n",
2460                       ntStatus));
2461
2462         if( !NT_SUCCESS( ntStatus))
2463         {
2464
2465             if( pWorkItem != NULL)
2466             {
2467
2468                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2469             }
2470
2471             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2472                           AFS_TRACE_LEVEL_ERROR,
2473                           "AFSQueueGlobalRootEnumeration Failed to queue request Status %08lX\n",
2474                           ntStatus));
2475         }
2476     }
2477     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2478     {
2479
2480         AFSDbgTrace(( 0,
2481                       0,
2482                       "EXCEPTION - AFSQueueGlobalRootEnumeration\n"));
2483
2484         AFSDumpTraceFilesFnc();
2485     }
2486
2487     return ntStatus;
2488 }
2489
2490 NTSTATUS
2491 AFSQueueStartIos( IN PFILE_OBJECT CacheFileObject,
2492                   IN UCHAR FunctionCode,
2493                   IN ULONG RequestFlags,
2494                   IN AFSIoRun *IoRuns,
2495                   IN ULONG RunCount,
2496                   IN AFSGatherIo *GatherIo)
2497 {
2498
2499     NTSTATUS ntStatus = STATUS_SUCCESS;
2500     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
2501     AFSWorkItem *pWorkItem = NULL;
2502
2503     __try
2504     {
2505
2506         if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
2507         {
2508
2509             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2510                           AFS_TRACE_LEVEL_ERROR,
2511                           "AFSQueueStartIos Failing request, in shutdown\n"));
2512
2513             try_return( ntStatus = STATUS_TOO_LATE);
2514         }
2515
2516         //
2517         // Allocate our request structure and send it to the worker
2518         //
2519
2520         pWorkItem = (AFSWorkItem *)AFSExAllocatePoolWithTag( NonPagedPool,
2521                                                              sizeof( AFSWorkItem),
2522                                                              AFS_WORK_ITEM_TAG);
2523
2524         if( pWorkItem == NULL)
2525         {
2526
2527             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2528                           AFS_TRACE_LEVEL_ERROR,
2529                           "AFSQueueStartIos Failed to allocate work item\n"));
2530
2531             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2532         }
2533
2534         RtlZeroMemory( pWorkItem,
2535                        sizeof( AFSWorkItem));
2536
2537         KeInitializeEvent( &pWorkItem->Event,
2538                            NotificationEvent,
2539                            FALSE);
2540
2541         pWorkItem->Size = sizeof( AFSWorkItem);
2542
2543         pWorkItem->ProcessID = (ULONGLONG)PsGetCurrentProcessId();
2544
2545         pWorkItem->RequestType = AFS_WORK_START_IOS;
2546
2547         pWorkItem->Specific.CacheAccess.CacheFileObject = CacheFileObject;
2548
2549         pWorkItem->Specific.CacheAccess.FunctionCode = FunctionCode;
2550
2551         pWorkItem->Specific.CacheAccess.RequestFlags = RequestFlags;
2552
2553         pWorkItem->Specific.CacheAccess.IoRuns = IoRuns;
2554
2555         pWorkItem->Specific.CacheAccess.RunCount = RunCount;
2556
2557         pWorkItem->Specific.CacheAccess.GatherIo = GatherIo;
2558
2559         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2560                       AFS_TRACE_LEVEL_VERBOSE,
2561                       "AFSQueueStartIos Queuing IO Workitem %p\n",
2562                       pWorkItem));
2563
2564         ntStatus = AFSQueueIOWorkerRequest( pWorkItem);
2565
2566 try_exit:
2567
2568         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2569                       AFS_TRACE_LEVEL_VERBOSE,
2570                       "AFSQueueStartIos Request complete Status %08lX\n",
2571                       ntStatus));
2572
2573         if( !NT_SUCCESS( ntStatus))
2574         {
2575
2576             if( pWorkItem != NULL)
2577             {
2578
2579                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2580             }
2581         }
2582     }
2583     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2584     {
2585
2586         AFSDbgTrace(( 0,
2587                       0,
2588                       "EXCEPTION - AFSQueueStartIos\n"));
2589
2590         AFSDumpTraceFilesFnc();
2591     }
2592
2593     return ntStatus;
2594 }
2595
2596 NTSTATUS
2597 AFSQueueInvalidateObject( IN AFSObjectInfoCB *ObjectInfo,
2598                           IN ULONG InvalidateReason)
2599 {
2600
2601     NTSTATUS ntStatus = STATUS_SUCCESS;
2602     AFSWorkItem *pWorkItem = NULL;
2603
2604     __try
2605     {
2606
2607         pWorkItem = (AFSWorkItem *) AFSExAllocatePoolWithTag( NonPagedPool,
2608                                                               sizeof(AFSWorkItem),
2609                                                               AFS_WORK_ITEM_TAG);
2610         if (NULL == pWorkItem)
2611         {
2612
2613             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
2614                           AFS_TRACE_LEVEL_ERROR,
2615                           "AFSQueueInvalidateObject Failed to allocate work item\n"));
2616
2617             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2618         }
2619
2620         RtlZeroMemory( pWorkItem,
2621                        sizeof(AFSWorkItem));
2622
2623         pWorkItem->Size = sizeof( AFSWorkItem);
2624
2625         pWorkItem->RequestType = AFS_WORK_INVALIDATE_OBJECT;
2626
2627         pWorkItem->Specific.Invalidate.ObjectInfo = ObjectInfo;
2628
2629         pWorkItem->Specific.Invalidate.InvalidateReason = InvalidateReason;
2630
2631         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2632                       AFS_TRACE_LEVEL_VERBOSE,
2633                       "AFSQueueInvalidateObject Workitem %p\n",
2634                       pWorkItem));
2635
2636         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2637
2638 try_exit:
2639
2640         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2641                       AFS_TRACE_LEVEL_VERBOSE,
2642                       "AFSQueueInvalidateObject Request complete Status %08lX\n",
2643                       ntStatus));
2644
2645         if( !NT_SUCCESS( ntStatus))
2646         {
2647
2648             if( pWorkItem != NULL)
2649             {
2650                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2651             }
2652
2653             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2654                           AFS_TRACE_LEVEL_ERROR,
2655                           "AFSQueueInvalidateObject Failed to queue request Status %08lX\n",
2656                           ntStatus));
2657         }
2658     }
2659     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2660     {
2661
2662         AFSDbgTrace(( 0,
2663                       0,
2664                       "EXCEPTION - AFSQueueInvalidateObject\n"));
2665
2666         AFSDumpTraceFilesFnc();
2667     }
2668
2669     return ntStatus;
2670 }
2671
2672 NTSTATUS
2673 AFSDeferWrite( IN PDEVICE_OBJECT DeviceObject,
2674                IN PFILE_OBJECT FileObject,
2675                IN HANDLE CallingUser,
2676                IN PIRP Irp,
2677                IN ULONG BytesToWrite,
2678                IN BOOLEAN bRetrying)
2679 {
2680     NTSTATUS ntStatus = STATUS_SUCCESS;
2681     AFSWorkItem *pWorkItem = NULL;
2682
2683     __try
2684     {
2685
2686         //
2687         // Pin the user buffer (first time round only - AFSLockSystemBuffer is
2688         // idempotent)
2689         //
2690
2691         if ( NULL == AFSLockSystemBuffer( Irp, BytesToWrite ))
2692         {
2693
2694             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
2695                           AFS_TRACE_LEVEL_ERROR,
2696                           "%s Could not pin user memory item\n",
2697                           __FUNCTION__));
2698
2699             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2700         }
2701
2702         pWorkItem = (AFSWorkItem *) AFSExAllocatePoolWithTag( NonPagedPool,
2703                                                               sizeof(AFSWorkItem),
2704                                                               AFS_WORK_ITEM_TAG);
2705
2706         if (NULL == pWorkItem)
2707         {
2708
2709             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
2710                           AFS_TRACE_LEVEL_ERROR,
2711                           "%s Failed to allocate work item\n",
2712                           __FUNCTION__));
2713
2714             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2715         }
2716
2717         RtlZeroMemory( pWorkItem,
2718                        sizeof(AFSWorkItem));
2719
2720         pWorkItem->Size = sizeof( AFSWorkItem);
2721
2722         pWorkItem->RequestType = AFS_WORK_DEFERRED_WRITE;
2723
2724         pWorkItem->Specific.AsynchIo.CallingProcess = CallingUser;
2725
2726         pWorkItem->Specific.AsynchIo.Device = DeviceObject;
2727
2728         pWorkItem->Specific.AsynchIo.Irp = Irp;
2729
2730         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING | AFS_SUBSYSTEM_WORKER_PROCESSING,
2731                       AFS_TRACE_LEVEL_VERBOSE,
2732                       "%s Workitem %p\n",
2733                       __FUNCTION__,
2734                       pWorkItem));
2735
2736         CcDeferWrite( FileObject, AFSPostedDeferredWrite, pWorkItem, NULL, BytesToWrite, bRetrying);
2737
2738         IoMarkIrpPending(Irp);
2739
2740         ntStatus = STATUS_PENDING;
2741     }
2742     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2743     {
2744
2745         AFSDbgTrace(( 0,
2746                       0,
2747                       "EXCEPTION - %s \n",
2748                       __FUNCTION__));
2749
2750         ntStatus = GetExceptionCode();
2751     }
2752
2753 try_exit:
2754
2755     AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2756                   AFS_TRACE_LEVEL_VERBOSE,
2757                   "%s complete Status %08lX\n",
2758                   __FUNCTION__,
2759                   ntStatus));
2760
2761     if( !NT_SUCCESS( ntStatus))
2762     {
2763
2764         if( pWorkItem != NULL)
2765         {
2766
2767             ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2768         }
2769
2770         AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2771                       AFS_TRACE_LEVEL_ERROR,
2772                       "%s Failed to queue request Status %08lX\n",
2773                       __FUNCTION__,
2774                       ntStatus));
2775     }
2776
2777     return ntStatus;
2778 }
2779
2780 static
2781 VOID
2782 AFSPostedDeferredWrite( IN PVOID Context1,
2783                         IN PVOID Context2)
2784 {
2785     UNREFERENCED_PARAMETER( Context2);
2786     NTSTATUS ntStatus;
2787
2788     AFSWorkItem *pWorkItem = (AFSWorkItem *) Context1;
2789
2790     AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING | AFS_SUBSYSTEM_WORKER_PROCESSING,
2791                   AFS_TRACE_LEVEL_ERROR,
2792                   "%s Workitem %p\n",
2793                   __FUNCTION__,
2794                   pWorkItem));
2795
2796     ntStatus = AFSQueueIOWorkerRequest( pWorkItem);
2797
2798     if (!NT_SUCCESS( ntStatus))
2799     {
2800
2801         AFSCompleteRequest( pWorkItem->Specific.AsynchIo.Irp, ntStatus);
2802
2803         ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2804
2805         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING | AFS_SUBSYSTEM_WORKER_PROCESSING,
2806                       AFS_TRACE_LEVEL_ERROR,
2807                       "%s (%p) Failed to queue request Status %08lX\n",
2808                       __FUNCTION__,
2809                       pWorkItem->Specific.AsynchIo.Irp,
2810                       ntStatus));
2811     }
2812 }