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