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