Windows: return error to system paging requests
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSExtentsSupport.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: AFSCommSupport.cpp
37 //
38 #include "AFSCommon.h"
39
40 #define AFS_MAX_FCBS_TO_DROP 10
41
42 static AFSExtent *ExtentFor( PLIST_ENTRY le, ULONG SkipList );
43 static AFSExtent *NextExtent( AFSExtent *Extent, ULONG SkipList );
44 static ULONG ExtentsMasks[AFS_NUM_EXTENT_LISTS] = AFS_EXTENTS_MASKS;
45 static VOID VerifyExtentsLists(AFSFcb *Fcb);
46 static AFSExtent *DirtyExtentFor(PLIST_ENTRY le);
47
48 LIST_ENTRY *
49 AFSEntryForOffset( IN AFSFcb *Fcb,
50                    IN PLARGE_INTEGER Offset);
51
52
53 //
54 // Returns with Extents lock EX and no one using them.
55 //
56
57 VOID
58 AFSLockForExtentsTrim( IN AFSFcb *Fcb)
59 {
60     NTSTATUS          ntStatus;
61     AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
62
63     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
64                   AFS_TRACE_LEVEL_VERBOSE,
65                   "AFSLockForExtentsTrim Acuiring Fcb extents lock %08lX EXCL %08lX\n",
66                   &pNPFcb->Specific.File.ExtentsResource,
67                   PsGetCurrentThread());
68
69     AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, TRUE );
70
71     return;
72 }
73
74 //
75 // return FALSE *or* with Extents lock EX and noone using them
76 //
77 BOOLEAN
78 AFSLockForExtentsTrimNoWait( IN AFSFcb *Fcb)
79 {
80     AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
81
82     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
83                   AFS_TRACE_LEVEL_VERBOSE,
84                   "AFSLockForExtentsTrimNoWait Attempting to acquiring Fcb extent lock %08lX EXCL %08lX\n",
85                   &pNPFcb->Specific.File.ExtentsResource,
86                   PsGetCurrentThread());
87
88     if (!AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, FALSE ))
89     {
90         //
91         // Couldn't lock immediately
92         //
93
94         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
95                       AFS_TRACE_LEVEL_VERBOSE,
96                       "AFSLockForExtentsTrimNoWait Refused to wait for Fcb extent lock %08lX EXCL %08lX\n",
97                       &pNPFcb->Specific.File.ExtentsResource,
98                       PsGetCurrentThread());
99
100         return FALSE;
101     }
102
103     return TRUE;
104 }
105 //
106 // Pull all the extents away from the FCB.
107 //
108 BOOLEAN
109 AFSTearDownFcbExtents( IN AFSFcb *Fcb )
110 {
111     BOOLEAN             bFoundExtents = FALSE;
112     AFSNonPagedFcb      *pNPFcb = Fcb->NPFcb;
113     LIST_ENTRY          *le;
114     AFSExtent           *pEntry;
115     ULONG                ulCount = 0, ulReleaseCount = 0, ulProcessCount = 0;
116     size_t               sz;
117     AFSReleaseExtentsCB *pRelease = NULL;
118     BOOLEAN              locked = FALSE;
119     NTSTATUS             ntStatus;
120     AFSDeviceExt        *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
121
122     __Enter
123     {
124
125         //
126         // Ensure that no one is working with the extents and grab the
127         // lock
128         //
129
130         AFSLockForExtentsTrim( Fcb );
131
132         locked = TRUE;
133
134         if (0 == Fcb->Specific.File.ExtentCount)
135         {
136             try_return ( ntStatus = STATUS_SUCCESS);
137         }
138
139         //
140         // Release a max of 100 extents at a time
141         //
142
143         sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
144
145         pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
146                                                                     sz,
147                                                                     AFS_EXTENT_RELEASE_TAG);
148         if (NULL == pRelease)
149         {
150
151             try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
152         }
153
154         le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
155
156         ulCount = Fcb->Specific.File.ExtentCount;
157
158         while( ulReleaseCount < ulCount)
159         {
160
161             bFoundExtents = TRUE;
162
163             RtlZeroMemory( pRelease,
164                            sizeof( AFSReleaseExtentsCB ) +
165                            (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB )));
166
167             if( ulCount - ulReleaseCount <= AFS_MAXIMUM_EXTENT_RELEASE_COUNT)
168             {
169                 ulProcessCount = ulCount - ulReleaseCount;
170             }
171             else
172             {
173                 ulProcessCount = AFS_MAXIMUM_EXTENT_RELEASE_COUNT;
174             }
175
176             pRelease->Flags = AFS_EXTENT_FLAG_RELEASE;
177             pRelease->ExtentCount = ulProcessCount;
178
179             //
180             // Update the metadata for this call
181             //
182
183             pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
184             pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
185             pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
186             pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
187             pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
188
189             ulProcessCount = 0;
190
191             while (ulProcessCount < pRelease->ExtentCount)
192             {
193                 pEntry = ExtentFor( le, AFS_EXTENTS_LIST );
194
195                 pRelease->FileExtents[ulProcessCount].Flags = AFS_EXTENT_FLAG_RELEASE;
196
197 #if GEN_MD5
198                 RtlCopyMemory( pRelease->FileExtents[ulProcessCount].MD5,
199                                pEntry->MD5,
200                                sizeof(pEntry->MD5));
201
202                 pRelease->FileExtents[ulProcessCount].Flags |= AFS_EXTENT_FLAG_MD5_SET;
203 #endif
204
205                 if( BooleanFlagOn( pEntry->Flags, AFS_EXTENT_DIRTY))
206                 {
207
208                     AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
209                                     TRUE);
210
211                     if( BooleanFlagOn( pEntry->Flags, AFS_EXTENT_DIRTY))
212                     {
213
214                         LONG dirtyCount;
215
216                         AFSRemoveEntryDirtyList( Fcb,
217                                                  pEntry);
218
219                         pRelease->FileExtents[ulProcessCount].Flags |= AFS_EXTENT_FLAG_DIRTY;
220
221                         dirtyCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
222
223                         ASSERT( dirtyCount >= 0);
224                     }
225
226                     AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
227                 }
228
229                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
230                               AFS_TRACE_LEVEL_VERBOSE,
231                               "AFSTearDownFcbExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %08lX-%08lX Len %08lX\n",
232                               pEntry,
233                               Fcb->ObjectInformation->FileId.Cell,
234                               Fcb->ObjectInformation->FileId.Volume,
235                               Fcb->ObjectInformation->FileId.Vnode,
236                               Fcb->ObjectInformation->FileId.Unique,
237                               pEntry->FileOffset.HighPart,
238                               pEntry->FileOffset.LowPart,
239                               pEntry->Size);
240
241                 pRelease->FileExtents[ulProcessCount].Length = pEntry->Size;
242                 pRelease->FileExtents[ulProcessCount].DirtyLength = pEntry->Size;
243                 pRelease->FileExtents[ulProcessCount].DirtyOffset = 0;
244                 pRelease->FileExtents[ulProcessCount].CacheOffset = pEntry->CacheOffset;
245                 pRelease->FileExtents[ulProcessCount].FileOffset = pEntry->FileOffset;
246
247                 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pEntry->Size/1024)));
248
249                 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pEntry->Size/1024)));
250
251                 ASSERT( pEntry->ActiveCount == 0);
252
253                 ulProcessCount ++;
254                 le = le->Flink;
255                 AFSExFreePool( pEntry);
256
257                 InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
258
259                 if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0)
260                 {
261
262                     KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
263                                 0,
264                                 FALSE);
265                 }
266             }
267
268             //
269             // Send the request down.  We cannot send this down
270             // asynchronously - if we did that we could request them
271             // back before the service got this request and then this
272             // request would be a corruption.
273             //
274
275             sz = sizeof( AFSReleaseExtentsCB ) + (ulProcessCount * sizeof ( AFSFileExtentCB ));
276
277             ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS,
278                                           AFS_REQUEST_FLAG_SYNCHRONOUS,
279                                           &Fcb->AuthGroup,
280                                           NULL,
281                                           &Fcb->ObjectInformation->FileId,
282                                           pRelease,
283                                           sz,
284                                           NULL,
285                                           NULL);
286
287             if( !NT_SUCCESS(ntStatus))
288             {
289
290                 //
291                 // Regardless of whether or not the AFSProcessRequest() succeeded, the extents
292                 // were released (if AFS_EXTENT_FLAG_RELEASE was set).  Log the error so it is known.
293                 //
294
295                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
296                               AFS_TRACE_LEVEL_ERROR,
297                               "AFSTearDownFcbExtents AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
298                               Fcb->ObjectInformation->FileId.Cell,
299                               Fcb->ObjectInformation->FileId.Volume,
300                               Fcb->ObjectInformation->FileId.Vnode,
301                               Fcb->ObjectInformation->FileId.Unique,
302                               ntStatus);
303
304             }
305
306             ulReleaseCount += ulProcessCount;
307         }
308
309         //
310         // Reinitialize the skip lists
311         //
312
313         ASSERT( Fcb->Specific.File.ExtentCount == 0);
314
315         for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i++)
316         {
317             InitializeListHead(&Fcb->Specific.File.ExtentsLists[i]);
318         }
319
320         //
321         // Reinitialize the dirty list as well
322         //
323
324         AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
325                         TRUE);
326
327         ASSERT( Fcb->Specific.File.ExtentsDirtyCount == 0);
328
329         Fcb->NPFcb->Specific.File.DirtyListHead = NULL;
330         Fcb->NPFcb->Specific.File.DirtyListTail = NULL;
331
332         AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
333
334         Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
335
336 try_exit:
337
338         if (locked)
339         {
340
341             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
342                           AFS_TRACE_LEVEL_VERBOSE,
343                           "AFSTearDownFcbExtents Releasing Fcb extent lock %08lX thread %08lX\n",
344                           &Fcb->NPFcb->Specific.File.ExtentsResource,
345                           PsGetCurrentThread());
346
347             AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource );
348         }
349
350         if (pRelease)
351         {
352
353             AFSExFreePool( pRelease);
354         }
355     }
356
357     return bFoundExtents;
358 }
359
360 static PAFSExtent
361 ExtentForOffsetInList( IN AFSFcb *Fcb,
362                        IN LIST_ENTRY *List,
363                        IN ULONG ListNumber,
364                        IN PLARGE_INTEGER Offset)
365 {
366     //
367     // Return the extent that maps the offset, that
368     //   - Contains the offset
369     //   - or is immediately ahead of the offset (in this list)
370     //   - otherwise return NULL.
371     //
372
373     PLIST_ENTRY  pLe = List;
374     AFSExtent   *pPrevious = NULL;
375
376     ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
377
378     while (pLe != &Fcb->Specific.File.ExtentsLists[ListNumber])
379     {
380         AFSExtent *entry;
381
382         entry = ExtentFor( pLe, ListNumber );
383
384         if( entry == NULL)
385         {
386             return entry;
387         }
388
389         if (Offset->QuadPart < entry->FileOffset.QuadPart)
390         {
391             //
392             // Offset is ahead of entry.  Return previous
393             //
394             return pPrevious;
395         }
396
397         if (Offset->QuadPart >= (entry->FileOffset.QuadPart + entry->Size))
398         {
399             //
400             // We start after this extent - carry on round
401             //
402             pPrevious = entry;
403             pLe = pLe->Flink;
404             continue;
405         }
406
407         //
408         // Otherwise its a match
409         //
410
411         return entry;
412     }
413
414     //
415     // Got to the end.  Return Previous
416     //
417     return pPrevious;
418 }
419
420 BOOLEAN
421 AFSExtentContains( IN AFSExtent *Extent, IN PLARGE_INTEGER Offset)
422 {
423     if (NULL == Extent)
424     {
425         return FALSE;
426     }
427     return (Extent->FileOffset.QuadPart <= Offset->QuadPart &&
428             (Extent->FileOffset.QuadPart + Extent->Size) > Offset->QuadPart);
429 }
430
431
432 //
433 // Return the extent that contains the offset
434 //
435 PAFSExtent
436 AFSExtentForOffsetHint( IN AFSFcb *Fcb,
437                         IN PLARGE_INTEGER Offset,
438                         IN BOOLEAN ReturnPrevious,
439                         IN AFSExtent *Hint)
440 {
441     AFSExtent *pPrevious = Hint;
442     LIST_ENTRY *pLe;
443     LONG i;
444
445     ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
446
447 #if AFS_VALIDATE_EXTENTS
448     VerifyExtentsLists(Fcb);
449 #endif
450
451     //
452     // So we will go across the skip lists until we find an
453     // appropriate entry (previous or direct match).  If it's a match
454     // we are done, other wise we start on the next layer down
455     //
456     for (i = AFS_NUM_EXTENT_LISTS-1; i >= AFS_EXTENTS_LIST; i--)
457     {
458         if (NULL == pPrevious)
459         {
460             //
461             // We haven't found anything in the previous layers
462             //
463             pLe = Fcb->Specific.File.ExtentsLists[i].Flink;
464         }
465         else if (NULL == pPrevious->Lists[i].Flink)
466         {
467             ASSERT(AFS_EXTENTS_LIST != i);
468             //
469             // The hint doesn't exist at this level, next one down
470             //
471             continue;
472         }
473         else
474         {
475             //
476             // take the previous into the next
477             //
478             pLe = &pPrevious->Lists[i];
479         }
480
481         pPrevious = ExtentForOffsetInList( Fcb, pLe, i, Offset);
482
483         if (NULL != pPrevious && AFSExtentContains(pPrevious, Offset))
484         {
485             //
486             // Found it immediately.  Stop here
487             //
488             return pPrevious;
489         }
490     }
491
492     if (NULL == pPrevious || ReturnPrevious )
493     {
494         return pPrevious;
495     }
496
497     ASSERT( !AFSExtentContains(pPrevious, Offset) );
498
499     return NULL;
500 }
501
502 LIST_ENTRY *
503 AFSEntryForOffset( IN AFSFcb *Fcb,
504                    IN PLARGE_INTEGER Offset)
505 {
506     AFSExtent *pPrevious = NULL;
507     LIST_ENTRY *pLe;
508     LONG i;
509
510     ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
511
512 #if AFS_VALIDATE_EXTENTS
513     VerifyExtentsLists(Fcb);
514 #endif
515
516     //
517     // So we will go across the skip lists until we find an
518     // appropriate entry (previous or direct match).  If it's a match
519     // we are done, other wise we start on the next layer down
520     //
521     for (i = AFS_NUM_EXTENT_LISTS-1; i >= AFS_EXTENTS_LIST; i--)
522     {
523         if (NULL == pPrevious)
524         {
525             //
526             // We haven't found anything in the previous layers
527             //
528             pLe = Fcb->Specific.File.ExtentsLists[i].Flink;
529         }
530         else if (NULL == pPrevious->Lists[i].Flink)
531         {
532             ASSERT(AFS_EXTENTS_LIST != i);
533             //
534             // The hint doesn't exist at this level, next one down
535             //
536             continue;
537         }
538         else
539         {
540             //
541             // take the previous into the next
542             //
543             pLe = &pPrevious->Lists[i];
544         }
545
546         pPrevious = ExtentForOffsetInList( Fcb, pLe, i, Offset);
547
548         if (NULL != pPrevious && AFSExtentContains(pPrevious, Offset))
549         {
550             //
551             // Found it immediately.  Stop here
552             //
553             return pLe;
554         }
555     }
556
557     return NULL;
558 }
559
560 PAFSExtent
561 AFSExtentForOffset( IN AFSFcb *Fcb,
562                     IN PLARGE_INTEGER Offset,
563                     IN BOOLEAN ReturnPrevious)
564 {
565     return AFSExtentForOffsetHint(Fcb, Offset, ReturnPrevious, NULL);
566 }
567
568
569 BOOLEAN AFSDoExtentsMapRegion(IN AFSFcb *Fcb,
570                               IN PLARGE_INTEGER Offset,
571                               IN ULONG Size,
572                               IN OUT AFSExtent **FirstExtent,
573                               OUT AFSExtent **LastExtent)
574 {
575     //
576     // Return TRUE region is completely mapped.  FALSE
577     // otherwise.  If the region isn't mapped then the last
578     // extent to map part of the region is returned.
579     //
580     // *LastExtent as input is where to start looking.
581     // *LastExtent as output is either the extent which
582     //  contains the Offset, or the last one which doesn't
583     //
584     AFSExtent *entry;
585     AFSExtent *newEntry;
586     BOOLEAN retVal = FALSE;
587
588     __Enter
589     {
590
591         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
592                       AFS_TRACE_LEVEL_VERBOSE,
593                       "AFSDoExtentsMapRegion Acquiring Fcb extent lock %08lX SHARED %08lX\n",
594                       &Fcb->NPFcb->Specific.File.ExtentsResource,
595                       PsGetCurrentThread());
596
597         AFSAcquireShared( &Fcb->NPFcb->Specific.File.ExtentsResource, TRUE );
598
599         entry = AFSExtentForOffsetHint(Fcb, Offset, TRUE, *FirstExtent);
600         *FirstExtent = entry;
601
602         if (NULL == entry || !AFSExtentContains(entry, Offset))
603         {
604             try_return (retVal = FALSE);
605         }
606
607         ASSERT(Offset->QuadPart >= entry->FileOffset.QuadPart);
608
609         while (TRUE)
610         {
611             if ((entry->FileOffset.QuadPart + entry->Size) >=
612                                                 (Offset->QuadPart + Size))
613             {
614                 //
615                 // The end is inside the extent
616                 //
617                 try_return (retVal = TRUE);
618             }
619
620             if (entry->Lists[AFS_EXTENTS_LIST].Flink == &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
621             {
622                 //
623                 // Run out of extents
624                 //
625                 try_return (retVal = FALSE);
626             }
627
628             newEntry = NextExtent( entry, AFS_EXTENTS_LIST );
629
630             if (newEntry->FileOffset.QuadPart !=
631                 (entry->FileOffset.QuadPart + entry->Size))
632             {
633                 //
634                 // Gap
635                 //
636                 try_return (retVal = FALSE);
637             }
638
639             entry = newEntry;
640         }
641
642 try_exit:
643
644         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
645                       AFS_TRACE_LEVEL_VERBOSE,
646                       "AFSDoExtentsMapRegion Releasing Fcb extent lock %08lX SHARED %08lX\n",
647                       &Fcb->NPFcb->Specific.File.ExtentsResource,
648                       PsGetCurrentThread());
649
650         AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource );
651
652         *LastExtent = entry;
653     }
654
655     return retVal;
656 }
657
658 //
659 // Given an FCB and an Offset we look to see whether there extents to
660 // Map them all.  If there are then we return TRUE to fullymapped
661 // and *FirstExtent points to the first extent to map the extent.
662 // If not then we return FALSE, but we request the extents to be mapped.
663 // Further *FirstExtent (if non null) is the last extent which doesn't
664 // map the extent.
665 //
666 // Finally on the way *in* if *FirstExtent is non null it is where we start looking
667 //
668
669 NTSTATUS
670 AFSRequestExtents( IN AFSFcb *Fcb,
671                    IN PLARGE_INTEGER Offset,
672                    IN ULONG Size,
673                    OUT BOOLEAN *FullyMapped)
674 {
675
676     AFSDeviceExt        *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
677     NTSTATUS             ntStatus = STATUS_SUCCESS;
678     AFSExtent           *pExtent;
679     AFSRequestExtentsCB  request;
680     AFSNonPagedFcb      *pNPFcb = Fcb->NPFcb;
681     AFSExtent           *pFirstExtent;
682     LARGE_INTEGER        liAlignedOffset;
683     ULONG                ulAlignedLength = 0;
684     LARGE_INTEGER        liTimeOut;
685     ULONGLONG            ullProcessId = (ULONGLONG)PsGetCurrentProcessId();
686
687     //
688     // Check our extents, then fire off a request if we need to.
689     // We start off knowing nothing about where we will go.
690     //
691     pFirstExtent = NULL;
692     pExtent = NULL;
693
694     *FullyMapped = AFSDoExtentsMapRegion( Fcb, Offset, Size, &pFirstExtent, &pExtent );
695
696     if (*FullyMapped)
697     {
698
699         ASSERT(AFSExtentContains(pFirstExtent, Offset));
700         LARGE_INTEGER end = *Offset;
701         end.QuadPart += (Size-1);
702         ASSERT(AFSExtentContains(pExtent, &end));
703
704         return STATUS_SUCCESS;
705     }
706
707     //
708     // So we need to queue a request. Since we will be clearing the
709     // ExtentsRequestComplete event we need to do with with the lock
710     // EX
711     //
712
713     liTimeOut.QuadPart = -(50000000);
714
715     while (TRUE)
716     {
717         if (!NT_SUCCESS( pNPFcb->Specific.File.ExtentsRequestStatus))
718         {
719
720             //
721             // If this isn't the same process which caused the failure
722             // then try to request them again
723             //
724
725             if( Fcb->Specific.File.ExtentRequestProcessId == ullProcessId)
726             {
727                 ntStatus = pNPFcb->Specific.File.ExtentsRequestStatus;
728
729                 break;
730             }
731
732             pNPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
733         }
734
735         ntStatus = KeWaitForSingleObject( &pNPFcb->Specific.File.ExtentsRequestComplete,
736                                           Executive,
737                                           KernelMode,
738                                           FALSE,
739                                           &liTimeOut);
740         if (!NT_SUCCESS(ntStatus))
741         {
742
743             //
744             // try again
745             //
746
747             continue;
748         }
749
750         //
751         // Lock resource EX and look again
752         //
753
754         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
755                       AFS_TRACE_LEVEL_VERBOSE,
756                       "AFSRequestExtents Acquiring Fcb extent lock %08lX EXCL %08lX\n",
757                       &pNPFcb->Specific.File.ExtentsResource,
758                       PsGetCurrentThread());
759
760         AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, TRUE );
761
762         if (!NT_SUCCESS( pNPFcb->Specific.File.ExtentsRequestStatus))
763         {
764
765             //
766             // If this isn't the same process which caused the failure then try to request them again
767             //
768
769             if( Fcb->Specific.File.ExtentRequestProcessId == ullProcessId)
770             {
771                 ntStatus = pNPFcb->Specific.File.ExtentsRequestStatus;
772
773                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
774                               AFS_TRACE_LEVEL_VERBOSE,
775                               "AFSRequestExtents Releasing Fcb extent lock %08lX EXCL %08lX\n",
776                               &pNPFcb->Specific.File.ExtentsResource,
777                               PsGetCurrentThread());
778
779                 AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
780
781                 break;
782             }
783
784             pNPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
785         }
786
787         if( KeReadStateEvent( &pNPFcb->Specific.File.ExtentsRequestComplete) ||
788             ntStatus == STATUS_TIMEOUT)
789         {
790
791             ntStatus = pNPFcb->Specific.File.ExtentsRequestStatus;
792
793             if( !NT_SUCCESS( ntStatus))
794             {
795
796                 //
797                 // If this isn't the same process which caused the failure
798                 // then try to request them again
799                 //
800
801                 if( Fcb->Specific.File.ExtentRequestProcessId == ullProcessId)
802                 {
803                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
804                                   AFS_TRACE_LEVEL_VERBOSE,
805                                   "AFSRequestExtents Releasing Fcb extent lock %08lX EXCL %08lX\n",
806                                   &pNPFcb->Specific.File.ExtentsResource,
807                                   PsGetCurrentThread());
808
809                     AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
810                 }
811                 else
812                 {
813
814                     pNPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
815
816                     ntStatus = STATUS_SUCCESS;
817                 }
818             }
819
820             break;
821         }
822
823         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
824                       AFS_TRACE_LEVEL_VERBOSE,
825                       "AFSRequestExtents Releasing Fcb extent lock %08lX EXCL %08lX\n",
826                       &pNPFcb->Specific.File.ExtentsResource,
827                       PsGetCurrentThread());
828
829         AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
830     }
831
832     if (!NT_SUCCESS(ntStatus))
833     {
834
835         return ntStatus;
836     }
837
838     __Enter
839     {
840         //
841         // We have the lock Ex and there is no filling going on.
842         // Check again to see whether things have moved since we last
843         // checked.  Since we haven't locked against pinning, we will
844         // reset here.
845         //
846
847         pFirstExtent = NULL;
848
849         *FullyMapped = AFSDoExtentsMapRegion(Fcb, Offset, Size, &pFirstExtent, &pExtent);
850
851         if (*FullyMapped)
852         {
853
854             ASSERT(AFSExtentContains(pFirstExtent, Offset));
855             LARGE_INTEGER end = *Offset;
856             end.QuadPart += (Size-1);
857             ASSERT(AFSExtentContains(pExtent, &end));
858
859             try_return (ntStatus = STATUS_SUCCESS);
860         }
861
862         RtlZeroMemory( &request,
863                        sizeof( AFSRequestExtentsCB));
864
865         //
866         // Align the request
867         //
868
869         ulAlignedLength = Size;
870
871         liAlignedOffset = *Offset;
872
873         if( liAlignedOffset.QuadPart % pDevExt->Specific.RDR.CacheBlockSize != 0)
874         {
875
876             liAlignedOffset.QuadPart = (ULONGLONG)( (ULONGLONG)(liAlignedOffset.QuadPart / pDevExt->Specific.RDR.CacheBlockSize) * (ULONGLONG)pDevExt->Specific.RDR.CacheBlockSize);
877
878             ulAlignedLength += (ULONG)(Offset->QuadPart - liAlignedOffset.QuadPart);
879         }
880
881         if( ulAlignedLength % pDevExt->Specific.RDR.CacheBlockSize != 0)
882         {
883
884             ulAlignedLength = (ULONG)(((ulAlignedLength / pDevExt->Specific.RDR.CacheBlockSize) + 1) * pDevExt->Specific.RDR.CacheBlockSize);
885         }
886
887         request.ByteOffset = liAlignedOffset;
888         request.Length = ulAlignedLength;
889
890         if( !AFSIsExtentRequestQueued( &Fcb->ObjectInformation->FileId,
891                                        &request.ByteOffset,
892                                        request.Length))
893         {
894
895             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
896                           AFS_TRACE_LEVEL_VERBOSE,
897                           "AFSRequestExtents Request extents for fid %08lX-%08lX-%08lX-%08lX Offset %08lX Len %08lX Thread %08lX\n",
898                           Fcb->ObjectInformation->FileId.Cell,
899                           Fcb->ObjectInformation->FileId.Volume,
900                           Fcb->ObjectInformation->FileId.Vnode,
901                           Fcb->ObjectInformation->FileId.Unique,
902                           request.ByteOffset.LowPart,
903                           request.Length,
904                           PsGetCurrentThread());
905
906             ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_REQUEST_FILE_EXTENTS,
907                                           0,
908                                           &Fcb->AuthGroup,
909                                           NULL,
910                                           &Fcb->ObjectInformation->FileId,
911                                           &request,
912                                           sizeof( AFSRequestExtentsCB ),
913                                           NULL,
914                                           NULL);
915
916             if( NT_SUCCESS( ntStatus))
917             {
918                 KeClearEvent( &pNPFcb->Specific.File.ExtentsRequestComplete );
919             }
920         }
921         else
922         {
923
924             KeClearEvent( &pNPFcb->Specific.File.ExtentsRequestComplete );
925         }
926
927 try_exit:
928
929         if (NT_SUCCESS( ntStatus ))
930         {
931             KeQueryTickCount( &Fcb->Specific.File.LastExtentAccess );
932         }
933
934         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
935                       AFS_TRACE_LEVEL_VERBOSE,
936                       "AFSRequestExtents Releasing Fcb extent lock %08lX EXCL %08lX\n",
937                       &pNPFcb->Specific.File.ExtentsResource,
938                       PsGetCurrentThread());
939
940         AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
941     }
942
943     return ntStatus;
944 }
945
946 NTSTATUS
947 AFSRequestExtentsAsync( IN AFSFcb *Fcb,
948                         IN PLARGE_INTEGER Offset,
949                         IN ULONG Size)
950 {
951
952     AFSDeviceExt        *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
953     NTSTATUS             ntStatus = STATUS_SUCCESS;
954     AFSExtent           *pExtent = NULL;
955     AFSRequestExtentsCB  request;
956     AFSNonPagedFcb      *pNPFcb = Fcb->NPFcb;
957     AFSExtent           *pFirstExtent = NULL;
958     LARGE_INTEGER        liAlignedOffset;
959     ULONG                ulAlignedLength = 0;
960     BOOLEAN              bRegionMapped = FALSE;
961     ULONGLONG            ullProcessId = (ULONGLONG)PsGetCurrentProcessId();
962
963     __Enter
964     {
965
966         ASSERT( !ExIsResourceAcquiredLite( &pNPFcb->Specific.File.ExtentsResource ));
967
968         //
969         // If the service set a failure on the file since the last
970         // CreateFile was issued, return it now.
971         //
972
973         if (!NT_SUCCESS( pNPFcb->Specific.File.ExtentsRequestStatus))
974         {
975
976             //
977             // If this isn't the same process which caused the failure then try to request them again
978             //
979
980             if( Fcb->Specific.File.ExtentRequestProcessId == ullProcessId)
981             {
982                 try_return( ntStatus = pNPFcb->Specific.File.ExtentsRequestStatus);
983             }
984
985             pNPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
986         }
987
988         //
989         // Check if we are already mapped
990         //
991
992         bRegionMapped = AFSDoExtentsMapRegion( Fcb, Offset, Size, &pFirstExtent, &pExtent);
993
994         if( bRegionMapped)
995         {
996
997             try_return( ntStatus = STATUS_SUCCESS);
998         }
999
1000         //
1001         // Align our request on extent size boundary
1002         //
1003
1004         ulAlignedLength = Size;
1005
1006         liAlignedOffset = *Offset;
1007
1008         if( liAlignedOffset.QuadPart % pDevExt->Specific.RDR.CacheBlockSize != 0)
1009         {
1010
1011             liAlignedOffset.QuadPart = (ULONGLONG)( (ULONGLONG)(liAlignedOffset.QuadPart / pDevExt->Specific.RDR.CacheBlockSize) * (ULONGLONG)pDevExt->Specific.RDR.CacheBlockSize);
1012
1013             ulAlignedLength += (ULONG)(Offset->QuadPart - liAlignedOffset.QuadPart);
1014         }
1015
1016         if( ulAlignedLength % pDevExt->Specific.RDR.CacheBlockSize != 0)
1017         {
1018
1019             ulAlignedLength = (ULONG)(((ulAlignedLength / pDevExt->Specific.RDR.CacheBlockSize) + 1) * pDevExt->Specific.RDR.CacheBlockSize);
1020         }
1021
1022         RtlZeroMemory( &request,
1023                        sizeof( AFSRequestExtentsCB));
1024
1025         request.ByteOffset = liAlignedOffset;
1026         request.Length = ulAlignedLength;
1027
1028         if( !AFSIsExtentRequestQueued( &Fcb->ObjectInformation->FileId,
1029                                        &request.ByteOffset,
1030                                        request.Length))
1031         {
1032
1033             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1034                           AFS_TRACE_LEVEL_VERBOSE,
1035                           "AFSRequestExtentsAsync Request extents for fid %08lX-%08lX-%08lX-%08lX Offset %08lX Len %08lX Thread %08lX\n",
1036                           Fcb->ObjectInformation->FileId.Cell,
1037                           Fcb->ObjectInformation->FileId.Volume,
1038                           Fcb->ObjectInformation->FileId.Vnode,
1039                           Fcb->ObjectInformation->FileId.Unique,
1040                           request.ByteOffset.LowPart,
1041                           request.Length,
1042                           PsGetCurrentThread());
1043
1044             ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_REQUEST_FILE_EXTENTS,
1045                                           0,
1046                                           &Fcb->AuthGroup,
1047                                           NULL,
1048                                           &Fcb->ObjectInformation->FileId,
1049                                           &request,
1050                                           sizeof( AFSRequestExtentsCB ),
1051                                           NULL,
1052                                           NULL);
1053
1054             if( NT_SUCCESS( ntStatus))
1055             {
1056
1057                 KeClearEvent( &pNPFcb->Specific.File.ExtentsRequestComplete );
1058             }
1059         }
1060         else
1061         {
1062
1063             KeClearEvent( &pNPFcb->Specific.File.ExtentsRequestComplete );
1064         }
1065
1066 try_exit:
1067
1068         NOTHING;
1069     }
1070
1071     return ntStatus;
1072 }
1073
1074 NTSTATUS
1075 AFSProcessExtentsResult( IN AFSFcb *Fcb,
1076                          IN ULONG   Count,
1077                          IN AFSFileExtentCB *Result)
1078 {
1079     NTSTATUS          ntStatus = STATUS_SUCCESS;
1080     AFSFileExtentCB  *pFileExtents = Result;
1081     AFSExtent        *pExtent;
1082     LIST_ENTRY       *le;
1083     AFSNonPagedFcb   *pNPFcb = Fcb->NPFcb;
1084     ULONG             fileExtentsUsed = 0;
1085     BOOLEAN           bFoundExtent = FALSE;
1086     LIST_ENTRY       *pSkipEntries[AFS_NUM_EXTENT_LISTS] = { 0 };
1087     AFSDeviceExt     *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1088
1089     //
1090     // Grab the extents exclusive for the duration
1091     //
1092
1093     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1094                   AFS_TRACE_LEVEL_VERBOSE,
1095                   "AFSProcessExtentsResult Acquiring Fcb extent lock %08lX EXCL %08lX\n",
1096                   &pNPFcb->Specific.File.ExtentsResource,
1097                   PsGetCurrentThread());
1098
1099     AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, TRUE );
1100
1101     __Enter
1102     {
1103
1104         //
1105         // Find where to put the extents
1106         //
1107         for (ULONG i = AFS_EXTENTS_LIST; i < AFS_NUM_EXTENT_LISTS; i++)
1108         {
1109
1110             pSkipEntries[i] = Fcb->Specific.File.ExtentsLists[i].Flink;
1111         }
1112
1113         le = pSkipEntries[AFS_EXTENTS_LIST];
1114
1115         if (le == &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
1116         {
1117             //
1118             // No extents.  Insert at head of list (which is where the skip lists point!)
1119             //
1120             pExtent = NULL;
1121         }
1122         else if (0 != pFileExtents->FileOffset.QuadPart)
1123         {
1124             //
1125             // We want to find the best extents immediately *behind* this offset
1126             //
1127             LARGE_INTEGER offset = pFileExtents->FileOffset;
1128
1129             //
1130             // Ask in the top skip list first, then work down
1131             //
1132             for (LONG i = AFS_NUM_EXTENT_LISTS-1; i >= AFS_EXTENTS_LIST; i--)
1133             {
1134                 pExtent = ExtentForOffsetInList( Fcb,
1135                                                  pSkipEntries[i],
1136                                                  i,
1137                                                  &offset);
1138
1139                 if (NULL == pExtent)
1140                 {
1141                     //
1142                     // No dice.  Header has to become the head of the list
1143                     //
1144                     pSkipEntries[i] = &Fcb->Specific.File.ExtentsLists[i];
1145                     //
1146                     // And as  a loop invariant we should never have found an extent
1147                     //
1148                     ASSERT(!bFoundExtent);
1149                 }
1150                 else
1151                 {
1152                     //
1153                     // pExtent is where to start to insert at this level
1154                     //
1155                     pSkipEntries[i] = &pExtent->Lists[i];
1156
1157                     //
1158                     // And also where to start to look at the next level
1159                     //
1160
1161                     if (i > AFS_EXTENTS_LIST)
1162                     {
1163                         pSkipEntries[i-1] = &pExtent->Lists[i-1];
1164                     }
1165                     bFoundExtent = TRUE;
1166                 }
1167             }
1168
1169             if (NULL == pExtent)
1170             {
1171                 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
1172                 le = le->Blink;
1173             }
1174             else
1175             {
1176                 le = pExtent->Lists[AFS_EXTENTS_LIST].Blink;
1177             }
1178         }
1179         else
1180         {
1181             //
1182             // Looking at offset 0, so we must start at the beginning
1183             //
1184
1185             pExtent = ExtentFor(le, AFS_EXTENTS_LIST);
1186             le = le->Blink;
1187
1188             //
1189             // And set up the skip lists
1190             //
1191
1192             for (ULONG i = AFS_EXTENTS_LIST; i < AFS_NUM_EXTENT_LISTS; i++)
1193             {
1194                 pSkipEntries[i] = &Fcb->Specific.File.ExtentsLists[i];
1195             }
1196         }
1197
1198         while (fileExtentsUsed < Count)
1199         {
1200
1201             //
1202             // Loop invariant - le points to where to insert after and
1203             // pExtent points to le->fLink
1204             //
1205
1206             ASSERT (NULL == pExtent ||
1207                     le->Flink == &pExtent->Lists[AFS_EXTENTS_LIST]);
1208
1209             if (NULL == pExtent ||
1210                 pExtent->FileOffset.QuadPart > pFileExtents->FileOffset.QuadPart)
1211             {
1212                 //
1213                 // We need to insert a new extent at le.  Start with
1214                 // some sanity check on spanning
1215                 //
1216                 if (NULL != pExtent &&
1217                     ((pFileExtents->FileOffset.QuadPart + pFileExtents->Length) >
1218                      pExtent->FileOffset.QuadPart))
1219                 {
1220                     //
1221                     // File Extents overlaps pExtent
1222                     //
1223                     ASSERT( (pFileExtents->FileOffset.QuadPart + pFileExtents->Length) <=
1224                             pExtent->FileOffset.QuadPart);
1225
1226                     try_return (ntStatus = STATUS_INVALID_PARAMETER);
1227                 }
1228
1229                 //
1230                 // File offset is entirely in front of this extent.  Create
1231                 // a new one (remember le is the previous list entry)
1232                 //
1233                 pExtent = (AFSExtent *) AFSExAllocatePoolWithTag( NonPagedPool,
1234                                                                   sizeof( AFSExtent),
1235                                                                   AFS_EXTENT_TAG );
1236                 if (NULL  == pExtent)
1237                 {
1238
1239                     ASSERT( FALSE);
1240
1241                     try_return (ntStatus = STATUS_INSUFFICIENT_RESOURCES );
1242                 }
1243
1244                 RtlZeroMemory( pExtent, sizeof( AFSExtent ));
1245
1246                 pExtent->FileOffset = pFileExtents->FileOffset;
1247                 pExtent->CacheOffset = pFileExtents->CacheOffset;
1248                 pExtent->Size = pFileExtents->Length;
1249
1250                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1251                               AFS_TRACE_LEVEL_VERBOSE,
1252                               "AFSProcessExtentsResult Received extent for fid %08lX-%08lX-%08lX-%08lX File Offset %I64X Cache Offset %I64X Len %08lX\n",
1253                               Fcb->ObjectInformation->FileId.Cell,
1254                               Fcb->ObjectInformation->FileId.Volume,
1255                               Fcb->ObjectInformation->FileId.Vnode,
1256                               Fcb->ObjectInformation->FileId.Unique,
1257                               pFileExtents->FileOffset.QuadPart,
1258                               pFileExtents->CacheOffset.QuadPart,
1259                               pFileExtents->Length);
1260
1261                 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, (LONG)(pExtent->Size/1024));
1262
1263                 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, (LONG)(pExtent->Size/1024));
1264
1265                 InterlockedIncrement( &Fcb->Specific.File.ExtentCount);
1266
1267                 if( InterlockedIncrement( &pControlDevExt->Specific.Control.ExtentCount) == 1)
1268                 {
1269
1270                     KeClearEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent);
1271                 }
1272
1273                 //
1274                 // Insert into list
1275                 //
1276                 InsertHeadList(le, &pExtent->Lists[AFS_EXTENTS_LIST]);
1277                 ASSERT(le->Flink == &pExtent->Lists[AFS_EXTENTS_LIST]);
1278                 ASSERT(0 == (pExtent->FileOffset.LowPart & ExtentsMasks[AFS_EXTENTS_LIST]));
1279
1280                 //
1281                 // Do not move the cursor - we will do it next time
1282                 //
1283
1284                 //
1285                 // And into the (upper) skip lists - Again, do not move the cursor
1286                 //
1287                 for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--)
1288                 {
1289                     if (0 == (pExtent->FileOffset.LowPart & ExtentsMasks[i]))
1290                     {
1291                         InsertHeadList(pSkipEntries[i], &pExtent->Lists[i]);
1292 #if AFS_VALIDATE_EXTENTS
1293                         VerifyExtentsLists(Fcb);
1294 #endif
1295                     }
1296                 }
1297             }
1298             else if (pExtent->FileOffset.QuadPart == pFileExtents->FileOffset.QuadPart)
1299             {
1300
1301                 if (pExtent->Size != pFileExtents->Length)
1302                 {
1303
1304                     ASSERT (pExtent->Size == pFileExtents->Length);
1305
1306                     try_return (ntStatus = STATUS_INVALID_PARAMETER);
1307                 }
1308
1309                 //
1310                 // Move both cursors forward.
1311                 //
1312                 // First the extent pointer
1313                 //
1314                 fileExtentsUsed++;
1315                 le = &pExtent->Lists[AFS_EXTENTS_LIST];
1316
1317                 //
1318                 // Then the skip lists cursors forward if needed
1319                 //
1320                 for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--)
1321                 {
1322                     if (0 == (pExtent->FileOffset.LowPart & ExtentsMasks[i]))
1323                     {
1324                         //
1325                         // Check sanity before
1326                         //
1327 #if AFS_VALIDATE_EXTENTS
1328                         VerifyExtentsLists(Fcb);
1329 #endif
1330
1331                         //
1332                         // Skip list should point to us
1333                         //
1334                         //ASSERT(pSkipEntries[i] == &pExtent->Lists[i]);
1335                         //
1336                         // Move forward cursor
1337                         //
1338                         pSkipEntries[i] = pSkipEntries[i]->Flink;
1339                         //
1340                         // Check sanity before
1341                         //
1342 #if AFS_VALIDATE_EXTENTS
1343                         VerifyExtentsLists(Fcb);
1344 #endif
1345                     }
1346                 }
1347
1348                 //
1349                 // And then the cursor in the supplied array
1350                 //
1351
1352                 pFileExtents++;
1353
1354                 //
1355                 // setup pExtent if there is one
1356                 //
1357                 if (le->Flink != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
1358                 {
1359                     pExtent = NextExtent( pExtent, AFS_EXTENTS_LIST ) ;
1360                 }
1361                 else
1362                 {
1363                     pExtent = NULL;
1364                 }
1365             }
1366             else
1367             {
1368
1369                 ASSERT( pExtent->FileOffset.QuadPart < pFileExtents->FileOffset.QuadPart );
1370
1371                 //
1372                 // Sanity check on spanning
1373                 //
1374                 if ((pExtent->FileOffset.QuadPart + pExtent->Size) >
1375                     pFileExtents->FileOffset.QuadPart)
1376                 {
1377
1378                     ASSERT( (pExtent->FileOffset.QuadPart + pExtent->Size) <=
1379                             pFileExtents->FileOffset.QuadPart);
1380
1381                     try_return (ntStatus = STATUS_INVALID_PARAMETER);
1382                 }
1383
1384                 //
1385                 // Move le and pExtent forward
1386                 //
1387                 le = &pExtent->Lists[AFS_EXTENTS_LIST];
1388
1389                 /*
1390                 //
1391                 // Then the check the skip lists cursors
1392                 //
1393                 for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--)
1394                 {
1395                     if (0 == (pFileExtents->FileOffset.LowPart & ExtentsMasks[i]))
1396                     {
1397                         //
1398                         // Three options:
1399                         //    - empty list (pSkipEntries[i]->Flink == pSkipEntries[i]->Flink == fcb->lists[i]
1400                         //    - We are the last on the list (pSkipEntries[i]->Flink == fcb->lists[i])
1401                         //    - We are not the last on the list.  In that case we have to be strictly less than
1402                         //      that extent.
1403                         if (pSkipEntries[i]->Flink != &Fcb->Specific.File.ExtentsLists[i]) {
1404
1405                             AFSExtent *otherExtent = ExtentFor(pSkipEntries[i]->Flink, i);
1406                             ASSERT(pFileExtents->FileOffset.QuadPart < otherExtent->FileOffset.QuadPart);
1407                         }
1408                     }
1409                 }
1410                 */
1411
1412                 //
1413                 // setup pExtent if there is one
1414                 //
1415
1416                 if (le->Flink != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
1417                 {
1418                     pExtent = NextExtent( pExtent, AFS_EXTENTS_LIST ) ;
1419                 }
1420                 else
1421                 {
1422                     pExtent = NULL;
1423                 }
1424             }
1425         }
1426
1427         //
1428         // All done, signal that we are done drop the lock, exit
1429         //
1430
1431 try_exit:
1432
1433         if( !NT_SUCCESS( ntStatus))
1434         {
1435
1436             //
1437             // If we failed the service is going to drop all extents so trim away the
1438             // set given to us
1439             //
1440
1441             AFSTrimSpecifiedExtents( Fcb,
1442                                      Count,
1443                                      Result);
1444         }
1445
1446 #if AFS_VALIDATE_EXTENTS
1447         VerifyExtentsLists(Fcb);
1448 #endif
1449
1450         KeSetEvent( &pNPFcb->Specific.File.ExtentsRequestComplete,
1451                     0,
1452                     FALSE);
1453
1454         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1455                       AFS_TRACE_LEVEL_VERBOSE,
1456                       "AFSProcessExtentsResult Releasing Fcb extent lock %08lX EXCL %08lX\n",
1457                       &pNPFcb->Specific.File.ExtentsResource,
1458                       PsGetCurrentThread());
1459
1460         AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
1461     }
1462
1463     return ntStatus;
1464 }
1465
1466 NTSTATUS
1467 AFSProcessSetFileExtents( IN AFSSetFileExtentsCB *SetExtents )
1468 {
1469     AFSFcb       *pFcb = NULL;
1470     AFSVolumeCB  *pVolumeCB = NULL;
1471     NTSTATUS      ntStatus = STATUS_SUCCESS;
1472     AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1473     ULONGLONG     ullIndex = 0;
1474     AFSObjectInfoCB *pObjectInfo = NULL;
1475
1476     __Enter
1477     {
1478
1479         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1480                       AFS_TRACE_LEVEL_VERBOSE,
1481                       "AFSProcessSetFileExtents Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n",
1482                       &pDevExt->Specific.RDR.VolumeTreeLock,
1483                       PsGetCurrentThread());
1484
1485         AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
1486
1487         AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1488                       AFS_TRACE_LEVEL_VERBOSE,
1489                       "AFSProcessSetFileExtents Set extents for fid %08lX-%08lX-%08lX-%08lX\n",
1490                       SetExtents->FileId.Cell,
1491                       SetExtents->FileId.Volume,
1492                       SetExtents->FileId.Vnode,
1493                       SetExtents->FileId.Unique);
1494
1495         //
1496         // Locate the volume node
1497         //
1498
1499         ullIndex = AFSCreateHighIndex( &SetExtents->FileId);
1500
1501         ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
1502                                        ullIndex,
1503                                        (AFSBTreeEntry **)&pVolumeCB);
1504
1505         if( pVolumeCB != NULL)
1506         {
1507
1508             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1509                           AFS_TRACE_LEVEL_VERBOSE,
1510                           "AFSProcessSetFileExtents Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n",
1511                           pVolumeCB->ObjectInfoTree.TreeLock,
1512                           PsGetCurrentThread());
1513
1514             InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
1515         }
1516
1517         AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
1518
1519         if( !NT_SUCCESS( ntStatus) ||
1520             pVolumeCB == NULL)
1521         {
1522
1523             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1524                           AFS_TRACE_LEVEL_ERROR,
1525                           "AFSProcessSetFileExtents Set extents for fid %08lX-%08lX-%08lX-%08lX Failed to locate volume Status %08lX\n",
1526                           SetExtents->FileId.Cell,
1527                           SetExtents->FileId.Volume,
1528                           SetExtents->FileId.Vnode,
1529                           SetExtents->FileId.Unique,
1530                           ntStatus);
1531
1532             try_return( ntStatus = STATUS_UNSUCCESSFUL);
1533         }
1534
1535         AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1536                           TRUE);
1537
1538         InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1539
1540         //
1541         // Now locate the Object in this volume
1542         //
1543
1544         ullIndex = AFSCreateLowIndex( &SetExtents->FileId);
1545
1546         ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
1547                                        ullIndex,
1548                                        (AFSBTreeEntry **)&pObjectInfo);
1549
1550         if( pObjectInfo != NULL)
1551         {
1552
1553             //
1554             // Reference the node so it won't be torn down
1555             //
1556
1557             InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
1558
1559             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1560                           AFS_TRACE_LEVEL_VERBOSE,
1561                           "AFSProcessSetFileExtents Increment count on object %08lX Cnt %d\n",
1562                           pObjectInfo,
1563                           pObjectInfo->ObjectReferenceCount);
1564         }
1565
1566         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1567
1568         if( !NT_SUCCESS( ntStatus) ||
1569             pObjectInfo == NULL)
1570         {
1571
1572             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1573                           AFS_TRACE_LEVEL_ERROR,
1574                           "AFSProcessSetFileExtents Set extents for hash %I64X fid %08lX-%08lX-%08lX-%08lX Failed to locate file in volume %08lX\n",
1575                           ullIndex,
1576                           SetExtents->FileId.Cell,
1577                           SetExtents->FileId.Volume,
1578                           SetExtents->FileId.Vnode,
1579                           SetExtents->FileId.Unique,
1580                           pVolumeCB);
1581
1582             try_return( ntStatus = STATUS_UNSUCCESSFUL);
1583         }
1584
1585         pFcb = pObjectInfo->Fcb;
1586
1587         //
1588         // If we have a result failure then don't bother trying to set the extents
1589         //
1590
1591         if( SetExtents->ResultStatus != STATUS_SUCCESS)
1592         {
1593
1594             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1595                           AFS_TRACE_LEVEL_ERROR,
1596                           "AFSProcessSetFileExtents Set extents failure fid %08lX-%08lX-%08lX-%08lX ResultStatus %08lX\n",
1597                           SetExtents->FileId.Cell,
1598                           SetExtents->FileId.Volume,
1599                           SetExtents->FileId.Vnode,
1600                           SetExtents->FileId.Unique,
1601                           SetExtents->ResultStatus);
1602
1603             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1604                           AFS_TRACE_LEVEL_VERBOSE,
1605                           "AFSProcessSetFileExtents Acquiring Fcb extents lock %08lX EXCL %08lX\n",
1606                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1607                           PsGetCurrentThread());
1608
1609             AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource,
1610                             TRUE);
1611
1612             pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_CANCELLED;
1613
1614             KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete,
1615                         0,
1616                         FALSE);
1617
1618             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1619                           AFS_TRACE_LEVEL_VERBOSE,
1620                           "AFSProcessSetFileExtents Releasing Fcb extent lock %08lX EXCL %08lX\n",
1621                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1622                           PsGetCurrentThread());
1623
1624             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
1625
1626             try_return( ntStatus);
1627         }
1628
1629         ntStatus = AFSProcessExtentsResult ( pFcb,
1630                                              SetExtents->ExtentCount,
1631                                              SetExtents->FileExtents );
1632
1633 try_exit:
1634
1635         if( pObjectInfo != NULL)
1636         {
1637
1638             InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
1639
1640             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1641                           AFS_TRACE_LEVEL_VERBOSE,
1642                           "AFSProcessSetFileExtents Decrement count on object %08lX Cnt %d\n",
1643                           pObjectInfo,
1644                           pObjectInfo->ObjectReferenceCount);
1645         }
1646     }
1647
1648     return ntStatus;
1649 }
1650
1651 //
1652 // Helper fuctions for Usermode initiation of release of extents
1653 //
1654 NTSTATUS
1655 AFSReleaseSpecifiedExtents( IN  AFSReleaseFileExtentsCB *Extents,
1656                             IN  AFSFcb *Fcb,
1657                             OUT AFSFileExtentCB *FileExtents,
1658                             IN  ULONG BufferSize,
1659                             OUT ULONG *ExtentCount,
1660                             OUT BOOLEAN *DirtyExtents)
1661 {
1662     AFSExtent           *pExtent;
1663     LIST_ENTRY          *le;
1664     LIST_ENTRY          *leNext;
1665     ULONG                ulExtentCount = 0;
1666     NTSTATUS             ntStatus = STATUS_SUCCESS;
1667     BOOLEAN              bReleaseAll = FALSE;
1668     AFSDeviceExt        *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1669
1670     __Enter
1671     {
1672         ASSERT( ExIsResourceAcquiredExclusiveLite( &Fcb->NPFcb->Specific.File.ExtentsResource));
1673
1674         if (BufferSize < (Extents->ExtentCount * sizeof( AFSFileExtentCB)))
1675         {
1676
1677             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1678                           AFS_TRACE_LEVEL_VERBOSE,
1679                           "AFSReleaseSpecifiedExtents Buffer too small\n");
1680
1681             try_return( ntStatus = STATUS_BUFFER_TOO_SMALL);
1682         }
1683
1684         RtlZeroMemory( FileExtents, BufferSize);
1685         *ExtentCount = 0;
1686
1687         *DirtyExtents = FALSE;
1688
1689         //
1690         // iterate until we have dealt with all we were asked for or
1691         // are at the end of the list.  Note that this deals (albeit
1692         // badly) with out of order extents
1693         //
1694
1695         pExtent = AFSExtentForOffset( Fcb,
1696                                       &Extents->FileExtents[0].FileOffset,
1697                                       FALSE);
1698
1699         if (NULL == pExtent)
1700         {
1701             le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1702         }
1703         else
1704         {
1705             le = &pExtent->Lists[AFS_EXTENTS_LIST];
1706         }
1707         ulExtentCount = 0;
1708
1709         if( BooleanFlagOn( Extents->Flags, AFS_RELEASE_EXTENTS_FLAGS_RELEASE_ALL) ||
1710             ( Extents->FileId.Cell   == 0 &&
1711               Extents->FileId.Volume == 0 &&
1712               Extents->FileId.Vnode  == 0 &&
1713               Extents->FileId.Unique == 0))
1714         {
1715
1716             bReleaseAll = TRUE;
1717         }
1718
1719         while( le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST] &&
1720                ulExtentCount < Extents->ExtentCount)
1721
1722         {
1723
1724             pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
1725
1726             if( !bReleaseAll)
1727             {
1728
1729                 if( pExtent->FileOffset.QuadPart < Extents->FileExtents[ulExtentCount].FileOffset.QuadPart)
1730                 {
1731                     //
1732                     // Skip forward through the extent list until we get
1733                     // to the one we want
1734                     //
1735                     le = le->Flink;
1736
1737                     continue;
1738                 }
1739                 else if (pExtent->FileOffset.QuadPart > Extents->FileExtents[ulExtentCount].FileOffset.QuadPart)
1740                 {
1741                     //
1742                     // We don't have the extent asked for so return UNKNOWN
1743                     //
1744
1745                     AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1746                                   AFS_TRACE_LEVEL_VERBOSE,
1747                                   "AFSReleaseSpecifiedExtents Located UNKNOWN extent Offset %I64X Len %08lX\n",
1748                                   Extents->FileExtents[ulExtentCount].FileOffset.QuadPart,
1749                                   Extents->FileExtents[ulExtentCount].Length);
1750
1751                     FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_UNKNOWN;
1752
1753                     FileExtents[*ExtentCount].Length = 0;
1754                     FileExtents[*ExtentCount].CacheOffset.QuadPart = 0;
1755                     FileExtents[*ExtentCount].FileOffset = Extents->FileExtents[ulExtentCount].FileOffset;
1756
1757                     *ExtentCount = (*ExtentCount) + 1;
1758
1759                     ulExtentCount++;
1760
1761                     //
1762                     // Reset where we are looking
1763                     //
1764
1765                     le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1766
1767                     continue;
1768                 }
1769                 else if( pExtent->ActiveCount > 0)
1770                 {
1771
1772                     AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1773                                   AFS_TRACE_LEVEL_VERBOSE,
1774                                   "AFSReleaseSpecifiedExtents Located IN_USE extent Offset %I64X Len %08lX\n",
1775                                   Extents->FileExtents[ulExtentCount].FileOffset.QuadPart,
1776                                   Extents->FileExtents[ulExtentCount].Length);
1777
1778                     FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_IN_USE;
1779
1780                     FileExtents[*ExtentCount].Length = 0;
1781                     FileExtents[*ExtentCount].CacheOffset.QuadPart = 0;
1782                     FileExtents[*ExtentCount].FileOffset = Extents->FileExtents[ulExtentCount].FileOffset;
1783
1784                     *ExtentCount = (*ExtentCount) + 1;
1785
1786                     ulExtentCount++;
1787
1788                     //
1789                     // Reset where we are looking
1790                     //
1791
1792                     le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1793
1794                     continue;
1795                 }
1796             }
1797             else
1798             {
1799
1800                 //
1801                 // If the extent is currently active then skip it
1802                 //
1803
1804                 if( pExtent->ActiveCount > 0)
1805                 {
1806
1807                     le = le->Flink;
1808
1809                     continue;
1810                 }
1811             }
1812
1813             FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_RELEASE;
1814
1815             FileExtents[*ExtentCount].Length = pExtent->Size;
1816             FileExtents[*ExtentCount].DirtyLength = pExtent->Size;
1817             FileExtents[*ExtentCount].DirtyOffset = 0;
1818             FileExtents[*ExtentCount].CacheOffset = pExtent->CacheOffset;
1819             FileExtents[*ExtentCount].FileOffset = pExtent->FileOffset;
1820
1821             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1822                           AFS_TRACE_LEVEL_VERBOSE,
1823                           "AFSReleaseSpecifiedExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
1824                           pExtent,
1825                           Fcb->ObjectInformation->FileId.Cell,
1826                           Fcb->ObjectInformation->FileId.Volume,
1827                           Fcb->ObjectInformation->FileId.Vnode,
1828                           Fcb->ObjectInformation->FileId.Unique,
1829                           FileExtents[*ExtentCount].FileOffset.QuadPart,
1830                           FileExtents[*ExtentCount].Length);
1831
1832             if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
1833             {
1834
1835                 AFSAcquireExcl( &Fcb->NPFcb->Specific.File.DirtyExtentsListLock,
1836                                 TRUE);
1837
1838                 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
1839                 {
1840
1841                     AFSRemoveEntryDirtyList( Fcb,
1842                                              pExtent);
1843
1844                     FileExtents[*ExtentCount].Flags |= AFS_EXTENT_FLAG_DIRTY;
1845
1846                     InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
1847
1848                     *DirtyExtents = TRUE;
1849                 }
1850
1851                 AFSReleaseResource( &Fcb->NPFcb->Specific.File.DirtyExtentsListLock);
1852             }
1853
1854             //
1855             // move forward all three cursors
1856             //
1857             le = le->Flink;
1858             ulExtentCount ++;
1859             *ExtentCount = (*ExtentCount) + 1;
1860
1861             //
1862             // And unpick
1863             //
1864             for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
1865             {
1866                 if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
1867                 {
1868                     RemoveEntryList( &pExtent->Lists[i] );
1869                 }
1870             }
1871
1872             InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
1873
1874             InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
1875
1876             //
1877             // and free
1878             //
1879             AFSExFreePool( pExtent);
1880
1881             InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
1882
1883             if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0)
1884             {
1885
1886                 KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
1887                             0,
1888                             FALSE);
1889             }
1890         }
1891
1892 try_exit:
1893
1894         NOTHING;
1895     }
1896
1897     return ntStatus;
1898 }
1899
1900 AFSFcb*
1901 AFSFindFcbToClean(ULONG IgnoreTime, AFSFcb *LastFcb, BOOLEAN Block)
1902 {
1903
1904     AFSFcb *pFcb = NULL;
1905     AFSVolumeCB *pVolumeCB = NULL;
1906     AFSDeviceExt *pRDRDeviceExt = NULL;
1907     AFSDeviceExt *pControlDeviceExt = NULL;
1908     BOOLEAN bLocatedEntry = FALSE;
1909     AFSObjectInfoCB *pCurrentObject = NULL;
1910     BOOLEAN bReleaseVolumeListLock = FALSE;
1911
1912     pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1913     pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1914
1915     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1916                   AFS_TRACE_LEVEL_VERBOSE,
1917                   "AFSFindFcbToClean Acquiring RDR VolumeListLock lock %08lX SHARED %08lX\n",
1918                   &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1919                   PsGetCurrentThread());
1920
1921     AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1922                       TRUE);
1923
1924     bReleaseVolumeListLock = TRUE;
1925
1926     pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead;
1927
1928     while( pVolumeCB != NULL)
1929     {
1930
1931         //
1932         // The Volume list may move under our feet.  Lock it.
1933         //
1934
1935         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1936                       AFS_TRACE_LEVEL_VERBOSE,
1937                       "AFSFindFcbToClean Acquiring VolumeRoot ObjectInfoTree lock %08lX SHARED %08lX\n",
1938                       pVolumeCB->ObjectInfoTree.TreeLock,
1939                       PsGetCurrentThread());
1940
1941         InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
1942
1943         AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1944
1945         bReleaseVolumeListLock = FALSE;
1946
1947         AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1948                           TRUE);
1949
1950         InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1951
1952         if( NULL == LastFcb)
1953         {
1954
1955             pCurrentObject = pVolumeCB->ObjectInfoListHead;
1956         }
1957         else
1958         {
1959
1960             pCurrentObject = (AFSObjectInfoCB *)LastFcb->ObjectInformation->ListEntry.fLink;
1961         }
1962
1963         pFcb = NULL;
1964
1965         while( pCurrentObject != NULL)
1966         {
1967
1968             pFcb = (AFSFcb *)pCurrentObject->Fcb;
1969
1970             //
1971             // If the FCB is a candidate we try to lock it (but without waiting - which
1972             // means we are deadlock free
1973             //
1974
1975             if( pFcb != NULL &&
1976                 pFcb->Header.NodeTypeCode == AFS_FILE_FCB)
1977             {
1978
1979                 if( Block)
1980                 {
1981
1982                     AFSLockForExtentsTrim( pFcb);
1983                 }
1984                 else
1985                 {
1986
1987                     if( !AFSLockForExtentsTrimNoWait( pFcb))
1988                     {
1989
1990                         pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1991
1992                         pFcb = NULL;
1993
1994                         continue;
1995                     }
1996                 }
1997
1998                 //
1999                 // Need to be sure there are no current flushes in the queue
2000                 //
2001
2002                 if( pFcb->Specific.File.ExtentCount == 0)
2003                 {
2004
2005                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2006                                   AFS_TRACE_LEVEL_VERBOSE,
2007                                   "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n",
2008                                   &pFcb->NPFcb->Specific.File.ExtentsResource,
2009                                   PsGetCurrentThread());
2010
2011                     AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
2012
2013                     pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
2014
2015                     pFcb = NULL;
2016
2017                     continue;
2018                 }
2019
2020                 if( pFcb->Specific.File.QueuedFlushCount > 0)
2021                 {
2022
2023                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2024                                   AFS_TRACE_LEVEL_VERBOSE,
2025                                   "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n",
2026                                   &pFcb->NPFcb->Specific.File.ExtentsResource,
2027                                   PsGetCurrentThread());
2028
2029                     AFSReleaseResource(&pFcb->NPFcb->Specific.File.ExtentsResource);
2030
2031                     if( Block)
2032                     {
2033                         AFSWaitOnQueuedFlushes( pFcb);
2034                     }
2035                     else
2036                     {
2037
2038                         pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
2039                     }
2040
2041                     pFcb = NULL;
2042
2043                     continue;
2044                 }
2045
2046                 if( pFcb->OpenHandleCount > 0)
2047                 {
2048
2049                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2050                                   AFS_TRACE_LEVEL_VERBOSE,
2051                                   "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n",
2052                                   &pFcb->NPFcb->Specific.File.ExtentsResource,
2053                                   PsGetCurrentThread());
2054
2055                     AFSReleaseResource(&pFcb->NPFcb->Specific.File.ExtentsResource);
2056
2057                     pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
2058
2059                     pFcb = NULL;
2060
2061                     continue;
2062                 }
2063
2064                 //
2065                 // A hit a very palpable hit.  Pin it
2066                 //
2067
2068                 InterlockedIncrement( &pCurrentObject->ObjectReferenceCount);
2069
2070                 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2071                               AFS_TRACE_LEVEL_VERBOSE,
2072                               "AFSFindFcbToClean Increment count on Fcb %08lX Cnt %d\n",
2073                               pCurrentObject,
2074                               pCurrentObject->ObjectReferenceCount);
2075
2076                 bLocatedEntry = TRUE;
2077
2078                 break;
2079             }
2080
2081             pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
2082
2083             pFcb = NULL;
2084         }
2085
2086         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
2087
2088         if( bLocatedEntry)
2089         {
2090             break;
2091         }
2092
2093         AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
2094                           TRUE);
2095
2096         bReleaseVolumeListLock = TRUE;
2097
2098         pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
2099     }
2100
2101     if( bReleaseVolumeListLock)
2102     {
2103
2104         AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
2105     }
2106
2107     return pFcb;
2108 }
2109
2110 NTSTATUS
2111 AFSProcessExtentFailure( PIRP Irp)
2112 {
2113     AFSExtentFailureCB                *pFailureCB = NULL;
2114     NTSTATUS                           ntStatus = STATUS_SUCCESS;
2115     AFSDeviceExt                      *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension;
2116     PIO_STACK_LOCATION                 pIrpSp = IoGetCurrentIrpStackLocation( Irp);
2117     AFSVolumeCB                       *pVolumeCB = NULL;
2118     ULONGLONG                          ullIndex = 0;
2119     AFSObjectInfoCB                   *pObjectInfo = NULL;
2120
2121     __Enter
2122     {
2123         if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSExtentFailureCB))
2124         {
2125
2126             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2127                           AFS_TRACE_LEVEL_ERROR,
2128                           "AFSProcessExtentFailure Input buffer too small\n");
2129
2130             try_return( ntStatus = STATUS_INVALID_PARAMETER);
2131         }
2132
2133         pFailureCB = (AFSExtentFailureCB *)Irp->AssociatedIrp.SystemBuffer;
2134
2135         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2136                       AFS_TRACE_LEVEL_ERROR,
2137                       "AFSProcessExtentFailure Service Reports Failure fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
2138                       pFailureCB->FileId.Cell,
2139                       pFailureCB->FileId.Volume,
2140                       pFailureCB->FileId.Vnode,
2141                       pFailureCB->FileId.Unique,
2142                       pFailureCB->FailureStatus);
2143
2144         AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
2145
2146         //
2147         // Locate the volume node
2148         //
2149
2150         ullIndex = AFSCreateHighIndex( &pFailureCB->FileId);
2151
2152         ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
2153                                        ullIndex,
2154                                        (AFSBTreeEntry **)&pVolumeCB);
2155
2156         if( pVolumeCB != NULL)
2157         {
2158
2159             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2160                           AFS_TRACE_LEVEL_VERBOSE,
2161                           "AFSProcessExtentFailure Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n",
2162                           pVolumeCB->ObjectInfoTree.TreeLock,
2163                           PsGetCurrentThread());
2164
2165             InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
2166         }
2167
2168         AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
2169
2170         if( !NT_SUCCESS( ntStatus) ||
2171             pVolumeCB == NULL)
2172         {
2173
2174             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2175                           AFS_TRACE_LEVEL_ERROR,
2176                           "AFSProcessExtentFailure Invalid volume index %I64X status %08X\n",
2177                           ullIndex, ntStatus);
2178
2179             try_return( ntStatus = STATUS_UNSUCCESSFUL);
2180         }
2181
2182         AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
2183                           TRUE);
2184
2185         InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
2186
2187         //
2188         // Now locate the Object in this volume
2189         //
2190
2191         ullIndex = AFSCreateLowIndex( &pFailureCB->FileId);
2192
2193         ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
2194                                        ullIndex,
2195                                        (AFSBTreeEntry **)&pObjectInfo);
2196
2197         if( pObjectInfo != NULL &&
2198             pObjectInfo->Fcb != NULL)
2199         {
2200
2201             //
2202             // Reference the node so it won't be torn down
2203             //
2204
2205             InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
2206
2207             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2208                           AFS_TRACE_LEVEL_VERBOSE,
2209                           "AFSProcessExtentFailure Increment count on object %08lX Cnt %d\n",
2210                           pObjectInfo,
2211                           pObjectInfo->ObjectReferenceCount);
2212         }
2213
2214         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
2215
2216         if( !NT_SUCCESS( ntStatus) ||
2217             pObjectInfo == NULL ||
2218             pObjectInfo->Fcb == NULL)
2219         {
2220
2221             if( pObjectInfo == NULL)
2222             {
2223                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2224                               AFS_TRACE_LEVEL_ERROR,
2225                               "AFSProcessExtentFailure Invalid file index %I64X\n",
2226                               ullIndex);
2227             }
2228             else
2229             {
2230                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2231                               AFS_TRACE_LEVEL_ERROR,
2232                               "AFSProcessExtentFailure Fcb dealocated for %I64X\n",
2233                               ullIndex);
2234             }
2235
2236             try_return( ntStatus = STATUS_UNSUCCESSFUL);
2237         }
2238
2239         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2240                       AFS_TRACE_LEVEL_VERBOSE,
2241                       "AFSProcessExtentFailure Acquiring Fcb extent lock %08lX EXCL %08lX\n",
2242                       &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
2243                       PsGetCurrentThread());
2244
2245         AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
2246                         TRUE);
2247
2248         pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = pFailureCB->FailureStatus;
2249
2250         KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
2251                     0,
2252                     FALSE);
2253
2254         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2255                       AFS_TRACE_LEVEL_VERBOSE,
2256                       "AFSProcessExtentFailure Releasing Fcb extent lock %08lX EXCL %08lX\n",
2257                       &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
2258                       PsGetCurrentThread());
2259
2260         AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource);
2261
2262         InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
2263
2264         AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2265                       AFS_TRACE_LEVEL_VERBOSE,
2266                       "AFSProcessExtentFailure Decrement count on object %08lX Cnt %d\n",
2267                       pObjectInfo,
2268                       pObjectInfo->ObjectReferenceCount);
2269
2270 try_exit:
2271
2272         NOTHING;
2273     }
2274
2275     return ntStatus;
2276 }
2277
2278 NTSTATUS
2279 AFSProcessReleaseFileExtents( IN PIRP Irp)
2280 {
2281     NTSTATUS                           ntStatus = STATUS_SUCCESS;
2282     PIO_STACK_LOCATION                 pIrpSp = IoGetCurrentIrpStackLocation( Irp);
2283     PFILE_OBJECT                       pFileObject = pIrpSp->FileObject;
2284     AFSFcb                            *pFcb = NULL;
2285     AFSVolumeCB                       *pVolumeCB = NULL;
2286     AFSDeviceExt                      *pDevExt;
2287     AFSReleaseFileExtentsCB           *pExtents;
2288     AFSReleaseFileExtentsResultCB     *pResult = NULL;
2289     AFSReleaseFileExtentsResultFileCB *pFile = NULL;
2290     ULONG                              ulSz = 0;
2291     ULONGLONG                          ullIndex = 0;
2292     AFSObjectInfoCB                   *pObjectInfo = NULL;
2293     BOOLEAN                            bLocked = FALSE;
2294     BOOLEAN                            bDirtyExtents = FALSE;
2295
2296     __Enter
2297     {
2298
2299         pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension;
2300
2301         pExtents = (AFSReleaseFileExtentsCB*) Irp->AssociatedIrp.SystemBuffer;
2302
2303         if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2304                                             sizeof( AFSReleaseFileExtentsCB))
2305         {
2306
2307             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2308                           AFS_TRACE_LEVEL_ERROR,
2309                           "AFSProcessReleaseFileExtents INPUT Buffer too small\n");
2310
2311             try_return( ntStatus = STATUS_INVALID_PARAMETER );
2312         }
2313
2314         if ( pIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
2315                                         sizeof(AFSReleaseFileExtentsResultCB))
2316         {
2317
2318             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2319                           AFS_TRACE_LEVEL_ERROR,
2320                           "AFSProcessReleaseFileExtents OUTPUT Buffer too small [1]\n");
2321
2322             //
2323             // Must have space for one extent in one file
2324             //
2325
2326             try_return( ntStatus = STATUS_BUFFER_TOO_SMALL);
2327         }
2328
2329         if (pExtents->ExtentCount == 0)
2330         {
2331
2332             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2333                           AFS_TRACE_LEVEL_ERROR,
2334                           "AFSProcessReleaseFileExtents Extent count zero\n");
2335
2336             try_return( ntStatus = STATUS_INVALID_PARAMETER);
2337         }
2338
2339         if (pExtents->FileId.Cell   != 0 ||
2340             pExtents->FileId.Volume != 0 ||
2341             pExtents->FileId.Vnode  != 0 ||
2342             pExtents->FileId.Unique != 0)
2343         {
2344
2345             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2346                           AFS_TRACE_LEVEL_VERBOSE,
2347                           "AFSProcessReleaseFileExtents Processing FID %08lX:%08lX:%08lX:%08lX\n",
2348                           pExtents->FileId.Cell,
2349                           pExtents->FileId.Volume,
2350                           pExtents->FileId.Vnode,
2351                           pExtents->FileId.Unique);
2352
2353             if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2354                             ( FIELD_OFFSET( AFSReleaseFileExtentsCB, ExtentCount) + sizeof(ULONG)) ||
2355                 pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2356                             ( FIELD_OFFSET( AFSReleaseFileExtentsCB, ExtentCount) + sizeof(ULONG) +
2357                                                             sizeof (AFSFileExtentCB) * pExtents->ExtentCount))
2358             {
2359
2360                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2361                               AFS_TRACE_LEVEL_ERROR,
2362                               "AFSProcessReleaseFileExtents Buffer too small for FID %08lX:%08lx:%08lX:%08lX\n",
2363                               pExtents->FileId.Cell,
2364                               pExtents->FileId.Volume,
2365                               pExtents->FileId.Vnode,
2366                               pExtents->FileId.Unique);
2367
2368                 try_return( ntStatus = STATUS_INVALID_PARAMETER );
2369             }
2370
2371             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2372                           AFS_TRACE_LEVEL_VERBOSE,
2373                           "AFSProcessReleaseFileExtents Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n",
2374                           &pDevExt->Specific.RDR.VolumeTreeLock,
2375                           PsGetCurrentThread());
2376
2377             AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
2378
2379             //
2380             // Locate the volume node
2381             //
2382
2383             ullIndex = AFSCreateHighIndex( &pExtents->FileId);
2384
2385             ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
2386                                            ullIndex,
2387                                            (AFSBTreeEntry **)&pVolumeCB);
2388
2389             if( pVolumeCB != NULL)
2390             {
2391
2392                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2393                               AFS_TRACE_LEVEL_VERBOSE,
2394                               "AFSProcessReleaseFileExtents Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n",
2395                               pVolumeCB->ObjectInfoTree.TreeLock,
2396                               PsGetCurrentThread());
2397
2398                 InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
2399             }
2400
2401             AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
2402
2403             if( !NT_SUCCESS( ntStatus) ||
2404                 pVolumeCB == NULL)
2405             {
2406
2407                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2408                               AFS_TRACE_LEVEL_ERROR,
2409                               "AFSProcessReleaseFileExtents Invalid volume index %I64X status %08X\n",
2410                               ullIndex, ntStatus);
2411
2412                 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2413             }
2414
2415             AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
2416                               TRUE);
2417
2418             InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
2419
2420             //
2421             // Now locate the Object in this volume
2422             //
2423
2424             ullIndex = AFSCreateLowIndex( &pExtents->FileId);
2425
2426             ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
2427                                            ullIndex,
2428                                            (AFSBTreeEntry **)&pObjectInfo);
2429
2430             if( pObjectInfo != NULL)
2431             {
2432
2433                 //
2434                 // Reference the node so it won't be torn down
2435                 //
2436
2437                 InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
2438
2439                 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2440                               AFS_TRACE_LEVEL_VERBOSE,
2441                               "AFSProcessReleaseFileExtents Increment count on object %08lX Cnt %d\n",
2442                               pObjectInfo,
2443                               pObjectInfo->ObjectReferenceCount);
2444             }
2445
2446             AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
2447
2448             if( !NT_SUCCESS( ntStatus) ||
2449                 pObjectInfo == NULL)
2450             {
2451
2452                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2453                               AFS_TRACE_LEVEL_ERROR,
2454                               "AFSProcessReleaseFileExtents Invalid file index %I64X\n",
2455                               ullIndex);
2456
2457                 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2458             }
2459
2460             pFcb = pObjectInfo->Fcb;
2461
2462             if( pFcb == NULL)
2463             {
2464
2465                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2466                               AFS_TRACE_LEVEL_ERROR,
2467                               "AFSProcessReleaseFileExtents Fcb not initialied (NO EXTENTS) for FID %08lX:%08lx:%08lX:%08lX\n",
2468                               pExtents->FileId.Cell,
2469                               pExtents->FileId.Volume,
2470                               pExtents->FileId.Vnode,
2471                               pExtents->FileId.Unique);
2472
2473                 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2474             }
2475
2476             AFSLockForExtentsTrim( pFcb );
2477
2478             bLocked = TRUE;
2479         }
2480         else
2481         {
2482
2483             //
2484             // Locate an Fcb to trim down
2485             //
2486
2487             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2488                           AFS_TRACE_LEVEL_VERBOSE,
2489                           "AFSProcessReleaseFileExtents Searching for a Fcb to Trim Down\n");
2490
2491             pFcb = AFSFindFcbToClean( 0, NULL, FALSE);
2492
2493             if( pFcb == NULL)
2494             {
2495
2496                 pFcb = AFSFindFcbToClean( 0, NULL, TRUE);
2497             }
2498
2499             if( pFcb == NULL)
2500             {
2501
2502                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2503                               AFS_TRACE_LEVEL_ERROR,
2504                               "AFSProcessReleaseFileExtents Failed to locate Fcb for release ...\n");
2505
2506                 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2507             }
2508
2509             pObjectInfo = pFcb->ObjectInformation;
2510
2511             bLocked = TRUE;
2512         }
2513
2514         //
2515         // Allocate a scratch buffer to move in the extent information
2516         //
2517
2518         ulSz = (pExtents->ExtentCount-1) * sizeof(AFSFileExtentCB);
2519         ulSz += sizeof(AFSReleaseFileExtentsResultCB);
2520
2521         if (ulSz > pIrpSp->Parameters.DeviceIoControl.OutputBufferLength)
2522         {
2523             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2524                           AFS_TRACE_LEVEL_ERROR,
2525                           "AFSProcessReleaseFileExtents OUTPUT Buffer too small [2]\n");
2526
2527             try_return( ntStatus = STATUS_BUFFER_TOO_SMALL );
2528         }
2529
2530         pResult = (AFSReleaseFileExtentsResultCB*) AFSExAllocatePoolWithTag( PagedPool,
2531                                                                              ulSz,
2532                                                                              AFS_EXTENTS_RESULT_TAG);
2533         if (NULL == pResult)
2534         {
2535
2536             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2537                           AFS_TRACE_LEVEL_ERROR,
2538                           "AFSProcessReleaseFileExtents Failed to allocate result block\n");
2539
2540             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2541         }
2542
2543         //
2544         // Set up the header (for an array of one)
2545         //
2546         pResult->FileCount = 1;
2547         pResult->Flags = AFS_EXTENT_FLAG_RELEASE;
2548         ulSz -= FIELD_OFFSET(AFSReleaseFileExtentsResultCB, Files);
2549
2550         //
2551         // Setup the first (and only) file
2552         //
2553         pFile = pResult->Files;
2554         pFile->FileId = pObjectInfo->FileId;
2555         pFile->Flags = AFS_EXTENT_FLAG_RELEASE;
2556
2557         //
2558         // Stash away the auth group
2559         //
2560
2561         RtlCopyMemory( &pFile->AuthGroup,
2562                        &pFcb->AuthGroup,
2563                        sizeof( GUID));
2564
2565         //
2566         // Update the metadata for this call
2567         //
2568
2569         pFile->AllocationSize = pFcb->ObjectInformation->EndOfFile;
2570         pFile->CreateTime = pFcb->ObjectInformation->CreationTime;
2571         pFile->ChangeTime = pFcb->ObjectInformation->ChangeTime;
2572         pFile->LastAccessTime = pFcb->ObjectInformation->LastAccessTime;
2573         pFile->LastWriteTime = pFcb->ObjectInformation->LastWriteTime;
2574
2575         ulSz -= FIELD_OFFSET(AFSReleaseFileExtentsResultFileCB, FileExtents);
2576
2577         ntStatus = AFSReleaseSpecifiedExtents( pExtents,
2578                                                pFcb,
2579                                                pFile->FileExtents,
2580                                                ulSz,
2581                                                &pFile->ExtentCount,
2582                                                &bDirtyExtents);
2583
2584         if (!NT_SUCCESS(ntStatus))
2585         {
2586
2587             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2588                           AFS_TRACE_LEVEL_ERROR,
2589                           "AFSProcessReleaseFileExtents Failed to release extents Status %08lX\n",
2590                           ntStatus);
2591
2592             try_return( ntStatus );
2593         }
2594
2595         if( pExtents->ExtentCount == 0)
2596         {
2597
2598             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2599                           AFS_TRACE_LEVEL_WARNING,
2600                           "AFSProcessReleaseFileExtents Failed to release ANY extents\n");
2601         }
2602
2603         ulSz = sizeof(AFSReleaseFileExtentsResultCB);
2604
2605         if( pExtents->ExtentCount > 0)
2606         {
2607             ulSz += ((pExtents->ExtentCount-1) * sizeof(AFSFileExtentCB));
2608         }
2609
2610         RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer,
2611                        pResult,
2612                        ulSz);
2613
2614 try_exit:
2615
2616         if( bLocked)
2617         {
2618
2619             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2620                           AFS_TRACE_LEVEL_VERBOSE,
2621                           "AFSProcessReleaseFileExtents Releasing Fcb extent lock %08lX thread %08lX\n",
2622                           &pFcb->NPFcb->Specific.File.ExtentsResource,
2623                           PsGetCurrentThread());
2624
2625             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
2626         }
2627
2628         if( NULL != pResult &&
2629             Irp->AssociatedIrp.SystemBuffer != pResult)
2630         {
2631
2632             AFSExFreePool(pResult);
2633         }
2634
2635         if (NT_SUCCESS(ntStatus))
2636         {
2637             Irp->IoStatus.Information = ulSz;
2638         }
2639         else
2640         {
2641             Irp->IoStatus.Information = 0;
2642         }
2643
2644         Irp->IoStatus.Status = ntStatus;
2645
2646         if( pObjectInfo != NULL)
2647         {
2648
2649             InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
2650
2651             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2652                           AFS_TRACE_LEVEL_VERBOSE,
2653                           "AFSProcessReleaseFileExtents Decrement count on object %08lX Cnt %d\n",
2654                           pObjectInfo,
2655                           pObjectInfo->ObjectReferenceCount);
2656         }
2657     }
2658
2659     return ntStatus;
2660 }
2661
2662 NTSTATUS
2663 AFSWaitForExtentMapping( AFSFcb *Fcb )
2664 {
2665     NTSTATUS ntStatus = STATUS_SUCCESS;
2666     LARGE_INTEGER liTimeOut;
2667     ULONGLONG            ullProcessId = (ULONGLONG)PsGetCurrentProcessId();
2668
2669     __Enter
2670     {
2671
2672         ASSERT( !ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
2673
2674         if (!NT_SUCCESS( Fcb->NPFcb->Specific.File.ExtentsRequestStatus))
2675         {
2676
2677             //
2678             // If this isn't the same process which caused the failure then try to request them again
2679             //
2680
2681             if( Fcb->Specific.File.ExtentRequestProcessId == ullProcessId)
2682             {
2683                 try_return( ntStatus = Fcb->NPFcb->Specific.File.ExtentsRequestStatus);
2684             }
2685
2686             Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
2687         }
2688
2689         liTimeOut.QuadPart = -(50000000);
2690
2691         ntStatus = KeWaitForSingleObject( &Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
2692                                           Executive,
2693                                           KernelMode,
2694                                           FALSE,
2695                                           &liTimeOut);
2696
2697         if (!NT_SUCCESS( Fcb->NPFcb->Specific.File.ExtentsRequestStatus))
2698         {
2699
2700             //
2701             // If this isn't the same process which caused the failure
2702             // and this isn't the System process, then try to request them again
2703             //
2704
2705             if( Fcb->Specific.File.ExtentRequestProcessId == ullProcessId ||
2706                 ullProcessId == 0x4)
2707             {
2708                 try_return( ntStatus = Fcb->NPFcb->Specific.File.ExtentsRequestStatus);
2709             }
2710
2711             Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
2712         }
2713
2714         if( ntStatus == STATUS_TIMEOUT)
2715         {
2716
2717             ntStatus = STATUS_SUCCESS;
2718         }
2719
2720 try_exit:
2721
2722         NOTHING;
2723     }
2724
2725     return ntStatus;
2726 }
2727
2728 NTSTATUS
2729 AFSFlushExtents( IN AFSFcb *Fcb)
2730 {
2731     AFSNonPagedFcb      *pNPFcb = Fcb->NPFcb;
2732     AFSExtent           *pExtent, *pNextExtent;
2733     LIST_ENTRY          *le;
2734     AFSReleaseExtentsCB *pRelease = NULL;
2735     ULONG                count = 0;
2736     ULONG                initialDirtyCount = 0;
2737     BOOLEAN              bExtentsLocked = FALSE;
2738     ULONG                total = 0;
2739     ULONG                sz = 0;
2740     NTSTATUS             ntStatus = STATUS_SUCCESS;
2741     LARGE_INTEGER        liLastFlush;
2742     AFSExtent           *pDirtyListHead = NULL, *pDirtyListTail = NULL;
2743     AFSDeviceExt        *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2744
2745     ASSERT( Fcb->Header.NodeTypeCode == AFS_FILE_FCB);
2746
2747     //
2748     // Save, then reset the flush time
2749     //
2750
2751     liLastFlush = Fcb->Specific.File.LastServerFlush;
2752
2753     KeQueryTickCount( &Fcb->Specific.File.LastServerFlush);
2754
2755     __Enter
2756     {
2757
2758         //
2759         // Lock extents while we count and set up the array to send to
2760         // the service
2761         //
2762
2763         AFSLockForExtentsTrim( Fcb);
2764
2765         bExtentsLocked = TRUE;
2766
2767         InterlockedIncrement( &Fcb->Specific.File.QueuedFlushCount);
2768
2769         //
2770         // Clear our queued flush event
2771         //
2772
2773         KeClearEvent( &Fcb->NPFcb->Specific.File.QueuedFlushEvent);
2774
2775         //
2776         // Look for a start in the list to flush entries
2777         //
2778
2779         total = count;
2780
2781         sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
2782
2783         pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
2784                                                                     sz,
2785                                                                     AFS_EXTENT_RELEASE_TAG);
2786         if( NULL == pRelease)
2787         {
2788
2789             try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2790         }
2791
2792         initialDirtyCount = Fcb->Specific.File.ExtentsDirtyCount;
2793
2794         while( Fcb->Specific.File.ExtentsDirtyCount > 0)
2795         {
2796
2797             pRelease->Flags = AFS_EXTENT_FLAG_DIRTY;
2798
2799             if( BooleanFlagOn( Fcb->Flags, AFS_FCB_FILE_CLOSED))
2800             {
2801
2802                 pRelease->Flags |= AFS_EXTENT_FLAG_FLUSH;
2803             }
2804
2805             //
2806             // Update the metadata for this call
2807             //
2808
2809             pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
2810             pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
2811             pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
2812             pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
2813             pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
2814
2815             count = 0;
2816
2817             AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
2818                             TRUE);
2819
2820             pExtent = (AFSExtent *)pNPFcb->Specific.File.DirtyListHead;
2821
2822             while( count < AFS_MAXIMUM_EXTENT_RELEASE_COUNT)
2823             {
2824
2825                 if ( pExtent == NULL)
2826                 {
2827
2828                     break;
2829                 }
2830
2831                 pNextExtent = (AFSExtent *)pExtent->DirtyList.fLink;
2832
2833                 if ( pExtent->ActiveCount > 0)
2834                 {
2835                     pExtent = pNextExtent;
2836                     continue;
2837                 }
2838
2839                 AFSRemoveEntryDirtyList( Fcb, pExtent);
2840
2841                 pExtent->DirtyList.fLink = NULL;
2842                 pExtent->DirtyList.bLink = NULL;
2843
2844                 InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
2845
2846                 //
2847                 // Clear the flag in advance of the write. If we do
2848                 // things this was we know that the clear is
2849                 // pessimistic (any write which happens from now on
2850                 // will set the flag dirty again).
2851                 //
2852
2853                 pExtent->Flags &= ~AFS_EXTENT_DIRTY;
2854
2855                 pRelease->FileExtents[count].Flags = AFS_EXTENT_FLAG_DIRTY;
2856
2857                 pRelease->FileExtents[count].Length = pExtent->Size;
2858                 pRelease->FileExtents[count].DirtyLength = pExtent->Size;
2859                 pRelease->FileExtents[count].DirtyOffset = 0;
2860                 pRelease->FileExtents[count].CacheOffset = pExtent->CacheOffset;
2861                 pRelease->FileExtents[count].FileOffset = pExtent->FileOffset;
2862
2863 #if GEN_MD5
2864                 RtlCopyMemory( pRelease->FileExtents[count].MD5,
2865                                pExtent->MD5,
2866                                sizeof(pExtent->MD5));
2867
2868                 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_MD5_SET;
2869 #endif
2870
2871                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2872                               AFS_TRACE_LEVEL_VERBOSE,
2873                               "AFSFlushExtents Releasing DIRTY extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
2874                               pExtent,
2875                               Fcb->ObjectInformation->FileId.Cell,
2876                               Fcb->ObjectInformation->FileId.Volume,
2877                               Fcb->ObjectInformation->FileId.Vnode,
2878                               Fcb->ObjectInformation->FileId.Unique,
2879                               pExtent->FileOffset.QuadPart,
2880                               pExtent->Size);
2881
2882                 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_RELEASE;
2883
2884                 //
2885                 // Need to pull this extent from the main list as well
2886                 //
2887
2888                 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
2889                 {
2890                     if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
2891                     {
2892                         RemoveEntryList( &pExtent->Lists[i] );
2893                     }
2894                 }
2895
2896                 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
2897
2898                 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
2899
2900                 AFSExFreePool( pExtent);
2901
2902                 InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
2903
2904                 if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0)
2905                 {
2906
2907                     KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
2908                                 0,
2909                                 FALSE);
2910                 }
2911
2912                 count ++;
2913
2914                 pExtent = pNextExtent;
2915             }
2916
2917             AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
2918
2919             //
2920             // If we are done then get out
2921             //
2922
2923             if( count == 0)
2924             {
2925
2926                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2927                               AFS_TRACE_LEVEL_VERBOSE,
2928                               "AFSFlushExtents No more dirty extents found\n");
2929
2930                 break;
2931             }
2932
2933             //
2934             // Fire off the request synchronously
2935             //
2936
2937             sz = sizeof( AFSReleaseExtentsCB ) + (count * sizeof ( AFSFileExtentCB ));
2938
2939             pRelease->ExtentCount = count;
2940
2941             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2942                           AFS_TRACE_LEVEL_VERBOSE,
2943                           "AFSFlushExtents Releasing(1) Fcb extents lock %08lX SHARED %08lX\n",
2944                           &pNPFcb->Specific.File.ExtentsResource,
2945                           PsGetCurrentThread());
2946
2947             AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource);
2948             bExtentsLocked = FALSE;
2949
2950             KeSetEvent( &pNPFcb->Specific.File.FlushEvent,
2951                         0,
2952                         FALSE);
2953
2954             ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS,
2955                                           AFS_REQUEST_FLAG_SYNCHRONOUS,
2956                                           &Fcb->AuthGroup,
2957                                           NULL,
2958                                           &Fcb->ObjectInformation->FileId,
2959                                           pRelease,
2960                                           sz,
2961                                           NULL,
2962                                           NULL);
2963
2964             if( !NT_SUCCESS(ntStatus))
2965             {
2966
2967                 //
2968                 // Regardless of whether or not the AFSProcessRequest() succeeded, the extents
2969                 // were released (if AFS_EXTENT_FLAG_RELEASE was set).  Log the error so it is known.
2970                 //
2971
2972                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2973                               AFS_TRACE_LEVEL_ERROR,
2974                               "AFSFlushExtents AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
2975                               Fcb->ObjectInformation->FileId.Cell,
2976                               Fcb->ObjectInformation->FileId.Volume,
2977                               Fcb->ObjectInformation->FileId.Vnode,
2978                               Fcb->ObjectInformation->FileId.Unique,
2979                               ntStatus);
2980
2981             }
2982             AFSLockForExtentsTrim( Fcb);
2983
2984             bExtentsLocked = TRUE;
2985         }
2986
2987 try_exit:
2988
2989         if( InterlockedDecrement( &Fcb->Specific.File.QueuedFlushCount) == 0)
2990         {
2991
2992             KeSetEvent( &pNPFcb->Specific.File.QueuedFlushEvent,
2993                         0,
2994                         FALSE);
2995         }
2996
2997         KeSetEvent( &pNPFcb->Specific.File.FlushEvent,
2998                     0,
2999                     FALSE);
3000
3001         if (bExtentsLocked)
3002         {
3003
3004             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3005                           AFS_TRACE_LEVEL_VERBOSE,
3006                           "AFSFlushExtents Releasing(2) Fcb extents lock %08lX SHARED %08lX\n",
3007                           &pNPFcb->Specific.File.ExtentsResource,
3008                           PsGetCurrentThread());
3009
3010             AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
3011         }
3012
3013         if (pRelease)
3014         {
3015             AFSExFreePool( pRelease);
3016         }
3017     }
3018
3019     return ntStatus;
3020 }
3021
3022 NTSTATUS
3023 AFSReleaseExtentsWithFlush( IN AFSFcb *Fcb)
3024 {
3025     AFSNonPagedFcb      *pNPFcb = Fcb->NPFcb;
3026     AFSExtent           *pExtent;
3027     LIST_ENTRY          *le;
3028     AFSReleaseExtentsCB *pRelease = NULL;
3029     ULONG                count = 0;
3030     ULONG                initialDirtyCount = 0;
3031     BOOLEAN              bExtentsLocked = FALSE;
3032     ULONG                total = 0;
3033     ULONG                sz = 0;
3034     NTSTATUS             ntStatus = STATUS_SUCCESS;
3035     LARGE_INTEGER        liLastFlush;
3036     ULONG                ulRemainingExtentLength = 0;
3037     AFSDeviceExt        *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
3038
3039     ASSERT( Fcb->Header.NodeTypeCode == AFS_FILE_FCB);
3040
3041     //
3042     // Save, then reset the flush time
3043     //
3044
3045     liLastFlush = Fcb->Specific.File.LastServerFlush;
3046
3047     KeQueryTickCount( &Fcb->Specific.File.LastServerFlush);
3048
3049     __Enter
3050     {
3051
3052         //
3053         // Look for a start in the list to flush entries
3054         //
3055
3056         total = count;
3057
3058         sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
3059
3060         pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
3061                                                                     sz,
3062                                                                     AFS_EXTENT_RELEASE_TAG);
3063         if( NULL == pRelease)
3064         {
3065
3066             try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
3067         }
3068
3069         if( Fcb->OpenHandleCount > 0)
3070         {
3071
3072             //
3073             // Don't release everything ...
3074             //
3075
3076             //
3077             // For now release everything
3078             //
3079
3080             //ulRemainingExtentLength = 1500;
3081         }
3082
3083         while( Fcb->Specific.File.ExtentLength > (LONG)ulRemainingExtentLength)
3084         {
3085
3086             AFSLockForExtentsTrim( Fcb);
3087
3088             bExtentsLocked = TRUE;
3089
3090             pRelease->Flags = AFS_EXTENT_FLAG_RELEASE;
3091
3092             //
3093             // Update the metadata for this call
3094             //
3095
3096             pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
3097             pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
3098             pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
3099             pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
3100             pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
3101
3102             count = 0;
3103
3104             le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
3105
3106             while( count < AFS_MAXIMUM_EXTENT_RELEASE_COUNT &&
3107                    le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
3108             {
3109
3110                 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
3111
3112                 le = le->Flink;
3113
3114                 if( pExtent->ActiveCount > 0)
3115                 {
3116
3117                     continue;
3118                 }
3119
3120                 pRelease->FileExtents[count].Flags = AFS_EXTENT_FLAG_RELEASE;
3121
3122                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3123                               AFS_TRACE_LEVEL_VERBOSE,
3124                               "AFSReleaseExtentsWithFlush Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
3125                               pExtent,
3126                               Fcb->ObjectInformation->FileId.Cell,
3127                               Fcb->ObjectInformation->FileId.Volume,
3128                               Fcb->ObjectInformation->FileId.Vnode,
3129                               Fcb->ObjectInformation->FileId.Unique,
3130                               pExtent->FileOffset.QuadPart,
3131                               pExtent->Size);
3132
3133                 pRelease->FileExtents[count].Length = pExtent->Size;
3134                 pRelease->FileExtents[count].DirtyLength = pExtent->Size;
3135                 pRelease->FileExtents[count].DirtyOffset = 0;
3136                 pRelease->FileExtents[count].CacheOffset = pExtent->CacheOffset;
3137                 pRelease->FileExtents[count].FileOffset = pExtent->FileOffset;
3138
3139 #if GEN_MD5
3140                 RtlCopyMemory( pRelease->FileExtents[count].MD5,
3141                                pExtent->MD5,
3142                                sizeof(pExtent->MD5));
3143
3144                 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_MD5_SET;
3145 #endif
3146
3147                 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3148                 {
3149
3150                     AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
3151                                     TRUE);
3152
3153                     if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3154                     {
3155
3156                         AFSRemoveEntryDirtyList( Fcb,
3157                                                  pExtent);
3158
3159                         pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_DIRTY;
3160
3161                         InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
3162                     }
3163
3164                     AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
3165                 }
3166
3167                 //
3168                 // Need to pull this extent from the main list as well
3169                 //
3170
3171                 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
3172                 {
3173                     if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
3174                     {
3175                         RemoveEntryList( &pExtent->Lists[i] );
3176                     }
3177                 }
3178
3179                 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
3180
3181                 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
3182
3183                 AFSExFreePool( pExtent);
3184
3185                 InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
3186
3187                 if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0)
3188                 {
3189
3190                     KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
3191                                 0,
3192                                 FALSE);
3193                 }
3194
3195                 count ++;
3196             }
3197
3198             //
3199             // If we are done then get out
3200             //
3201
3202             if( count == 0)
3203             {
3204
3205                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3206                               AFS_TRACE_LEVEL_VERBOSE,
3207                               "AFSReleaseExtentsWithFlush No more dirty extents found\n");
3208
3209                 break;
3210             }
3211
3212             //
3213             // Fire off the request synchronously
3214             //
3215
3216             sz = sizeof( AFSReleaseExtentsCB ) + (count * sizeof ( AFSFileExtentCB ));
3217
3218             pRelease->ExtentCount = count;
3219
3220             //
3221             // Drop the extents lock for the duration of the call to
3222             // the network.  We have pinned the extents so, even
3223             // though we might get extents added during this period,
3224             // but none will be removed.  Hence we can carry on from
3225             // le.
3226             //
3227
3228             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3229                           AFS_TRACE_LEVEL_VERBOSE,
3230                           "AFSReleaseExtentsWithFlush Releasing Fcb extents lock %08lX thread %08lX\n",
3231                           &pNPFcb->Specific.File.ExtentsResource,
3232                           PsGetCurrentThread());
3233
3234             AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource);
3235             bExtentsLocked = FALSE;
3236
3237             ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS,
3238                                           AFS_REQUEST_FLAG_SYNCHRONOUS,
3239                                           &Fcb->AuthGroup,
3240                                           NULL,
3241                                           &Fcb->ObjectInformation->FileId,
3242                                           pRelease,
3243                                           sz,
3244                                           NULL,
3245                                           NULL);
3246
3247             if( !NT_SUCCESS(ntStatus))
3248             {
3249
3250                 //
3251                 // Regardless of whether or not the AFSProcessRequest() succeeded, the extents
3252                 // were released (if AFS_EXTENT_FLAG_RELEASE was set).  Log the error so it is known.
3253                 //
3254
3255                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3256                               AFS_TRACE_LEVEL_ERROR,
3257                               "AFSReleaseExtentsWithFlush AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
3258                               Fcb->ObjectInformation->FileId.Cell,
3259                               Fcb->ObjectInformation->FileId.Volume,
3260                               Fcb->ObjectInformation->FileId.Vnode,
3261                               Fcb->ObjectInformation->FileId.Unique,
3262                               ntStatus);
3263             }
3264         }
3265
3266 try_exit:
3267
3268         if (bExtentsLocked)
3269         {
3270
3271             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3272                           AFS_TRACE_LEVEL_VERBOSE,
3273                           "AFSReleaseExtentsWithFlush Releasing Fcb extents lock %08lX thread %08lX\n",
3274                           &pNPFcb->Specific.File.ExtentsResource,
3275                           PsGetCurrentThread());
3276
3277             AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
3278         }
3279
3280         if (pRelease)
3281         {
3282             AFSExFreePool( pRelease);
3283         }
3284     }
3285
3286     return ntStatus;
3287 }
3288
3289 VOID
3290 AFSMarkDirty( IN AFSFcb *Fcb,
3291               IN AFSExtent *StartExtent,
3292               IN ULONG ExtentsCount,
3293               IN LARGE_INTEGER *StartingByte)
3294 {
3295
3296     AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
3297     AFSExtent     *pExtent = StartExtent;
3298     AFSExtent     *pNextExtent, *pCurrentExtent = NULL;
3299     ULONG ulCount = 0;
3300     BOOLEAN bInsertTail = FALSE, bInsertHead = FALSE;
3301
3302     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3303                   AFS_TRACE_LEVEL_VERBOSE,
3304                   "AFSMarkDirty Acquiring Fcb extents lock %08lX SHARED %08lX\n",
3305                   &Fcb->NPFcb->Specific.File.ExtentsResource,
3306                   PsGetCurrentThread());
3307
3308     AFSAcquireShared( &Fcb->NPFcb->Specific.File.ExtentsResource, TRUE);
3309
3310     AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
3311                     TRUE);
3312
3313     //
3314     // Find the insertion point
3315     //
3316
3317     if( pNPFcb->Specific.File.DirtyListHead == NULL)
3318     {
3319
3320         bInsertTail = TRUE;
3321     }
3322     else if( StartingByte->QuadPart == 0)
3323     {
3324
3325         bInsertHead = TRUE;
3326     }
3327     else
3328     {
3329
3330         pCurrentExtent = pNPFcb->Specific.File.DirtyListHead;
3331
3332         while( pCurrentExtent != NULL)
3333         {
3334
3335             if( pCurrentExtent->FileOffset.QuadPart + pCurrentExtent->Size >= StartingByte->QuadPart ||
3336                 pCurrentExtent->DirtyList.fLink == NULL)
3337             {
3338
3339                 break;
3340             }
3341
3342             pCurrentExtent = (AFSExtent *)pCurrentExtent->DirtyList.fLink;
3343         }
3344     }
3345
3346     while( ulCount < ExtentsCount)
3347     {
3348
3349         pNextExtent = NextExtent( pExtent, AFS_EXTENTS_LIST);
3350
3351         if( !BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3352         {
3353
3354             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3355                           AFS_TRACE_LEVEL_VERBOSE,
3356                           "AFSMarkDirty Marking extent offset %I64X Length %08lX DIRTY\n",
3357                           pExtent->FileOffset.QuadPart,
3358                           pExtent->Size);
3359
3360             pExtent->DirtyList.fLink = NULL;
3361             pExtent->DirtyList.bLink = NULL;
3362
3363             if( bInsertHead)
3364             {
3365
3366                 pExtent->DirtyList.fLink = (void *)pNPFcb->Specific.File.DirtyListHead;
3367
3368                 pExtent->DirtyList.bLink = NULL;
3369
3370                 pNPFcb->Specific.File.DirtyListHead->DirtyList.bLink = (void *)pExtent;
3371
3372                 pNPFcb->Specific.File.DirtyListHead = pExtent;
3373
3374                 pCurrentExtent = pExtent;
3375
3376                 bInsertHead = FALSE;
3377             }
3378             else if( bInsertTail)
3379             {
3380
3381                 if( pNPFcb->Specific.File.DirtyListHead == NULL)
3382                 {
3383
3384                     pNPFcb->Specific.File.DirtyListHead = pExtent;
3385                 }
3386                 else
3387                 {
3388
3389                     pNPFcb->Specific.File.DirtyListTail->DirtyList.fLink = (void *)pExtent;
3390
3391                     pExtent->DirtyList.bLink = (void *)pNPFcb->Specific.File.DirtyListTail;
3392                 }
3393
3394                 pNPFcb->Specific.File.DirtyListTail = pExtent;
3395             }
3396             else
3397             {
3398
3399                 pExtent->DirtyList.fLink = pCurrentExtent->DirtyList.fLink;
3400                 pExtent->DirtyList.bLink = (void *)pCurrentExtent;
3401
3402                 if( pExtent->DirtyList.fLink == NULL)
3403                 {
3404
3405                     pNPFcb->Specific.File.DirtyListTail = pExtent;
3406                 }
3407                 else
3408                 {
3409
3410                     ((AFSExtent *)pExtent->DirtyList.fLink)->DirtyList.bLink = (void *)pExtent;
3411                 }
3412
3413                 pCurrentExtent->DirtyList.fLink = (void *)pExtent;
3414
3415                 pCurrentExtent = pExtent;
3416             }
3417
3418             pExtent->Flags |= AFS_EXTENT_DIRTY;
3419
3420             //
3421             // Up the dirty count
3422             //
3423
3424             InterlockedIncrement( &Fcb->Specific.File.ExtentsDirtyCount);
3425         }
3426         else
3427         {
3428
3429             pCurrentExtent = pExtent;
3430         }
3431
3432         AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_ACTIVE_COUNTING,
3433                       AFS_TRACE_LEVEL_VERBOSE,
3434                       "AFSMarkDirty Decrement count on extent %08lX Cnt %d\n",
3435                       pExtent,
3436                       pExtent->ActiveCount);
3437
3438         ASSERT( pExtent->ActiveCount > 0);
3439
3440         InterlockedDecrement( &pExtent->ActiveCount);
3441
3442         pExtent = pNextExtent;
3443
3444         ulCount++;
3445     }
3446
3447     AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
3448
3449     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3450                   AFS_TRACE_LEVEL_VERBOSE,
3451                   "AFSMarkDirty Releasing Fcb extents lock %08lX SHARED %08lX\n",
3452                   &Fcb->NPFcb->Specific.File.ExtentsResource,
3453                   PsGetCurrentThread());
3454
3455     AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource );
3456
3457     return;
3458 }
3459
3460 //
3461 // Helper functions
3462 //
3463
3464 static AFSExtent *ExtentFor(PLIST_ENTRY le, ULONG SkipList)
3465 {
3466     return CONTAINING_RECORD( le, AFSExtent, Lists[SkipList] );
3467 }
3468
3469 static AFSExtent *NextExtent(AFSExtent *Extent, ULONG SkipList)
3470 {
3471     return ExtentFor(Extent->Lists[SkipList].Flink, SkipList);
3472 }
3473
3474 static AFSExtent *DirtyExtentFor(PLIST_ENTRY le)
3475 {
3476     return CONTAINING_RECORD( le, AFSExtent, DirtyList );
3477 }
3478
3479 static VOID VerifyExtentsLists(AFSFcb *Fcb)
3480 {
3481 #if DBG > 0
3482     //
3483     // Check the ordering of the extents lists
3484     //
3485     ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
3486
3487     ASSERT(Fcb->Specific.File.ExtentsLists[0].Flink != &Fcb->Specific.File.ExtentsLists[1]);
3488
3489     for (ULONG listNo = 0; listNo < AFS_NUM_EXTENT_LISTS; listNo ++)
3490     {
3491         LARGE_INTEGER lastOffset;
3492
3493         lastOffset.QuadPart = 0;
3494
3495         for (PLIST_ENTRY pLe = Fcb->Specific.File.ExtentsLists[listNo].Flink;
3496              pLe != &Fcb->Specific.File.ExtentsLists[listNo];
3497              pLe = pLe->Flink)
3498         {
3499             AFSExtent *pExtent;
3500
3501             pExtent = ExtentFor(pLe, listNo);
3502
3503             if (listNo == 0) {
3504                 ASSERT(pLe        != &Fcb->Specific.File.ExtentsLists[1] &&
3505                        pLe->Flink !=&Fcb->Specific.File.ExtentsLists[1] &&
3506                        pLe->Blink !=&Fcb->Specific.File.ExtentsLists[1]);
3507             }
3508
3509             ASSERT(pLe->Flink->Blink == pLe);
3510             ASSERT(pLe->Blink->Flink == pLe);
3511
3512             //
3513             // Should follow on from previous
3514             //
3515             ASSERT(pExtent->FileOffset.QuadPart >= lastOffset.QuadPart);
3516             lastOffset.QuadPart = pExtent->FileOffset.QuadPart + pExtent->Size;
3517
3518             //
3519             // Should match alignment criteria
3520             //
3521             ASSERT( 0 == (pExtent->FileOffset.LowPart & ExtentsMasks[listNo]) );
3522
3523             //
3524             // "lower" lists should be populated
3525             //
3526             for (LONG subListNo = listNo-1; subListNo > 0; subListNo --)
3527             {
3528                 ASSERT( !IsListEmpty(&pExtent->Lists[subListNo]));
3529             }
3530         }
3531     }
3532 #endif
3533 }
3534
3535 void
3536 AFSTrimExtents( IN AFSFcb *Fcb,
3537                 IN PLARGE_INTEGER FileSize)
3538 {
3539
3540     AFSNonPagedFcb      *pNPFcb = Fcb->NPFcb;
3541     LIST_ENTRY          *le;
3542     AFSExtent           *pExtent;
3543     BOOLEAN              locked = FALSE;
3544     NTSTATUS             ntStatus = STATUS_SUCCESS;
3545     LARGE_INTEGER        liAlignedOffset = {0,0};
3546     AFSDeviceExt        *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
3547     AFSDeviceExt        *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
3548
3549     __Enter
3550     {
3551
3552         //
3553         // Get an aligned offset
3554         //
3555
3556         if( FileSize != NULL)
3557         {
3558
3559             liAlignedOffset = *FileSize;
3560         }
3561
3562         if( liAlignedOffset.QuadPart > 0 &&
3563             liAlignedOffset.QuadPart % pDevExt->Specific.RDR.CacheBlockSize != 0)
3564         {
3565
3566             //
3567             // Align UP to the next cache block size
3568             //
3569
3570             liAlignedOffset.QuadPart = (ULONGLONG)( (ULONGLONG)((liAlignedOffset.QuadPart / pDevExt->Specific.RDR.CacheBlockSize) + 1) * (ULONGLONG)pDevExt->Specific.RDR.CacheBlockSize);
3571         }
3572
3573         //
3574         // Ensure that no one is working with the extents and grab the
3575         // lock
3576         //
3577
3578         AFSLockForExtentsTrim( Fcb);
3579
3580         locked = TRUE;
3581
3582         if( 0 == Fcb->Specific.File.ExtentCount)
3583         {
3584
3585             //
3586             // Update the request extent status
3587             //
3588
3589             Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
3590
3591             try_return( ntStatus = STATUS_SUCCESS);
3592         }
3593
3594         //
3595         // We are truncating from a specific length in the file. If the offset
3596         // is non-zero then go find the first extent to remove
3597         //
3598
3599         if( 0 == FileSize->QuadPart)
3600         {
3601
3602             le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
3603         }
3604         else
3605         {
3606
3607             pExtent = AFSExtentForOffset( Fcb,
3608                                           FileSize,
3609                                           TRUE);
3610
3611             if( NULL == pExtent)
3612             {
3613
3614                 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
3615             }
3616             else
3617             {
3618                 le = &pExtent->Lists[AFS_EXTENTS_LIST];
3619             }
3620         }
3621
3622         while( le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
3623         {
3624
3625             pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
3626
3627             //
3628             // Only trim down extents beyond the aligned offset
3629             //
3630
3631             le = le->Flink;
3632
3633             if( pExtent->FileOffset.QuadPart >= liAlignedOffset.QuadPart)
3634             {
3635
3636                 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3637                 {
3638
3639                     AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
3640                                     TRUE);
3641
3642                     if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3643                     {
3644                         LONG dirtyCount;
3645
3646                         AFSRemoveEntryDirtyList( Fcb,
3647                                                  pExtent);
3648
3649                         dirtyCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
3650
3651                         ASSERT(dirtyCount >= 0);
3652                     }
3653
3654                     AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
3655                 }
3656
3657                 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
3658                 {
3659                     if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
3660                     {
3661                         RemoveEntryList( &pExtent->Lists[i] );
3662                     }
3663                 }
3664
3665                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3666                               AFS_TRACE_LEVEL_VERBOSE,
3667                               "AFSTrimExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
3668                               pExtent,
3669                               Fcb->ObjectInformation->FileId.Cell,
3670                               Fcb->ObjectInformation->FileId.Volume,
3671                               Fcb->ObjectInformation->FileId.Vnode,
3672                               Fcb->ObjectInformation->FileId.Unique,
3673                               pExtent->FileOffset.QuadPart,
3674                               pExtent->Size);
3675
3676                 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
3677
3678                 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
3679
3680                 ASSERT( pExtent->ActiveCount == 0);
3681
3682                 //
3683                 // and free
3684                 //
3685                 AFSExFreePool( pExtent);
3686
3687                 InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
3688
3689                 if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0)
3690                 {
3691
3692                     KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
3693                                 0,
3694                                 FALSE);
3695                 }
3696             }
3697         }
3698
3699         //
3700         // Update the request extent status
3701         //
3702
3703         Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
3704
3705 try_exit:
3706
3707         if (locked)
3708         {
3709
3710             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3711                           AFS_TRACE_LEVEL_VERBOSE,
3712                           "AFSTrimExtents Releasing Fcb extents lock %08lX thread %08lX\n",
3713                           &Fcb->NPFcb->Specific.File.ExtentsResource,
3714                           PsGetCurrentThread());
3715
3716             AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource );
3717         }
3718     }
3719
3720     return;
3721 }
3722
3723 void
3724 AFSTrimSpecifiedExtents( IN AFSFcb *Fcb,
3725                          IN ULONG   Count,
3726                          IN AFSFileExtentCB *Result)
3727 {
3728
3729     AFSNonPagedFcb      *pNPFcb = Fcb->NPFcb;
3730     LIST_ENTRY          *le;
3731     AFSExtent           *pExtent;
3732     AFSFileExtentCB     *pFileExtents = Result;
3733     NTSTATUS             ntStatus = STATUS_SUCCESS;
3734     AFSDeviceExt        *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
3735     AFSDeviceExt        *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
3736
3737     __Enter
3738     {
3739
3740         le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
3741
3742         while( le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST] &&
3743                Count > 0)
3744         {
3745
3746             pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
3747
3748             //
3749             // Only trim down extents beyond the aligned offset
3750             //
3751
3752             le = le->Flink;
3753
3754             if( pExtent->FileOffset.QuadPart == pFileExtents->FileOffset.QuadPart)
3755             {
3756
3757                 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3758                 {
3759
3760                     AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
3761                                     TRUE);
3762
3763                     if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3764                     {
3765
3766                         LONG dirtyCount;
3767
3768                         AFSRemoveEntryDirtyList( Fcb,
3769                                                  pExtent);
3770
3771                         dirtyCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
3772
3773                         ASSERT( dirtyCount >= 0);
3774
3775                     }
3776
3777                     AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
3778
3779                 }
3780
3781                 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
3782                 {
3783                     if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
3784                     {
3785                         RemoveEntryList( &pExtent->Lists[i] );
3786                     }
3787                 }
3788
3789                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3790                               AFS_TRACE_LEVEL_VERBOSE,
3791                               "AFSTrimSpecifiedExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
3792                               pExtent,
3793                               Fcb->ObjectInformation->FileId.Cell,
3794                               Fcb->ObjectInformation->FileId.Volume,
3795                               Fcb->ObjectInformation->FileId.Vnode,
3796                               Fcb->ObjectInformation->FileId.Unique,
3797                               pExtent->FileOffset.QuadPart,
3798                               pExtent->Size);
3799
3800                 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
3801
3802                 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
3803
3804                 ASSERT( pExtent->ActiveCount == 0);
3805
3806                 //
3807                 // and free
3808                 //
3809                 AFSExFreePool( pExtent);
3810
3811                 InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
3812
3813                 if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0)
3814                 {
3815
3816                     KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
3817                                 0,
3818                                 FALSE);
3819                 }
3820
3821                 //
3822                 // Next extent we are looking for
3823                 //
3824
3825                 pFileExtents++;
3826
3827                 Count--;
3828             }
3829         }
3830
3831         //
3832         // Update the request extent status
3833         //
3834
3835         Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
3836     }
3837
3838     return;
3839 }
3840
3841 void
3842 AFSReferenceActiveExtents( IN AFSExtent *StartExtent,
3843                            IN ULONG ExtentsCount)
3844 {
3845
3846     AFSExtent     *pExtent = StartExtent;
3847     AFSExtent     *pNextExtent;
3848     ULONG          ulCount = 0;
3849
3850     while( ulCount < ExtentsCount)
3851     {
3852
3853         pNextExtent = NextExtent( pExtent, AFS_EXTENTS_LIST);
3854
3855         InterlockedIncrement( &pExtent->ActiveCount);
3856
3857         AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_ACTIVE_COUNTING,
3858                       AFS_TRACE_LEVEL_VERBOSE,
3859                       "AFSReferenceActiveExtents Increment count on extent %08lX Cnt %d\n",
3860                       pExtent,
3861                       pExtent->ActiveCount);
3862
3863         pExtent = pNextExtent;
3864
3865         ulCount++;
3866     }
3867
3868     return;
3869 }
3870
3871 void
3872 AFSDereferenceActiveExtents( IN AFSExtent *StartExtent,
3873                              IN ULONG ExtentsCount)
3874 {
3875
3876     AFSExtent     *pExtent = StartExtent;
3877     AFSExtent     *pNextExtent;
3878     ULONG          ulCount = 0;
3879
3880     while( ulCount < ExtentsCount)
3881     {
3882
3883         pNextExtent = NextExtent( pExtent, AFS_EXTENTS_LIST);
3884
3885         AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_ACTIVE_COUNTING,
3886                       AFS_TRACE_LEVEL_VERBOSE,
3887                       "AFSDereferenceActiveExtents Decrement count on extent %08lX Cnt %d\n",
3888                       pExtent,
3889                       pExtent->ActiveCount);
3890
3891         ASSERT( pExtent->ActiveCount > 0);
3892
3893         InterlockedDecrement( &pExtent->ActiveCount);
3894
3895         pExtent = pNextExtent;
3896
3897         ulCount++;
3898     }
3899
3900     return;
3901 }
3902
3903 void
3904 AFSRemoveEntryDirtyList( IN AFSFcb *Fcb,
3905                          IN AFSExtent *Extent)
3906 {
3907
3908     if( Extent->DirtyList.fLink == NULL)
3909     {
3910
3911         Fcb->NPFcb->Specific.File.DirtyListTail = (AFSExtent *)Extent->DirtyList.bLink;
3912
3913         if( Fcb->NPFcb->Specific.File.DirtyListTail != NULL)
3914         {
3915
3916             Fcb->NPFcb->Specific.File.DirtyListTail->DirtyList.fLink = NULL;
3917         }
3918     }
3919     else
3920     {
3921
3922         ((AFSExtent *)Extent->DirtyList.fLink)->DirtyList.bLink = Extent->DirtyList.bLink;
3923     }
3924
3925     if( Extent->DirtyList.bLink == NULL)
3926     {
3927
3928         Fcb->NPFcb->Specific.File.DirtyListHead = (AFSExtent *)Extent->DirtyList.fLink;
3929
3930         if( Fcb->NPFcb->Specific.File.DirtyListHead != NULL)
3931         {
3932
3933             Fcb->NPFcb->Specific.File.DirtyListHead->DirtyList.bLink = NULL;
3934         }
3935     }
3936     else
3937     {
3938
3939         ((AFSExtent *)Extent->DirtyList.bLink)->DirtyList.fLink = Extent->DirtyList.fLink;
3940     }
3941
3942
3943     return;
3944 }
3945
3946 #if GEN_MD5
3947 void
3948 AFSSetupMD5Hash( IN AFSFcb *Fcb,
3949                  IN AFSExtent *StartExtent,
3950                  IN ULONG ExtentsCount,
3951                  IN void *SystemBuffer,
3952                  IN LARGE_INTEGER *ByteOffset,
3953                  IN ULONG ByteCount)
3954 {
3955
3956     NTSTATUS ntStatus = STATUS_SUCCESS;
3957     AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
3958     AFSExtent     *pExtent = StartExtent;
3959     AFSExtent     *pNextExtent, *pCurrentExtent = NULL;
3960     ULONG ulCount = 0;
3961     char *pCurrentBuffer = (char *)SystemBuffer;
3962     char *pMD5Buffer = NULL;
3963     ULONG ulCurrentLen = 0;
3964     void *pExtentBuffer = NULL;
3965     LARGE_INTEGER liByteOffset;
3966     ULONG ulBytesRead = 0;
3967
3968     __Enter
3969     {
3970
3971         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3972                       AFS_TRACE_LEVEL_VERBOSE,
3973                       "AFSSetupMD5Hash Acquiring Fcb extents lock %08lX SHARED %08lX\n",
3974                       &Fcb->NPFcb->Specific.File.ExtentsResource,
3975                       PsGetCurrentThread());
3976
3977         AFSAcquireShared( &Fcb->NPFcb->Specific.File.ExtentsResource, TRUE);
3978
3979         liByteOffset.QuadPart = ByteOffset->QuadPart;
3980
3981         while( ulCount < ExtentsCount)
3982         {
3983
3984             RtlZeroMemory( pExtent->MD5,
3985                            sizeof( pExtent->MD5));
3986
3987             pNextExtent = NextExtent( pExtent, AFS_EXTENTS_LIST);
3988
3989             if( liByteOffset.QuadPart == pExtent->FileOffset.QuadPart &&
3990                 ByteCount < pExtent->Size)
3991             {
3992
3993                 if( pExtentBuffer == NULL)
3994                 {
3995
3996                     pExtentBuffer = AFSExAllocatePoolWithTag( PagedPool,
3997                                                               pExtent->Size,
3998                                                               AFS_GENERIC_MEMORY_9_TAG);
3999
4000                     if( pExtentBuffer == NULL)
4001                     {
4002
4003                         break;
4004                     }
4005                 }
4006
4007                 RtlZeroMemory( pExtentBuffer,
4008                                pExtent->Size);
4009
4010                 RtlCopyMemory( pExtentBuffer,
4011                                pCurrentBuffer,
4012                                ByteCount);
4013
4014                 pMD5Buffer = (char *)pExtentBuffer;
4015
4016                 ulCurrentLen = ByteCount;
4017             }
4018             else if( liByteOffset.QuadPart != pExtent->FileOffset.QuadPart)
4019             {
4020
4021                 pExtentBuffer = AFSExAllocatePoolWithTag( PagedPool,
4022                                                           pExtent->Size,
4023                                                           AFS_GENERIC_MEMORY_10_TAG);
4024
4025                 if( pExtentBuffer == NULL)
4026                 {
4027
4028                     break;
4029                 }
4030
4031                 RtlZeroMemory( pExtentBuffer,
4032                                pExtent->Size);
4033
4034                 if( BooleanFlagOn( AFSLibControlFlags, AFS_REDIR_LIB_FLAGS_NONPERSISTENT_CACHE))
4035                 {
4036
4037 #ifdef AMD64
4038                     RtlCopyMemory( pExtentBuffer,
4039                                    ((char *)AFSLibCacheBaseAddress + pExtent->CacheOffset.QuadPart),
4040                                    pExtent->Size);
4041 #else
4042                     ASSERT( pExtent->CacheOffset.HighPart == 0);
4043                     RtlCopyMemory( pExtentBuffer,
4044                                    ((char *)AFSLibCacheBaseAddress + pExtent->CacheOffset.LowPart),
4045                                    pExtent->Size);
4046 #endif
4047
4048                     ulBytesRead = pExtent->Size;
4049                 }
4050                 else
4051                 {
4052
4053                     ntStatus = AFSReadCacheFile( pExtentBuffer,
4054                                                  &pExtent->CacheOffset,
4055                                                  pExtent->Size,
4056                                                  &ulBytesRead);
4057
4058                     if( !NT_SUCCESS( ntStatus))
4059                     {
4060                         break;
4061                     }
4062                 }
4063
4064                 pMD5Buffer = (char *)pExtentBuffer;
4065
4066                 ulCurrentLen = min( ByteCount, pExtent->Size - (ULONG)(liByteOffset.QuadPart - pExtent->FileOffset.QuadPart));
4067
4068                 RtlCopyMemory( (void *)((char *)pExtentBuffer + (ULONG)(liByteOffset.QuadPart - pExtent->FileOffset.QuadPart)),
4069                                pCurrentBuffer,
4070                                ulCurrentLen);
4071             }
4072             else
4073             {
4074
4075                 ulCurrentLen = pExtent->Size;
4076
4077                 pMD5Buffer = pCurrentBuffer;
4078             }
4079
4080             AFSGenerateMD5( pMD5Buffer,
4081                             pExtent->Size,
4082                             pExtent->MD5);
4083
4084             pExtent = pNextExtent;
4085
4086             ulCount++;
4087
4088             ByteCount -= ulCurrentLen;
4089
4090             pCurrentBuffer += ulCurrentLen;
4091
4092             liByteOffset.QuadPart += ulCurrentLen;
4093         }
4094
4095         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
4096                       AFS_TRACE_LEVEL_VERBOSE,
4097                       "AFSSetupMD5Hash Releasing Fcb extents lock %08lX SHARED %08lX\n",
4098                       &Fcb->NPFcb->Specific.File.ExtentsResource,
4099                       PsGetCurrentThread());
4100
4101         AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource );
4102
4103         if( pExtentBuffer != NULL)
4104         {
4105
4106             AFSExFreePool( pExtentBuffer);
4107         }
4108     }
4109
4110     return;
4111 }
4112 #endif
4113