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