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