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