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