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