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