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