2310268e549afdb7b691527b96fd5e717e148fe6
[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             //
1640             // The CurrentObject is either destroyed or the reference count has been
1641             // dropped by AFSExamineObjectInfo().
1642             //
1643
1644             if ( bReleaseVolumeTreeLock == FALSE)
1645             {
1646
1647                 //
1648                 // Try to obtain the Volume's ObjectInfoTree.TreeLock after dropping
1649                 // other locks and continue.
1650                 //
1651
1652                 bReleaseVolumeTreeLock = AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
1653                                                          FALSE);
1654             }
1655
1656             pCurrentObject = pNextObject;
1657
1658             pNextObject = NULL;
1659         }
1660
1661         if ( pCurrentObject != NULL)
1662         {
1663
1664             lCount = AFSObjectInfoDecrement( pCurrentObject,
1665                                              AFS_OBJECT_REFERENCE_WORKER);
1666
1667             AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1668                           AFS_TRACE_LEVEL_VERBOSE,
1669                           "AFSExamineVolume Decrement count on object %p Cnt %d\n",
1670                           pCurrentObject,
1671                           lCount));
1672         }
1673
1674         if( bReleaseVolumeTreeLock)
1675         {
1676
1677             AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1678         }
1679     }
1680 }
1681
1682 void
1683 AFSPrimaryVolumeWorkerThread( IN PVOID Context)
1684 {
1685
1686     UNREFERENCED_PARAMETER(Context);
1687     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)&AFSGlobalRoot->NonPagedVcb->VolumeWorkerContext;
1688     AFSDeviceExt *pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1689     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1690     LARGE_INTEGER DueTime;
1691     LONG TimeOut;
1692     KTIMER Timer;
1693     AFSVolumeCB *pVolumeCB = NULL, *pNextVolume = NULL;
1694     LONG lCount;
1695
1696     AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1697                   AFS_TRACE_LEVEL_VERBOSE,
1698                   "AFSPrimaryVolumeWorkerThread Initialized\n"));
1699
1700     //
1701     // Initialize the timer for the worker thread
1702     //
1703
1704     DueTime.QuadPart = -(5000);
1705
1706     TimeOut = 5000;
1707
1708     KeInitializeTimerEx( &Timer,
1709                          SynchronizationTimer);
1710
1711     KeSetTimerEx( &Timer,
1712                   DueTime,
1713                   TimeOut,
1714                   NULL);
1715
1716     //
1717     // Indicate that we are initialized and ready
1718     //
1719
1720     KeSetEvent( &pPoolContext->WorkerThreadReady,
1721                 0,
1722                 FALSE);
1723
1724     //
1725     // Indicate we are initialized
1726     //
1727
1728     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
1729
1730     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
1731     {
1732
1733         KeWaitForSingleObject( &Timer,
1734                                Executive,
1735                                KernelMode,
1736                                FALSE,
1737                                NULL);
1738
1739         //
1740         // This is the primary volume worker so it will traverse the volume list
1741         // looking for cleanup or volumes requiring private workers
1742         //
1743
1744         AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1745                           TRUE);
1746
1747         pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead;
1748
1749         while( pVolumeCB != NULL)
1750         {
1751
1752             if( pVolumeCB == AFSGlobalRoot ||
1753                 !AFSAcquireExcl( pVolumeCB->VolumeLock,
1754                                  FALSE))
1755             {
1756
1757                 pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1758
1759                 continue;
1760             }
1761
1762             if( pVolumeCB->ObjectInfoListHead == NULL)
1763             {
1764
1765                 AFSReleaseResource( pVolumeCB->VolumeLock);
1766
1767                 AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1768
1769                 AFSAcquireExcl( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock,
1770                                 TRUE);
1771
1772                 AFSAcquireExcl( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1773                                 TRUE);
1774
1775                 if( !AFSAcquireExcl( pVolumeCB->VolumeLock,
1776                                      FALSE))
1777                 {
1778
1779                     AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1780
1781                     AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
1782
1783                     pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1784
1785                     continue;
1786                 }
1787
1788                 pNextVolume = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1789
1790                 AFSAcquireExcl( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock,
1791                                 TRUE);
1792
1793                 //
1794                 // If VolumeCB is idle, the Volume can be garbage collected
1795                 //
1796
1797                 if( pVolumeCB->ObjectInfoListHead == NULL &&
1798                     pVolumeCB->DirectoryCB->DirOpenReferenceCount <= 0 &&
1799                     pVolumeCB->DirectoryCB->NameArrayReferenceCount <= 0 &&
1800                     pVolumeCB->VolumeReferenceCount == 0 &&
1801                     ( pVolumeCB->RootFcb == NULL ||
1802                       pVolumeCB->RootFcb->OpenReferenceCount == 0) &&
1803                     pVolumeCB->ObjectInformation.ObjectReferenceCount <= 0)
1804                 {
1805
1806                     AFSRemoveRootFcb( pVolumeCB);
1807
1808                     AFSReleaseResource( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
1809
1810                     AFSRemoveVolume( pVolumeCB);
1811                 }
1812                 else
1813                 {
1814
1815                     AFSReleaseResource( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
1816
1817                     AFSReleaseResource( pVolumeCB->VolumeLock);
1818                 }
1819
1820                 AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1821
1822                 AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
1823
1824                 pVolumeCB = pNextVolume;
1825
1826                 continue;
1827             }
1828
1829             //
1830             // Don't need this lock anymore now that we have a volume cb to work with
1831             //
1832
1833             AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1834
1835             //
1836             // For now we only need the volume lock shared
1837             //
1838
1839             AFSConvertToShared( pVolumeCB->VolumeLock);
1840
1841             AFSExamineVolume( pVolumeCB);
1842
1843             //
1844             // Next volume cb
1845             //
1846
1847             AFSReleaseResource( pVolumeCB->VolumeLock);
1848
1849             AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1850                               TRUE);
1851
1852             pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1853         }
1854
1855         AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1856
1857     } // worker thread loop
1858
1859     KeCancelTimer( &Timer);
1860
1861     ClearFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
1862
1863     AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
1864                   AFS_TRACE_LEVEL_VERBOSE,
1865                   "AFSPrimaryVolumeWorkerThread Exiting\n"));
1866
1867     lCount = InterlockedDecrement( &pControlDeviceExt->Specific.Control.VolumeWorkerThreadCount);
1868
1869     if( lCount == 0)
1870     {
1871
1872         KeSetEvent( &pControlDeviceExt->Specific.Control.VolumeWorkerCloseEvent,
1873                     0,
1874                     FALSE);
1875     }
1876
1877     PsTerminateSystemThread( 0);
1878
1879     return;
1880 }
1881
1882 NTSTATUS
1883 AFSInsertWorkitem( IN AFSWorkItem *WorkItem)
1884 {
1885
1886     NTSTATUS ntStatus = STATUS_SUCCESS;
1887     AFSDeviceExt *pControlDevExt = NULL;
1888     LONG lCount;
1889
1890     pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1891
1892     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1893                   AFS_TRACE_LEVEL_VERBOSE,
1894                   "AFSInsertWorkitem Acquiring Control QueueLock lock %p EXCL %08lX\n",
1895                   &pControlDevExt->Specific.Control.QueueLock,
1896                   PsGetCurrentThread()));
1897
1898     AFSAcquireExcl( &pControlDevExt->Specific.Control.QueueLock,
1899                     TRUE);
1900
1901     lCount = InterlockedIncrement( &pControlDevExt->Specific.Control.QueueItemCount);
1902
1903     AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
1904                   AFS_TRACE_LEVEL_VERBOSE,
1905                   "AFSInsertWorkitem Inserting work item %p Count %d\n",
1906                   WorkItem,
1907                   lCount));
1908
1909     if( pControlDevExt->Specific.Control.QueueTail != NULL) // queue already has nodes
1910     {
1911
1912         pControlDevExt->Specific.Control.QueueTail->next = WorkItem;
1913     }
1914     else // first node
1915     {
1916
1917         pControlDevExt->Specific.Control.QueueHead = WorkItem;
1918     }
1919
1920     WorkItem->next = NULL;
1921     pControlDevExt->Specific.Control.QueueTail = WorkItem;
1922
1923     // indicate that the queue has nodes
1924     KeSetEvent( &(pControlDevExt->Specific.Control.WorkerQueueHasItems),
1925                 0,
1926                 FALSE);
1927
1928     AFSReleaseResource( &pControlDevExt->Specific.Control.QueueLock);
1929
1930     return ntStatus;
1931 }
1932
1933 NTSTATUS
1934 AFSInsertIOWorkitem( IN AFSWorkItem *WorkItem)
1935 {
1936
1937     NTSTATUS ntStatus = STATUS_SUCCESS;
1938     AFSDeviceExt *pControlDevExt = NULL;
1939     LONG lCount;
1940
1941     pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1942
1943     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1944                   AFS_TRACE_LEVEL_VERBOSE,
1945                   "AFSInsertIOWorkitem Acquiring Control QueueLock lock %p EXCL %08lX\n",
1946                   &pControlDevExt->Specific.Control.IOQueueLock,
1947                   PsGetCurrentThread()));
1948
1949     AFSAcquireExcl( &pControlDevExt->Specific.Control.IOQueueLock,
1950                     TRUE);
1951
1952     lCount = InterlockedIncrement( &pControlDevExt->Specific.Control.IOQueueItemCount);
1953
1954     AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
1955                   AFS_TRACE_LEVEL_VERBOSE,
1956                   "AFSInsertWorkitem Inserting IO work item %p Count %d\n",
1957                   WorkItem,
1958                   lCount));
1959
1960     if( pControlDevExt->Specific.Control.IOQueueTail != NULL) // queue already has nodes
1961     {
1962
1963         pControlDevExt->Specific.Control.IOQueueTail->next = WorkItem;
1964     }
1965     else // first node
1966     {
1967
1968         pControlDevExt->Specific.Control.IOQueueHead = WorkItem;
1969     }
1970
1971     WorkItem->next = NULL;
1972     pControlDevExt->Specific.Control.IOQueueTail = WorkItem;
1973
1974     // indicate that the queue has nodes
1975     KeSetEvent( &(pControlDevExt->Specific.Control.IOWorkerQueueHasItems),
1976                 0,
1977                 FALSE);
1978
1979     AFSReleaseResource( &pControlDevExt->Specific.Control.IOQueueLock);
1980
1981     return ntStatus;
1982 }
1983
1984 NTSTATUS
1985 AFSInsertWorkitemAtHead( IN AFSWorkItem *WorkItem)
1986 {
1987
1988     NTSTATUS ntStatus = STATUS_SUCCESS;
1989     AFSDeviceExt *pControlDevExt = NULL;
1990     LONG lCount;
1991
1992     pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1993
1994     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1995                   AFS_TRACE_LEVEL_VERBOSE,
1996                   "AFSInsertWorkitemAtHead Acquiring Control QueueLock lock %p EXCL %08lX\n",
1997                   &pControlDevExt->Specific.Control.QueueLock,
1998                   PsGetCurrentThread()));
1999
2000     AFSAcquireExcl( &pControlDevExt->Specific.Control.QueueLock,
2001                     TRUE);
2002
2003     WorkItem->next = pControlDevExt->Specific.Control.QueueHead;
2004
2005     pControlDevExt->Specific.Control.QueueHead = WorkItem;
2006
2007     lCount = InterlockedIncrement( &pControlDevExt->Specific.Control.QueueItemCount);
2008
2009     AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2010                   AFS_TRACE_LEVEL_VERBOSE,
2011                   "AFSInsertWorkitemAtHead Inserting work item %p Count %d\n",
2012                   WorkItem,
2013                   lCount));
2014
2015     //
2016     // indicate that the queue has nodes
2017     //
2018
2019     KeSetEvent( &(pControlDevExt->Specific.Control.WorkerQueueHasItems),
2020                 0,
2021                 FALSE);
2022
2023     AFSReleaseResource( &pControlDevExt->Specific.Control.QueueLock);
2024
2025     return ntStatus;
2026 }
2027
2028 AFSWorkItem *
2029 AFSRemoveWorkItem()
2030 {
2031
2032     AFSWorkItem        *pWorkItem = NULL;
2033     AFSDeviceExt *pControlDevExt = NULL;
2034     LONG lCount;
2035
2036     pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2037
2038     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
2039                   AFS_TRACE_LEVEL_VERBOSE,
2040                   "AFSRemoveWorkItem Acquiring Control QueueLock lock %p EXCL %08lX\n",
2041                   &pControlDevExt->Specific.Control.QueueLock,
2042                   PsGetCurrentThread()));
2043
2044     AFSAcquireExcl( &pControlDevExt->Specific.Control.QueueLock,
2045                     TRUE);
2046
2047     if( pControlDevExt->Specific.Control.QueueHead != NULL) // queue has nodes
2048     {
2049
2050         pWorkItem = pControlDevExt->Specific.Control.QueueHead;
2051
2052         lCount = InterlockedDecrement( &pControlDevExt->Specific.Control.QueueItemCount);
2053
2054         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2055                       AFS_TRACE_LEVEL_VERBOSE,
2056                       "AFSRemoveWorkItem Removing work item %p Count %d Thread %08lX\n",
2057                       pWorkItem,
2058                       lCount,
2059                       PsGetCurrentThreadId()));
2060
2061         pControlDevExt->Specific.Control.QueueHead = pControlDevExt->Specific.Control.QueueHead->next;
2062
2063         if( pControlDevExt->Specific.Control.QueueHead == NULL) // if queue just became empty
2064         {
2065
2066             pControlDevExt->Specific.Control.QueueTail = NULL;
2067         }
2068         else
2069         {
2070
2071             //
2072             // Wake up another worker
2073             //
2074
2075             KeSetEvent( &(pControlDevExt->Specific.Control.WorkerQueueHasItems),
2076                         0,
2077                         FALSE);
2078         }
2079     }
2080
2081     AFSReleaseResource( &pControlDevExt->Specific.Control.QueueLock);
2082
2083     return pWorkItem;
2084 }
2085
2086 AFSWorkItem *
2087 AFSRemoveIOWorkItem()
2088 {
2089
2090     AFSWorkItem        *pWorkItem = NULL;
2091     AFSDeviceExt *pControlDevExt = NULL;
2092     LONG lCount;
2093
2094     pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2095
2096     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
2097                   AFS_TRACE_LEVEL_VERBOSE,
2098                   "AFSRemoveIOWorkItem Acquiring Control QueueLock lock %p EXCL %08lX\n",
2099                   &pControlDevExt->Specific.Control.IOQueueLock,
2100                   PsGetCurrentThread()));
2101
2102     AFSAcquireExcl( &pControlDevExt->Specific.Control.IOQueueLock,
2103                     TRUE);
2104
2105     if( pControlDevExt->Specific.Control.IOQueueHead != NULL) // queue has nodes
2106     {
2107
2108         pWorkItem = pControlDevExt->Specific.Control.IOQueueHead;
2109
2110         lCount = InterlockedDecrement( &pControlDevExt->Specific.Control.IOQueueItemCount);
2111
2112         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2113                       AFS_TRACE_LEVEL_VERBOSE,
2114                       "AFSRemoveWorkItem Removing work item %p Count %d Thread %08lX\n",
2115                       pWorkItem,
2116                       lCount,
2117                       PsGetCurrentThreadId()));
2118
2119         pControlDevExt->Specific.Control.IOQueueHead = pControlDevExt->Specific.Control.IOQueueHead->next;
2120
2121         if( pControlDevExt->Specific.Control.IOQueueHead == NULL) // if queue just became empty
2122         {
2123
2124             pControlDevExt->Specific.Control.IOQueueTail = NULL;
2125         }
2126         else
2127         {
2128
2129             //
2130             // Wake up another worker
2131             //
2132
2133             KeSetEvent( &(pControlDevExt->Specific.Control.IOWorkerQueueHasItems),
2134                         0,
2135                         FALSE);
2136         }
2137     }
2138
2139     AFSReleaseResource( &pControlDevExt->Specific.Control.IOQueueLock);
2140
2141     return pWorkItem;
2142 }
2143
2144 NTSTATUS
2145 AFSQueueWorkerRequest( IN AFSWorkItem *WorkItem)
2146 {
2147
2148     NTSTATUS ntStatus = STATUS_SUCCESS;
2149     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
2150
2151     //
2152     // Submit the work item to the worker
2153     //
2154
2155     ntStatus = AFSInsertWorkitem( WorkItem);
2156
2157     if( bWait)
2158     {
2159
2160         //
2161         // Sync request so block on the work item event
2162         //
2163
2164         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2165                                           Executive,
2166                                           KernelMode,
2167                                           FALSE,
2168                                           NULL);
2169     }
2170
2171     return ntStatus;
2172 }
2173
2174 NTSTATUS
2175 AFSQueueIOWorkerRequest( IN AFSWorkItem *WorkItem)
2176 {
2177
2178     NTSTATUS ntStatus = STATUS_SUCCESS;
2179     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
2180
2181     //
2182     // Submit the work item to the worker
2183     //
2184
2185     ntStatus = AFSInsertIOWorkitem( WorkItem);
2186
2187     if( bWait)
2188     {
2189
2190         //
2191         // Sync request so block on the work item event
2192         //
2193
2194         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2195                                           Executive,
2196                                           KernelMode,
2197                                           FALSE,
2198                                           NULL);
2199     }
2200
2201     return ntStatus;
2202 }
2203
2204 NTSTATUS
2205 AFSQueueWorkerRequestAtHead( IN AFSWorkItem *WorkItem)
2206 {
2207
2208     NTSTATUS ntStatus = STATUS_SUCCESS;
2209     BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST);
2210
2211     //
2212     // Submit the work item to the worker
2213     //
2214
2215     ntStatus = AFSInsertWorkitemAtHead( WorkItem);
2216
2217     if( bWait)
2218     {
2219
2220         //
2221         // Sync request so block on the work item event
2222         //
2223
2224         ntStatus = KeWaitForSingleObject( &WorkItem->Event,
2225                                           Executive,
2226                                           KernelMode,
2227                                           FALSE,
2228                                           NULL);
2229     }
2230
2231     return ntStatus;
2232 }
2233
2234 NTSTATUS
2235 AFSQueueFlushExtents( IN AFSFcb *Fcb,
2236                       IN GUID *AuthGroup)
2237 {
2238
2239     NTSTATUS ntStatus = STATUS_SUCCESS;
2240     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
2241     AFSWorkItem *pWorkItem = NULL;
2242     LONG lCount;
2243
2244     __try
2245     {
2246
2247         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2248                       AFS_TRACE_LEVEL_VERBOSE,
2249                       "AFSQueueFlushExtents Queuing request for FID %08lX-%08lX-%08lX-%08lX\n",
2250                       Fcb->ObjectInformation->FileId.Cell,
2251                       Fcb->ObjectInformation->FileId.Volume,
2252                       Fcb->ObjectInformation->FileId.Vnode,
2253                       Fcb->ObjectInformation->FileId.Unique));
2254
2255         //
2256         // Increment our flush count here just to keep the number of items in the
2257         // queue down. We'll decrement it just below.
2258         //
2259
2260         lCount = InterlockedIncrement( &Fcb->Specific.File.QueuedFlushCount);
2261
2262         if( lCount > 3)
2263         {
2264
2265             AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2266                           AFS_TRACE_LEVEL_VERBOSE,
2267                           "AFSQueueFlushExtents Max queued items for FID %08lX-%08lX-%08lX-%08lX\n",
2268                           Fcb->ObjectInformation->FileId.Cell,
2269                           Fcb->ObjectInformation->FileId.Volume,
2270                           Fcb->ObjectInformation->FileId.Vnode,
2271                           Fcb->ObjectInformation->FileId.Unique));
2272
2273             try_return( ntStatus);
2274         }
2275
2276         if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
2277         {
2278
2279             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2280                           AFS_TRACE_LEVEL_ERROR,
2281                           "AFSQueueFlushExtents Failing request, in shutdown\n"));
2282
2283             try_return( ntStatus = STATUS_TOO_LATE);
2284         }
2285
2286         //
2287         // Allocate our request structure and send it to the worker
2288         //
2289
2290         pWorkItem = (AFSWorkItem *)AFSExAllocatePoolWithTag( NonPagedPool,
2291                                                              sizeof( AFSWorkItem),
2292                                                              AFS_WORK_ITEM_TAG);
2293
2294         if( pWorkItem == NULL)
2295         {
2296
2297             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2298                           AFS_TRACE_LEVEL_ERROR,
2299                           "AFSQueueFlushExtents Failed to allocate work item\n"));
2300
2301             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2302         }
2303
2304         RtlZeroMemory( pWorkItem,
2305                        sizeof( AFSWorkItem));
2306
2307         pWorkItem->Size = sizeof( AFSWorkItem);
2308
2309         pWorkItem->ProcessID = (ULONGLONG)PsGetCurrentProcessId();
2310
2311         pWorkItem->RequestType = AFS_WORK_FLUSH_FCB;
2312
2313         if ( AuthGroup == NULL)
2314         {
2315
2316             RtlZeroMemory( &pWorkItem->AuthGroup,
2317                            sizeof( GUID));
2318
2319             ntStatus = AFSRetrieveValidAuthGroup( Fcb,
2320                                                   NULL,
2321                                                   TRUE,
2322                                                   &pWorkItem->AuthGroup);
2323         }
2324         else
2325         {
2326             RtlCopyMemory( &pWorkItem->AuthGroup,
2327                            AuthGroup,
2328                            sizeof( GUID));
2329         }
2330
2331         pWorkItem->Specific.Fcb.Fcb = Fcb;
2332
2333         lCount = InterlockedIncrement( &Fcb->OpenReferenceCount);
2334
2335         AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
2336                       AFS_TRACE_LEVEL_VERBOSE,
2337                       "AFSQueueFlushExtents Increment count on Fcb %p Cnt %d\n",
2338                       Fcb,
2339                       lCount));
2340
2341         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2342                       AFS_TRACE_LEVEL_VERBOSE,
2343                       "AFSQueueFlushExtents Workitem %p for FID %08lX-%08lX-%08lX-%08lX\n",
2344                       pWorkItem,
2345                       Fcb->ObjectInformation->FileId.Cell,
2346                       Fcb->ObjectInformation->FileId.Volume,
2347                       Fcb->ObjectInformation->FileId.Vnode,
2348                       Fcb->ObjectInformation->FileId.Unique));
2349
2350         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2351
2352 try_exit:
2353
2354         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2355                       AFS_TRACE_LEVEL_VERBOSE,
2356                       "AFSQueueFlushExtents Request complete Status %08lX FID %08lX-%08lX-%08lX-%08lX\n",
2357                       Fcb->ObjectInformation->FileId.Cell,
2358                       Fcb->ObjectInformation->FileId.Volume,
2359                       Fcb->ObjectInformation->FileId.Vnode,
2360                       Fcb->ObjectInformation->FileId.Unique,
2361                       ntStatus));
2362
2363         //
2364         // Remove the count we added above
2365         //
2366
2367         lCount = InterlockedDecrement( &Fcb->Specific.File.QueuedFlushCount);
2368
2369         ASSERT( lCount >= 0);
2370
2371         if( lCount == 0)
2372         {
2373
2374             KeSetEvent( &Fcb->NPFcb->Specific.File.QueuedFlushEvent,
2375                         0,
2376                         FALSE);
2377         }
2378
2379         if( !NT_SUCCESS( ntStatus))
2380         {
2381
2382             if( pWorkItem != NULL)
2383             {
2384
2385                 lCount = InterlockedDecrement( &Fcb->OpenReferenceCount);
2386
2387                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2388             }
2389
2390             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2391                           AFS_TRACE_LEVEL_ERROR,
2392                           "AFSQueueFlushExtents Failed to queue request Status %08lX\n",
2393                           ntStatus));
2394         }
2395     }
2396     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2397     {
2398
2399         AFSDbgTrace(( 0,
2400                       0,
2401                       "EXCEPTION - AFSQueueFlushExtents\n"));
2402
2403         AFSDumpTraceFilesFnc();
2404     }
2405
2406     return ntStatus;
2407 }
2408
2409 NTSTATUS
2410 AFSQueueGlobalRootEnumeration()
2411 {
2412
2413     NTSTATUS ntStatus = STATUS_SUCCESS;
2414     AFSWorkItem *pWorkItem = NULL;
2415
2416     __try
2417     {
2418
2419         pWorkItem = (AFSWorkItem *) AFSExAllocatePoolWithTag( NonPagedPool,
2420                                                               sizeof(AFSWorkItem),
2421                                                               AFS_WORK_ITEM_TAG);
2422         if (NULL == pWorkItem)
2423         {
2424
2425             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
2426                           AFS_TRACE_LEVEL_ERROR,
2427                           "AFSQueueGlobalRootEnumeration Failed to allocate work item\n"));
2428
2429             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2430         }
2431
2432         RtlZeroMemory( pWorkItem,
2433                        sizeof(AFSWorkItem));
2434
2435         pWorkItem->Size = sizeof( AFSWorkItem);
2436
2437         pWorkItem->RequestType = AFS_WORK_ENUMERATE_GLOBAL_ROOT;
2438
2439         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2440                       AFS_TRACE_LEVEL_VERBOSE,
2441                       "AFSQueueGlobalRootEnumeration Workitem %p\n",
2442                       pWorkItem));
2443
2444         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2445
2446 try_exit:
2447
2448         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2449                       AFS_TRACE_LEVEL_VERBOSE,
2450                       "AFSQueueGlobalRootEnumeration Request complete Status %08lX\n",
2451                       ntStatus));
2452
2453         if( !NT_SUCCESS( ntStatus))
2454         {
2455
2456             if( pWorkItem != NULL)
2457             {
2458
2459                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2460             }
2461
2462             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2463                           AFS_TRACE_LEVEL_ERROR,
2464                           "AFSQueueGlobalRootEnumeration Failed to queue request Status %08lX\n",
2465                           ntStatus));
2466         }
2467     }
2468     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2469     {
2470
2471         AFSDbgTrace(( 0,
2472                       0,
2473                       "EXCEPTION - AFSQueueGlobalRootEnumeration\n"));
2474
2475         AFSDumpTraceFilesFnc();
2476     }
2477
2478     return ntStatus;
2479 }
2480
2481 NTSTATUS
2482 AFSQueueStartIos( IN PFILE_OBJECT CacheFileObject,
2483                   IN UCHAR FunctionCode,
2484                   IN ULONG RequestFlags,
2485                   IN AFSIoRun *IoRuns,
2486                   IN ULONG RunCount,
2487                   IN AFSGatherIo *GatherIo)
2488 {
2489
2490     NTSTATUS ntStatus = STATUS_SUCCESS;
2491     AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
2492     AFSWorkItem *pWorkItem = NULL;
2493
2494     __try
2495     {
2496
2497         if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
2498         {
2499
2500             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2501                           AFS_TRACE_LEVEL_ERROR,
2502                           "AFSQueueStartIos Failing request, in shutdown\n"));
2503
2504             try_return( ntStatus = STATUS_TOO_LATE);
2505         }
2506
2507         //
2508         // Allocate our request structure and send it to the worker
2509         //
2510
2511         pWorkItem = (AFSWorkItem *)AFSExAllocatePoolWithTag( NonPagedPool,
2512                                                              sizeof( AFSWorkItem),
2513                                                              AFS_WORK_ITEM_TAG);
2514
2515         if( pWorkItem == NULL)
2516         {
2517
2518             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2519                           AFS_TRACE_LEVEL_ERROR,
2520                           "AFSQueueStartIos Failed to allocate work item\n"));
2521
2522             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2523         }
2524
2525         RtlZeroMemory( pWorkItem,
2526                        sizeof( AFSWorkItem));
2527
2528         KeInitializeEvent( &pWorkItem->Event,
2529                            NotificationEvent,
2530                            FALSE);
2531
2532         pWorkItem->Size = sizeof( AFSWorkItem);
2533
2534         pWorkItem->ProcessID = (ULONGLONG)PsGetCurrentProcessId();
2535
2536         pWorkItem->RequestType = AFS_WORK_START_IOS;
2537
2538         pWorkItem->Specific.CacheAccess.CacheFileObject = CacheFileObject;
2539
2540         pWorkItem->Specific.CacheAccess.FunctionCode = FunctionCode;
2541
2542         pWorkItem->Specific.CacheAccess.RequestFlags = RequestFlags;
2543
2544         pWorkItem->Specific.CacheAccess.IoRuns = IoRuns;
2545
2546         pWorkItem->Specific.CacheAccess.RunCount = RunCount;
2547
2548         pWorkItem->Specific.CacheAccess.GatherIo = GatherIo;
2549
2550         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2551                       AFS_TRACE_LEVEL_VERBOSE,
2552                       "AFSQueueStartIos Queuing IO Workitem %p\n",
2553                       pWorkItem));
2554
2555         ntStatus = AFSQueueIOWorkerRequest( pWorkItem);
2556
2557 try_exit:
2558
2559         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2560                       AFS_TRACE_LEVEL_VERBOSE,
2561                       "AFSQueueStartIos Request complete Status %08lX\n",
2562                       ntStatus));
2563
2564         if( !NT_SUCCESS( ntStatus))
2565         {
2566
2567             if( pWorkItem != NULL)
2568             {
2569
2570                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2571             }
2572         }
2573     }
2574     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2575     {
2576
2577         AFSDbgTrace(( 0,
2578                       0,
2579                       "EXCEPTION - AFSQueueStartIos\n"));
2580
2581         AFSDumpTraceFilesFnc();
2582     }
2583
2584     return ntStatus;
2585 }
2586
2587 NTSTATUS
2588 AFSQueueInvalidateObject( IN AFSObjectInfoCB *ObjectInfo,
2589                           IN ULONG InvalidateReason)
2590 {
2591
2592     NTSTATUS ntStatus = STATUS_SUCCESS;
2593     AFSWorkItem *pWorkItem = NULL;
2594
2595     __try
2596     {
2597
2598         pWorkItem = (AFSWorkItem *) AFSExAllocatePoolWithTag( NonPagedPool,
2599                                                               sizeof(AFSWorkItem),
2600                                                               AFS_WORK_ITEM_TAG);
2601         if (NULL == pWorkItem)
2602         {
2603
2604             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
2605                           AFS_TRACE_LEVEL_ERROR,
2606                           "AFSQueueInvalidateObject Failed to allocate work item\n"));
2607
2608             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2609         }
2610
2611         RtlZeroMemory( pWorkItem,
2612                        sizeof(AFSWorkItem));
2613
2614         pWorkItem->Size = sizeof( AFSWorkItem);
2615
2616         pWorkItem->RequestType = AFS_WORK_INVALIDATE_OBJECT;
2617
2618         pWorkItem->Specific.Invalidate.ObjectInfo = ObjectInfo;
2619
2620         pWorkItem->Specific.Invalidate.InvalidateReason = InvalidateReason;
2621
2622         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2623                       AFS_TRACE_LEVEL_VERBOSE,
2624                       "AFSQueueInvalidateObject Workitem %p\n",
2625                       pWorkItem));
2626
2627         ntStatus = AFSQueueWorkerRequest( pWorkItem);
2628
2629 try_exit:
2630
2631         AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2632                       AFS_TRACE_LEVEL_VERBOSE,
2633                       "AFSQueueInvalidateObject Request complete Status %08lX\n",
2634                       ntStatus));
2635
2636         if( !NT_SUCCESS( ntStatus))
2637         {
2638
2639             if( pWorkItem != NULL)
2640             {
2641                 ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2642             }
2643
2644             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2645                           AFS_TRACE_LEVEL_ERROR,
2646                           "AFSQueueInvalidateObject Failed to queue request Status %08lX\n",
2647                           ntStatus));
2648         }
2649     }
2650     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2651     {
2652
2653         AFSDbgTrace(( 0,
2654                       0,
2655                       "EXCEPTION - AFSQueueInvalidateObject\n"));
2656
2657         AFSDumpTraceFilesFnc();
2658     }
2659
2660     return ntStatus;
2661 }
2662
2663 NTSTATUS
2664 AFSDeferWrite( IN PDEVICE_OBJECT DeviceObject,
2665                IN PFILE_OBJECT FileObject,
2666                IN HANDLE CallingUser,
2667                IN PIRP Irp,
2668                IN ULONG BytesToWrite,
2669                IN BOOLEAN bRetrying)
2670 {
2671     NTSTATUS ntStatus = STATUS_SUCCESS;
2672     AFSWorkItem *pWorkItem = NULL;
2673
2674     __try
2675     {
2676
2677         //
2678         // Pin the user buffer (first time round only - AFSLockSystemBuffer is
2679         // idempotent)
2680         //
2681
2682         if ( NULL == AFSLockSystemBuffer( Irp, BytesToWrite ))
2683         {
2684
2685             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
2686                           AFS_TRACE_LEVEL_ERROR,
2687                           "%s Could not pin user memory item\n",
2688                           __FUNCTION__));
2689
2690             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2691         }
2692
2693         pWorkItem = (AFSWorkItem *) AFSExAllocatePoolWithTag( NonPagedPool,
2694                                                               sizeof(AFSWorkItem),
2695                                                               AFS_WORK_ITEM_TAG);
2696
2697         if (NULL == pWorkItem)
2698         {
2699
2700             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
2701                           AFS_TRACE_LEVEL_ERROR,
2702                           "%s Failed to allocate work item\n",
2703                           __FUNCTION__));
2704
2705             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2706         }
2707
2708         RtlZeroMemory( pWorkItem,
2709                        sizeof(AFSWorkItem));
2710
2711         pWorkItem->Size = sizeof( AFSWorkItem);
2712
2713         pWorkItem->RequestType = AFS_WORK_DEFERRED_WRITE;
2714
2715         pWorkItem->Specific.AsynchIo.CallingProcess = CallingUser;
2716
2717         pWorkItem->Specific.AsynchIo.Device = DeviceObject;
2718
2719         pWorkItem->Specific.AsynchIo.Irp = Irp;
2720
2721         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING | AFS_SUBSYSTEM_WORKER_PROCESSING,
2722                       AFS_TRACE_LEVEL_VERBOSE,
2723                       "%s Workitem %p\n",
2724                       __FUNCTION__,
2725                       pWorkItem));
2726
2727         CcDeferWrite( FileObject, AFSPostedDeferredWrite, pWorkItem, NULL, BytesToWrite, bRetrying);
2728
2729         IoMarkIrpPending(Irp);
2730
2731         ntStatus = STATUS_PENDING;
2732     }
2733     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
2734     {
2735
2736         AFSDbgTrace(( 0,
2737                       0,
2738                       "EXCEPTION - %s \n",
2739                       __FUNCTION__));
2740
2741         ntStatus = GetExceptionCode();
2742     }
2743
2744 try_exit:
2745
2746     AFSDbgTrace(( AFS_SUBSYSTEM_WORKER_PROCESSING,
2747                   AFS_TRACE_LEVEL_VERBOSE,
2748                   "%s complete Status %08lX\n",
2749                   __FUNCTION__,
2750                   ntStatus));
2751
2752     if( !NT_SUCCESS( ntStatus))
2753     {
2754
2755         if( pWorkItem != NULL)
2756         {
2757
2758             ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2759         }
2760
2761         AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2762                       AFS_TRACE_LEVEL_ERROR,
2763                       "%s Failed to queue request Status %08lX\n",
2764                       __FUNCTION__,
2765                       ntStatus));
2766     }
2767
2768     return ntStatus;
2769 }
2770
2771 static
2772 VOID
2773 AFSPostedDeferredWrite( IN PVOID Context1,
2774                         IN PVOID Context2)
2775 {
2776     UNREFERENCED_PARAMETER( Context2);
2777     NTSTATUS ntStatus;
2778
2779     AFSWorkItem *pWorkItem = (AFSWorkItem *) Context1;
2780
2781     AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING | AFS_SUBSYSTEM_WORKER_PROCESSING,
2782                   AFS_TRACE_LEVEL_ERROR,
2783                   "%s Workitem %p\n",
2784                   __FUNCTION__,
2785                   pWorkItem));
2786
2787     ntStatus = AFSQueueIOWorkerRequest( pWorkItem);
2788
2789     if (!NT_SUCCESS( ntStatus))
2790     {
2791
2792         AFSCompleteRequest( pWorkItem->Specific.AsynchIo.Irp, ntStatus);
2793
2794         ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
2795
2796         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING | AFS_SUBSYSTEM_WORKER_PROCESSING,
2797                       AFS_TRACE_LEVEL_ERROR,
2798                       "%s (%p) Failed to queue request Status %08lX\n",
2799                       __FUNCTION__,
2800                       pWorkItem->Specific.AsynchIo.Irp,
2801                       ntStatus));
2802     }
2803 }