Windows: consoldiate NextExtent() implementations
[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 ULONG ExtentsMasks[AFS_NUM_EXTENT_LISTS] = AFS_EXTENTS_MASKS;
43 static VOID VerifyExtentsLists(AFSFcb *Fcb);
44 static AFSExtent *DirtyExtentFor(PLIST_ENTRY le);
45
46 LIST_ENTRY *
47 AFSEntryForOffset( IN AFSFcb *Fcb,
48                    IN PLARGE_INTEGER Offset);
49
50
51 //
52 // Returns with Extents lock EX and no one using them.
53 //
54
55 VOID
56 AFSLockForExtentsTrim( IN AFSFcb *Fcb)
57 {
58     NTSTATUS          ntStatus;
59     AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
60
61     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
62                   AFS_TRACE_LEVEL_VERBOSE,
63                   "AFSLockForExtentsTrim Acquiring Fcb extents lock %08lX EXCL %08lX\n",
64                   &pNPFcb->Specific.File.ExtentsResource,
65                   PsGetCurrentThread());
66
67     AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, TRUE );
68
69     return;
70 }
71
72 //
73 // return FALSE *or* with Extents lock EX and noone using them
74 //
75 BOOLEAN
76 AFSLockForExtentsTrimNoWait( IN AFSFcb *Fcb)
77 {
78     AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
79
80     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
81                   AFS_TRACE_LEVEL_VERBOSE,
82                   "AFSLockForExtentsTrimNoWait Attempting to acquire Fcb extent lock %08lX EXCL %08lX\n",
83                   &pNPFcb->Specific.File.ExtentsResource,
84                   PsGetCurrentThread());
85
86     if (!AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, FALSE ))
87     {
88         //
89         // Couldn't lock immediately
90         //
91
92         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
93                       AFS_TRACE_LEVEL_VERBOSE,
94                       "AFSLockForExtentsTrimNoWait Refused to wait for Fcb extent lock %08lX EXCL %08lX\n",
95                       &pNPFcb->Specific.File.ExtentsResource,
96                       PsGetCurrentThread());
97
98         return FALSE;
99     }
100
101     return TRUE;
102 }
103 //
104 // AFSTearDownFcbExtents was originally written to
105 // remove all of the extents from an FCB.  For that to happen
106 // it must be an invariant that the extent list cannot change
107 // from the moment the caller decides to execute AFSTearDownFcbExtents
108 // until it returns.  This invariant does not hold because the
109 // the decision to call AFSTearDownFcbExtents is made without
110 // holding the ExtentsResource and it is possible that extents
111 // are in active use. Therefore, AFSTearDownFcbExtents now releases
112 // as many non-active extents as it can.
113 //
114 VOID
115 AFSTearDownFcbExtents( IN AFSFcb *Fcb,
116                        IN GUID *AuthGroup)
117 {
118     AFSNonPagedFcb      *pNPFcb = Fcb->NPFcb;
119     LIST_ENTRY          *le, *leNext;
120     AFSExtent           *pEntry;
121     LONG                 lExtentCount = 0;
122     ULONG                ulReleaseCount = 0, ulProcessCount = 0;
123     size_t               sz;
124     AFSReleaseExtentsCB *pRelease = NULL;
125     BOOLEAN              locked = FALSE;
126     NTSTATUS             ntStatus;
127     AFSDeviceExt        *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
128     GUID                *pAuthGroup = AuthGroup;
129     GUID                 stAuthGroup;
130     LONG                 lCount;
131
132     __Enter
133     {
134
135         if( pAuthGroup == NULL ||
136             RtlCompareMemory( pAuthGroup,
137                               &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
138                               sizeof( GUID)) == sizeof( GUID))
139         {
140
141             RtlZeroMemory( &stAuthGroup,
142                            sizeof( GUID));
143
144             ntStatus = AFSRetrieveValidAuthGroup( Fcb,
145                                                   NULL,
146                                                   TRUE,
147                                                   &stAuthGroup);
148
149             if( !NT_SUCCESS( ntStatus))
150             {
151                 try_return( ntStatus);
152             }
153
154             pAuthGroup = &stAuthGroup;
155         }
156
157         //
158         // Ensure that no one is working with the extents and grab the
159         // lock
160         //
161
162         AFSLockForExtentsTrim( Fcb );
163
164         locked = TRUE;
165
166         if (0 == Fcb->Specific.File.ExtentCount)
167         {
168             try_return ( ntStatus = STATUS_SUCCESS);
169         }
170
171         sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
172
173         pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
174                                                                     sz,
175                                                                     AFS_EXTENT_RELEASE_TAG);
176         if (NULL == pRelease)
177         {
178
179             try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
180         }
181
182         AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
183                         TRUE);
184
185         for( le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink,
186              lExtentCount = 0;
187              lExtentCount < Fcb->Specific.File.ExtentCount;
188              lExtentCount += ulProcessCount)
189         {
190
191             RtlZeroMemory( pRelease,
192                            sizeof( AFSReleaseExtentsCB ) +
193                            (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB )));
194
195             for( ulProcessCount = 0, ulReleaseCount = 0;
196                  !IsListEmpty( le) && ulReleaseCount < AFS_MAXIMUM_EXTENT_RELEASE_COUNT;
197                  ulProcessCount++, le = leNext)
198             {
199
200                 leNext = le->Flink;
201
202                 pEntry = ExtentFor( le, AFS_EXTENTS_LIST );
203
204                 if( pEntry->ActiveCount == 0)
205                 {
206
207                     ulReleaseCount++;
208
209                     pRelease->FileExtents[ulProcessCount].Flags = AFS_EXTENT_FLAG_RELEASE;
210
211 #if GEN_MD5
212                     RtlCopyMemory( pRelease->FileExtents[ulProcessCount].MD5,
213                                    pEntry->MD5,
214                                    sizeof(pEntry->MD5));
215
216                     pRelease->FileExtents[ulProcessCount].Flags |= AFS_EXTENT_FLAG_MD5_SET;
217 #endif
218
219                     if( BooleanFlagOn( pEntry->Flags, AFS_EXTENT_DIRTY))
220                     {
221
222                         LONG dirtyCount;
223
224                         AFSRemoveEntryDirtyList( Fcb,
225                                                  pEntry);
226
227                         pRelease->FileExtents[ulProcessCount].Flags |= AFS_EXTENT_FLAG_DIRTY;
228
229                         dirtyCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
230
231                         ASSERT( dirtyCount >= 0);
232                     }
233
234                     AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
235                                   AFS_TRACE_LEVEL_VERBOSE,
236                                   "AFSTearDownFcbExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %08lX-%08lX Len %08lX\n",
237                                   pEntry,
238                                   Fcb->ObjectInformation->FileId.Cell,
239                                   Fcb->ObjectInformation->FileId.Volume,
240                                   Fcb->ObjectInformation->FileId.Vnode,
241                                   Fcb->ObjectInformation->FileId.Unique,
242                                   pEntry->FileOffset.HighPart,
243                                   pEntry->FileOffset.LowPart,
244                                   pEntry->Size);
245
246                     pRelease->FileExtents[ulProcessCount].Length = pEntry->Size;
247                     pRelease->FileExtents[ulProcessCount].DirtyLength = pEntry->Size;
248                     pRelease->FileExtents[ulProcessCount].DirtyOffset = 0;
249                     pRelease->FileExtents[ulProcessCount].CacheOffset = pEntry->CacheOffset;
250                     pRelease->FileExtents[ulProcessCount].FileOffset = pEntry->FileOffset;
251
252                     InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pEntry->Size/1024)));
253
254                     InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pEntry->Size/1024)));
255
256                     RemoveEntryList( le);
257
258                     AFSExFreePool( pEntry);
259
260                     lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
261
262                     lCount = InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount);
263
264                     if( lCount == 0)
265                     {
266
267                         KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
268                                     0,
269                                     FALSE);
270                     }
271                 }
272             }
273
274             if ( ulReleaseCount > 0)
275             {
276
277                 pRelease->ExtentCount = ulReleaseCount;
278
279                 pRelease->Flags = AFS_EXTENT_FLAG_RELEASE;
280
281                 //
282                 // Update the metadata for this call
283                 //
284
285                 pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
286                 pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
287                 pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
288                 pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
289                 pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
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         }
330
331         AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
332
333         //
334         // if all extents have been released, reinitialize the skip lists
335         //
336
337         if( Fcb->Specific.File.ExtentCount == 0)
338         {
339
340             for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i++)
341             {
342                 InitializeListHead(&Fcb->Specific.File.ExtentsLists[i]);
343             }
344
345             //
346             // Reinitialize the dirty list as well
347             //
348
349             AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
350                             TRUE);
351
352             ASSERT( Fcb->Specific.File.ExtentsDirtyCount == 0);
353
354             Fcb->NPFcb->Specific.File.DirtyListHead = NULL;
355             Fcb->NPFcb->Specific.File.DirtyListTail = NULL;
356
357             AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
358         }
359
360         Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
361
362 try_exit:
363
364         if (locked)
365         {
366
367             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
368                           AFS_TRACE_LEVEL_VERBOSE,
369                           "AFSTearDownFcbExtents Releasing Fcb extent lock %08lX thread %08lX\n",
370                           &Fcb->NPFcb->Specific.File.ExtentsResource,
371                           PsGetCurrentThread());
372
373             AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource );
374         }
375
376         if (pRelease)
377         {
378
379             AFSExFreePool( pRelease);
380         }
381     }
382 }
383
384 static PAFSExtent
385 ExtentForOffsetInList( IN AFSFcb *Fcb,
386                        IN LIST_ENTRY *List,
387                        IN ULONG ListNumber,
388                        IN PLARGE_INTEGER Offset)
389 {
390     //
391     // Return the extent that maps the offset, that
392     //   - Contains the offset
393     //   - or is immediately ahead of the offset (in this list)
394     //   - otherwise return NULL.
395     //
396
397     PLIST_ENTRY  pLe = List;
398     AFSExtent   *pPrevious = NULL;
399
400     ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
401
402     while (pLe != &Fcb->Specific.File.ExtentsLists[ListNumber])
403     {
404         AFSExtent *entry;
405
406         entry = ExtentFor( pLe, ListNumber );
407
408         if( entry == NULL)
409         {
410             return entry;
411         }
412
413         if (Offset->QuadPart < entry->FileOffset.QuadPart)
414         {
415             //
416             // Offset is ahead of entry.  Return previous
417             //
418             return pPrevious;
419         }
420
421         if (Offset->QuadPart >= (entry->FileOffset.QuadPart + entry->Size))
422         {
423             //
424             // We start after this extent - carry on round
425             //
426             pPrevious = entry;
427             pLe = pLe->Flink;
428             continue;
429         }
430
431         //
432         // Otherwise its a match
433         //
434
435         return entry;
436     }
437
438     //
439     // Got to the end.  Return Previous
440     //
441     return pPrevious;
442 }
443
444 BOOLEAN
445 AFSExtentContains( IN AFSExtent *Extent, IN PLARGE_INTEGER Offset)
446 {
447     if (NULL == Extent)
448     {
449         return FALSE;
450     }
451     return (Extent->FileOffset.QuadPart <= Offset->QuadPart &&
452             (Extent->FileOffset.QuadPart + Extent->Size) > Offset->QuadPart);
453 }
454
455
456 //
457 // Return the extent that contains the offset
458 //
459 PAFSExtent
460 AFSExtentForOffsetHint( IN AFSFcb *Fcb,
461                         IN PLARGE_INTEGER Offset,
462                         IN BOOLEAN ReturnPrevious,
463                         IN AFSExtent *Hint)
464 {
465     AFSExtent *pPrevious = Hint;
466     LIST_ENTRY *pLe;
467     LONG i;
468
469     ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
470
471 #if AFS_VALIDATE_EXTENTS
472     VerifyExtentsLists(Fcb);
473 #endif
474
475     //
476     // So we will go across the skip lists until we find an
477     // appropriate entry (previous or direct match).  If it's a match
478     // we are done, other wise we start on the next layer down
479     //
480     for (i = AFS_NUM_EXTENT_LISTS-1; i >= AFS_EXTENTS_LIST; i--)
481     {
482         if (NULL == pPrevious)
483         {
484             //
485             // We haven't found anything in the previous layers
486             //
487             pLe = Fcb->Specific.File.ExtentsLists[i].Flink;
488         }
489         else if (NULL == pPrevious->Lists[i].Flink)
490         {
491             ASSERT(AFS_EXTENTS_LIST != i);
492             //
493             // The hint doesn't exist at this level, next one down
494             //
495             continue;
496         }
497         else
498         {
499             //
500             // take the previous into the next
501             //
502             pLe = &pPrevious->Lists[i];
503         }
504
505         pPrevious = ExtentForOffsetInList( Fcb, pLe, i, Offset);
506
507         if (NULL != pPrevious && AFSExtentContains(pPrevious, Offset))
508         {
509             //
510             // Found it immediately.  Stop here
511             //
512             return pPrevious;
513         }
514     }
515
516     if (NULL == pPrevious || ReturnPrevious )
517     {
518         return pPrevious;
519     }
520
521     ASSERT( !AFSExtentContains(pPrevious, Offset) );
522
523     return NULL;
524 }
525
526 LIST_ENTRY *
527 AFSEntryForOffset( IN AFSFcb *Fcb,
528                    IN PLARGE_INTEGER Offset)
529 {
530     AFSExtent *pPrevious = NULL;
531     LIST_ENTRY *pLe;
532     LONG i;
533
534     ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
535
536 #if AFS_VALIDATE_EXTENTS
537     VerifyExtentsLists(Fcb);
538 #endif
539
540     //
541     // So we will go across the skip lists until we find an
542     // appropriate entry (previous or direct match).  If it's a match
543     // we are done, other wise we start on the next layer down
544     //
545     for (i = AFS_NUM_EXTENT_LISTS-1; i >= AFS_EXTENTS_LIST; i--)
546     {
547         if (NULL == pPrevious)
548         {
549             //
550             // We haven't found anything in the previous layers
551             //
552             pLe = Fcb->Specific.File.ExtentsLists[i].Flink;
553         }
554         else if (NULL == pPrevious->Lists[i].Flink)
555         {
556             ASSERT(AFS_EXTENTS_LIST != i);
557             //
558             // The hint doesn't exist at this level, next one down
559             //
560             continue;
561         }
562         else
563         {
564             //
565             // take the previous into the next
566             //
567             pLe = &pPrevious->Lists[i];
568         }
569
570         pPrevious = ExtentForOffsetInList( Fcb, pLe, i, Offset);
571
572         if (NULL != pPrevious && AFSExtentContains(pPrevious, Offset))
573         {
574             //
575             // Found it immediately.  Stop here
576             //
577             return pLe;
578         }
579     }
580
581     return NULL;
582 }
583
584 PAFSExtent
585 AFSExtentForOffset( IN AFSFcb *Fcb,
586                     IN PLARGE_INTEGER Offset,
587                     IN BOOLEAN ReturnPrevious)
588 {
589     return AFSExtentForOffsetHint(Fcb, Offset, ReturnPrevious, NULL);
590 }
591
592
593 BOOLEAN AFSDoExtentsMapRegion(IN AFSFcb *Fcb,
594                               IN PLARGE_INTEGER Offset,
595                               IN ULONG Size,
596                               IN OUT AFSExtent **FirstExtent,
597                               OUT AFSExtent **LastExtent)
598 {
599     //
600     // Return TRUE region is completely mapped.  FALSE
601     // otherwise.  If the region isn't mapped then the last
602     // extent to map part of the region is returned.
603     //
604     // *LastExtent as input is where to start looking.
605     // *LastExtent as output is either the extent which
606     //  contains the Offset, or the last one which doesn't
607     //
608     AFSExtent *entry;
609     AFSExtent *newEntry;
610     BOOLEAN retVal = FALSE;
611
612     __Enter
613     {
614
615         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
616                       AFS_TRACE_LEVEL_VERBOSE,
617                       "AFSDoExtentsMapRegion Acquiring Fcb extent lock %08lX SHARED %08lX\n",
618                       &Fcb->NPFcb->Specific.File.ExtentsResource,
619                       PsGetCurrentThread());
620
621         AFSAcquireShared( &Fcb->NPFcb->Specific.File.ExtentsResource, TRUE );
622
623         __try
624         {
625             entry = AFSExtentForOffsetHint(Fcb, Offset, TRUE, *FirstExtent);
626             *FirstExtent = entry;
627
628             if (NULL == entry || !AFSExtentContains(entry, Offset))
629             {
630                 try_return (retVal = FALSE);
631             }
632
633             ASSERT(Offset->QuadPart >= entry->FileOffset.QuadPart);
634
635             while (TRUE)
636             {
637                 if ((entry->FileOffset.QuadPart + entry->Size) >=
638                      (Offset->QuadPart + Size))
639                 {
640                     //
641                     // The end is inside the extent
642                     //
643                     try_return (retVal = TRUE);
644                 }
645
646                 if (entry->Lists[AFS_EXTENTS_LIST].Flink == &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
647                 {
648                     //
649                     // Run out of extents
650                     //
651                     try_return (retVal = FALSE);
652                 }
653
654                 newEntry = NextExtent( entry, AFS_EXTENTS_LIST );
655
656                 if (newEntry->FileOffset.QuadPart !=
657                      (entry->FileOffset.QuadPart + entry->Size))
658                 {
659                     //
660                     // Gap
661                     //
662                     try_return (retVal = FALSE);
663                 }
664
665                 entry = newEntry;
666             }
667         }
668         __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
669         {
670
671             AFSDbgLogMsg( 0,
672                           0,
673                           "EXCEPTION - AFSDoExtentsMapRegion\n");
674
675             AFSDumpTraceFilesFnc();
676         }
677
678 try_exit:
679
680         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
681                       AFS_TRACE_LEVEL_VERBOSE,
682                       "AFSDoExtentsMapRegion Releasing Fcb extent lock %08lX SHARED %08lX\n",
683                       &Fcb->NPFcb->Specific.File.ExtentsResource,
684                       PsGetCurrentThread());
685
686         AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource );
687
688         *LastExtent = entry;
689     }
690
691     return retVal;
692 }
693
694 NTSTATUS
695 AFSRequestExtentsAsync( IN AFSFcb *Fcb,
696                         IN AFSCcb *Ccb,
697                         IN PLARGE_INTEGER Offset,
698                         IN ULONG Size)
699 {
700
701     AFSDeviceExt        *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
702     NTSTATUS             ntStatus = STATUS_SUCCESS;
703     AFSExtent           *pExtent = NULL;
704     AFSRequestExtentsCB  request;
705     AFSNonPagedFcb      *pNPFcb = Fcb->NPFcb;
706     AFSExtent           *pFirstExtent = NULL;
707     LARGE_INTEGER        liAlignedOffset;
708     ULONG                ulAlignedLength = 0;
709     BOOLEAN              bRegionMapped = FALSE;
710     ULONGLONG            ullProcessId = (ULONGLONG)PsGetCurrentProcessId();
711
712     __Enter
713     {
714
715         ASSERT( !ExIsResourceAcquiredLite( &pNPFcb->Specific.File.ExtentsResource ));
716
717         //
718         // If the service set a failure on the file since the last
719         // CreateFile was issued, return it now.
720         //
721
722         if (!NT_SUCCESS( pNPFcb->Specific.File.ExtentsRequestStatus))
723         {
724
725             //
726             // If this isn't the same authgroup which caused the failure
727             // then try to request them again
728             //
729
730             if( RtlCompareMemory( &pNPFcb->Specific.File.ExtentsRequestAuthGroup,
731                                   &Ccb->AuthGroup,
732                                   sizeof( GUID)) == sizeof( GUID))
733             {
734
735                 ntStatus = pNPFcb->Specific.File.ExtentsRequestStatus;
736
737                 pNPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
738
739                 RtlZeroMemory( &pNPFcb->Specific.File.ExtentsRequestAuthGroup,
740                                sizeof( GUID));
741
742                 try_return( ntStatus);
743             }
744         }
745
746         //
747         // Check if we are already mapped
748         //
749
750         bRegionMapped = AFSDoExtentsMapRegion( Fcb, Offset, Size, &pFirstExtent, &pExtent);
751
752         if( bRegionMapped)
753         {
754
755             try_return( ntStatus = STATUS_SUCCESS);
756         }
757
758         //
759         // Align our request on extent size boundary
760         //
761
762         ulAlignedLength = Size;
763
764         liAlignedOffset = *Offset;
765
766         if( liAlignedOffset.QuadPart % pDevExt->Specific.RDR.CacheBlockSize != 0)
767         {
768
769             liAlignedOffset.QuadPart = (ULONGLONG)( (ULONGLONG)(liAlignedOffset.QuadPart / pDevExt->Specific.RDR.CacheBlockSize) * (ULONGLONG)pDevExt->Specific.RDR.CacheBlockSize);
770
771             ulAlignedLength += (ULONG)(Offset->QuadPart - liAlignedOffset.QuadPart);
772         }
773
774         if( ulAlignedLength % pDevExt->Specific.RDR.CacheBlockSize != 0)
775         {
776
777             ulAlignedLength = (ULONG)(((ulAlignedLength / pDevExt->Specific.RDR.CacheBlockSize) + 1) * pDevExt->Specific.RDR.CacheBlockSize);
778         }
779
780         RtlZeroMemory( &request,
781                        sizeof( AFSRequestExtentsCB));
782
783         request.ByteOffset = liAlignedOffset;
784         request.Length = ulAlignedLength;
785
786         if( !AFSIsExtentRequestQueued( &Fcb->ObjectInformation->FileId,
787                                        &request.ByteOffset,
788                                        request.Length))
789         {
790
791             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
792                           AFS_TRACE_LEVEL_VERBOSE,
793                           "AFSRequestExtentsAsync Request extents for fid %08lX-%08lX-%08lX-%08lX Offset %08lX Len %08lX Thread %08lX\n",
794                           Fcb->ObjectInformation->FileId.Cell,
795                           Fcb->ObjectInformation->FileId.Volume,
796                           Fcb->ObjectInformation->FileId.Vnode,
797                           Fcb->ObjectInformation->FileId.Unique,
798                           request.ByteOffset.LowPart,
799                           request.Length,
800                           PsGetCurrentThread());
801
802             ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_REQUEST_FILE_EXTENTS,
803                                           0,
804                                           &Ccb->AuthGroup,
805                                           NULL,
806                                           &Fcb->ObjectInformation->FileId,
807                                           &request,
808                                           sizeof( AFSRequestExtentsCB ),
809                                           NULL,
810                                           NULL);
811
812             if (  ntStatus == STATUS_ACCESS_DENIED)
813             {
814                 GUID                 stAuthGroup;
815                 DWORD                ntStatus2;
816
817                 ntStatus2 = AFSRetrieveValidAuthGroup( Fcb,
818                                                       NULL,
819                                                       TRUE,
820                                                       &stAuthGroup);
821
822                 if ( NT_SUCCESS( ntStatus2) &&
823                      RtlCompareMemory( &stAuthGroup,
824                                        &Ccb->AuthGroup,
825                                        sizeof( GUID)) != sizeof( GUID))
826                 {
827
828                     ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_REQUEST_FILE_EXTENTS,
829                                                   0,
830                                                   &stAuthGroup,
831                                                   NULL,
832                                                   &Fcb->ObjectInformation->FileId,
833                                                   &request,
834                                                   sizeof( AFSRequestExtentsCB ),
835                                                   NULL,
836                                                   NULL);
837                 }
838             }
839
840             if( NT_SUCCESS( ntStatus))
841             {
842
843                 KeClearEvent( &pNPFcb->Specific.File.ExtentsRequestComplete );
844             }
845         }
846         else
847         {
848
849             KeClearEvent( &pNPFcb->Specific.File.ExtentsRequestComplete );
850         }
851
852 try_exit:
853
854         NOTHING;
855     }
856
857     return ntStatus;
858 }
859
860 NTSTATUS
861 AFSProcessExtentsResult( IN AFSFcb *Fcb,
862                          IN ULONG   Count,
863                          IN AFSFileExtentCB *Result)
864 {
865     NTSTATUS          ntStatus = STATUS_SUCCESS;
866     AFSFileExtentCB  *pFileExtents = Result;
867     AFSExtent        *pExtent;
868     LIST_ENTRY       *le;
869     AFSNonPagedFcb   *pNPFcb = Fcb->NPFcb;
870     ULONG             fileExtentsUsed = 0;
871     BOOLEAN           bFoundExtent = FALSE;
872     LIST_ENTRY       *pSkipEntries[AFS_NUM_EXTENT_LISTS] = { 0 };
873     AFSDeviceExt     *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
874     LONG              lCount;
875
876     //
877     // Grab the extents exclusive for the duration
878     //
879
880     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
881                   AFS_TRACE_LEVEL_VERBOSE,
882                   "AFSProcessExtentsResult Acquiring Fcb extent lock %08lX EXCL %08lX\n",
883                   &pNPFcb->Specific.File.ExtentsResource,
884                   PsGetCurrentThread());
885
886     AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, TRUE );
887
888     __Enter
889     {
890
891         //
892         // Find where to put the extents
893         //
894         for (ULONG i = AFS_EXTENTS_LIST; i < AFS_NUM_EXTENT_LISTS; i++)
895         {
896
897             pSkipEntries[i] = Fcb->Specific.File.ExtentsLists[i].Flink;
898         }
899
900         le = pSkipEntries[AFS_EXTENTS_LIST];
901
902         if (le == &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
903         {
904             //
905             // No extents.  Insert at head of list (which is where the skip lists point!)
906             //
907             pExtent = NULL;
908         }
909         else if (0 != pFileExtents->FileOffset.QuadPart)
910         {
911             //
912             // We want to find the best extents immediately *behind* this offset
913             //
914             LARGE_INTEGER offset = pFileExtents->FileOffset;
915
916             //
917             // Ask in the top skip list first, then work down
918             //
919             for (LONG i = AFS_NUM_EXTENT_LISTS-1; i >= AFS_EXTENTS_LIST; i--)
920             {
921                 pExtent = ExtentForOffsetInList( Fcb,
922                                                  pSkipEntries[i],
923                                                  i,
924                                                  &offset);
925
926                 if (NULL == pExtent)
927                 {
928                     //
929                     // No dice.  Header has to become the head of the list
930                     //
931                     pSkipEntries[i] = &Fcb->Specific.File.ExtentsLists[i];
932                     //
933                     // And as  a loop invariant we should never have found an extent
934                     //
935                     ASSERT(!bFoundExtent);
936                 }
937                 else
938                 {
939                     //
940                     // pExtent is where to start to insert at this level
941                     //
942                     pSkipEntries[i] = &pExtent->Lists[i];
943
944                     //
945                     // And also where to start to look at the next level
946                     //
947
948                     if (i > AFS_EXTENTS_LIST)
949                     {
950                         pSkipEntries[i-1] = &pExtent->Lists[i-1];
951                     }
952                     bFoundExtent = TRUE;
953                 }
954             }
955
956             if (NULL == pExtent)
957             {
958                 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
959                 le = le->Blink;
960             }
961             else
962             {
963                 le = pExtent->Lists[AFS_EXTENTS_LIST].Blink;
964             }
965         }
966         else
967         {
968             //
969             // Looking at offset 0, so we must start at the beginning
970             //
971
972             pExtent = ExtentFor(le, AFS_EXTENTS_LIST);
973             le = le->Blink;
974
975             //
976             // And set up the skip lists
977             //
978
979             for (ULONG i = AFS_EXTENTS_LIST; i < AFS_NUM_EXTENT_LISTS; i++)
980             {
981                 pSkipEntries[i] = &Fcb->Specific.File.ExtentsLists[i];
982             }
983         }
984
985         while (fileExtentsUsed < Count)
986         {
987
988             //
989             // Loop invariant - le points to where to insert after and
990             // pExtent points to le->fLink
991             //
992
993             ASSERT (NULL == pExtent ||
994                     le->Flink == &pExtent->Lists[AFS_EXTENTS_LIST]);
995
996             if (NULL == pExtent ||
997                 pExtent->FileOffset.QuadPart > pFileExtents->FileOffset.QuadPart)
998             {
999                 //
1000                 // We need to insert a new extent at le.  Start with
1001                 // some sanity check on spanning
1002                 //
1003                 if (NULL != pExtent &&
1004                     ((pFileExtents->FileOffset.QuadPart + pFileExtents->Length) >
1005                      pExtent->FileOffset.QuadPart))
1006                 {
1007                     //
1008                     // File Extents overlaps pExtent
1009                     //
1010                     ASSERT( (pFileExtents->FileOffset.QuadPart + pFileExtents->Length) <=
1011                             pExtent->FileOffset.QuadPart);
1012
1013                     try_return (ntStatus = STATUS_INVALID_PARAMETER);
1014                 }
1015
1016                 //
1017                 // File offset is entirely in front of this extent.  Create
1018                 // a new one (remember le is the previous list entry)
1019                 //
1020                 pExtent = (AFSExtent *) AFSExAllocatePoolWithTag( NonPagedPool,
1021                                                                   sizeof( AFSExtent),
1022                                                                   AFS_EXTENT_TAG );
1023                 if (NULL  == pExtent)
1024                 {
1025
1026                     try_return (ntStatus = STATUS_INSUFFICIENT_RESOURCES );
1027                 }
1028
1029                 RtlZeroMemory( pExtent, sizeof( AFSExtent ));
1030
1031                 pExtent->FileOffset = pFileExtents->FileOffset;
1032                 pExtent->CacheOffset = pFileExtents->CacheOffset;
1033                 pExtent->Size = pFileExtents->Length;
1034
1035                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1036                               AFS_TRACE_LEVEL_VERBOSE,
1037                               "AFSProcessExtentsResult Received extent for fid %08lX-%08lX-%08lX-%08lX File Offset %I64X Cache Offset %I64X Len %08lX\n",
1038                               Fcb->ObjectInformation->FileId.Cell,
1039                               Fcb->ObjectInformation->FileId.Volume,
1040                               Fcb->ObjectInformation->FileId.Vnode,
1041                               Fcb->ObjectInformation->FileId.Unique,
1042                               pFileExtents->FileOffset.QuadPart,
1043                               pFileExtents->CacheOffset.QuadPart,
1044                               pFileExtents->Length);
1045
1046                 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, (LONG)(pExtent->Size/1024));
1047
1048                 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, (LONG)(pExtent->Size/1024));
1049
1050                 lCount = InterlockedIncrement( &Fcb->Specific.File.ExtentCount);
1051
1052                 lCount = InterlockedIncrement( &pControlDevExt->Specific.Control.ExtentCount);
1053
1054                 if( lCount == 1)
1055                 {
1056
1057                     KeClearEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent);
1058                 }
1059
1060                 //
1061                 // Insert into list
1062                 //
1063                 InsertHeadList(le, &pExtent->Lists[AFS_EXTENTS_LIST]);
1064                 ASSERT(le->Flink == &pExtent->Lists[AFS_EXTENTS_LIST]);
1065                 ASSERT(0 == (pExtent->FileOffset.LowPart & ExtentsMasks[AFS_EXTENTS_LIST]));
1066
1067                 //
1068                 // Do not move the cursor - we will do it next time
1069                 //
1070
1071                 //
1072                 // And into the (upper) skip lists - Again, do not move the cursor
1073                 //
1074                 for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--)
1075                 {
1076                     if (0 == (pExtent->FileOffset.LowPart & ExtentsMasks[i]))
1077                     {
1078                         InsertHeadList(pSkipEntries[i], &pExtent->Lists[i]);
1079 #if AFS_VALIDATE_EXTENTS
1080                         VerifyExtentsLists(Fcb);
1081 #endif
1082                     }
1083                 }
1084             }
1085             else if (pExtent->FileOffset.QuadPart == pFileExtents->FileOffset.QuadPart)
1086             {
1087
1088                 if (pExtent->Size != pFileExtents->Length)
1089                 {
1090
1091                     ASSERT (pExtent->Size == pFileExtents->Length);
1092
1093                     try_return (ntStatus = STATUS_INVALID_PARAMETER);
1094                 }
1095
1096                 //
1097                 // Move both cursors forward.
1098                 //
1099                 // First the extent pointer
1100                 //
1101                 fileExtentsUsed++;
1102                 le = &pExtent->Lists[AFS_EXTENTS_LIST];
1103
1104                 //
1105                 // Then the skip lists cursors forward if needed
1106                 //
1107                 for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--)
1108                 {
1109                     if (0 == (pExtent->FileOffset.LowPart & ExtentsMasks[i]))
1110                     {
1111                         //
1112                         // Check sanity before
1113                         //
1114 #if AFS_VALIDATE_EXTENTS
1115                         VerifyExtentsLists(Fcb);
1116 #endif
1117
1118                         //
1119                         // Skip list should point to us
1120                         //
1121                         //ASSERT(pSkipEntries[i] == &pExtent->Lists[i]);
1122                         //
1123                         // Move forward cursor
1124                         //
1125                         pSkipEntries[i] = pSkipEntries[i]->Flink;
1126                         //
1127                         // Check sanity before
1128                         //
1129 #if AFS_VALIDATE_EXTENTS
1130                         VerifyExtentsLists(Fcb);
1131 #endif
1132                     }
1133                 }
1134
1135                 //
1136                 // And then the cursor in the supplied array
1137                 //
1138
1139                 pFileExtents++;
1140
1141                 //
1142                 // setup pExtent if there is one
1143                 //
1144                 if (le->Flink != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
1145                 {
1146                     pExtent = NextExtent( pExtent, AFS_EXTENTS_LIST ) ;
1147                 }
1148                 else
1149                 {
1150                     pExtent = NULL;
1151                 }
1152             }
1153             else
1154             {
1155
1156                 ASSERT( pExtent->FileOffset.QuadPart < pFileExtents->FileOffset.QuadPart );
1157
1158                 //
1159                 // Sanity check on spanning
1160                 //
1161                 if ((pExtent->FileOffset.QuadPart + pExtent->Size) >
1162                     pFileExtents->FileOffset.QuadPart)
1163                 {
1164
1165                     ASSERT( (pExtent->FileOffset.QuadPart + pExtent->Size) <=
1166                             pFileExtents->FileOffset.QuadPart);
1167
1168                     try_return (ntStatus = STATUS_INVALID_PARAMETER);
1169                 }
1170
1171                 //
1172                 // Move le and pExtent forward
1173                 //
1174                 le = &pExtent->Lists[AFS_EXTENTS_LIST];
1175
1176                 /*
1177                 //
1178                 // Then the check the skip lists cursors
1179                 //
1180                 for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--)
1181                 {
1182                     if (0 == (pFileExtents->FileOffset.LowPart & ExtentsMasks[i]))
1183                     {
1184                         //
1185                         // Three options:
1186                         //    - empty list (pSkipEntries[i]->Flink == pSkipEntries[i]->Flink == fcb->lists[i]
1187                         //    - We are the last on the list (pSkipEntries[i]->Flink == fcb->lists[i])
1188                         //    - We are not the last on the list.  In that case we have to be strictly less than
1189                         //      that extent.
1190                         if (pSkipEntries[i]->Flink != &Fcb->Specific.File.ExtentsLists[i]) {
1191
1192                             AFSExtent *otherExtent = ExtentFor(pSkipEntries[i]->Flink, i);
1193                             ASSERT(pFileExtents->FileOffset.QuadPart < otherExtent->FileOffset.QuadPart);
1194                         }
1195                     }
1196                 }
1197                 */
1198
1199                 //
1200                 // setup pExtent if there is one
1201                 //
1202
1203                 if (le->Flink != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
1204                 {
1205                     pExtent = NextExtent( pExtent, AFS_EXTENTS_LIST ) ;
1206                 }
1207                 else
1208                 {
1209                     pExtent = NULL;
1210                 }
1211             }
1212         }
1213
1214         //
1215         // All done, signal that we are done drop the lock, exit
1216         //
1217
1218 try_exit:
1219
1220         if( !NT_SUCCESS( ntStatus))
1221         {
1222
1223             //
1224             // If we failed the service is going to drop all extents so trim away the
1225             // set given to us
1226             //
1227
1228             AFSTrimSpecifiedExtents( Fcb,
1229                                      Count,
1230                                      Result);
1231         }
1232
1233 #if AFS_VALIDATE_EXTENTS
1234         VerifyExtentsLists(Fcb);
1235 #endif
1236
1237         KeSetEvent( &pNPFcb->Specific.File.ExtentsRequestComplete,
1238                     0,
1239                     FALSE);
1240
1241         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1242                       AFS_TRACE_LEVEL_VERBOSE,
1243                       "AFSProcessExtentsResult Releasing Fcb extent lock %08lX EXCL %08lX\n",
1244                       &pNPFcb->Specific.File.ExtentsResource,
1245                       PsGetCurrentThread());
1246
1247         AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
1248     }
1249
1250     return ntStatus;
1251 }
1252
1253 NTSTATUS
1254 AFSProcessSetFileExtents( IN AFSSetFileExtentsCB *SetExtents )
1255 {
1256     AFSFcb       *pFcb = NULL;
1257     AFSVolumeCB  *pVolumeCB = NULL;
1258     NTSTATUS      ntStatus = STATUS_SUCCESS;
1259     AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1260     ULONGLONG     ullIndex = 0;
1261     AFSObjectInfoCB *pObjectInfo = NULL;
1262     LONG          lCount;
1263
1264     __Enter
1265     {
1266
1267         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1268                       AFS_TRACE_LEVEL_VERBOSE,
1269                       "AFSProcessSetFileExtents Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n",
1270                       &pDevExt->Specific.RDR.VolumeTreeLock,
1271                       PsGetCurrentThread());
1272
1273         AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
1274
1275         AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1276                       AFS_TRACE_LEVEL_VERBOSE,
1277                       "AFSProcessSetFileExtents Set extents for fid %08lX-%08lX-%08lX-%08lX\n",
1278                       SetExtents->FileId.Cell,
1279                       SetExtents->FileId.Volume,
1280                       SetExtents->FileId.Vnode,
1281                       SetExtents->FileId.Unique);
1282
1283         //
1284         // Locate the volume node
1285         //
1286
1287         ullIndex = AFSCreateHighIndex( &SetExtents->FileId);
1288
1289         ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
1290                                        ullIndex,
1291                                        (AFSBTreeEntry **)&pVolumeCB);
1292
1293         if( pVolumeCB != NULL)
1294         {
1295
1296             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1297                           AFS_TRACE_LEVEL_VERBOSE,
1298                           "AFSProcessSetFileExtents Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n",
1299                           pVolumeCB->ObjectInfoTree.TreeLock,
1300                           PsGetCurrentThread());
1301
1302             lCount = InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
1303         }
1304
1305         AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
1306
1307         if( !NT_SUCCESS( ntStatus) ||
1308             pVolumeCB == NULL)
1309         {
1310
1311             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1312                           AFS_TRACE_LEVEL_ERROR,
1313                           "AFSProcessSetFileExtents Set extents for fid %08lX-%08lX-%08lX-%08lX Failed to locate volume Status %08lX\n",
1314                           SetExtents->FileId.Cell,
1315                           SetExtents->FileId.Volume,
1316                           SetExtents->FileId.Vnode,
1317                           SetExtents->FileId.Unique,
1318                           ntStatus);
1319
1320             try_return( ntStatus = STATUS_UNSUCCESSFUL);
1321         }
1322
1323         AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1324                           TRUE);
1325
1326         lCount = InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1327
1328         //
1329         // Now locate the Object in this volume
1330         //
1331
1332         ullIndex = AFSCreateLowIndex( &SetExtents->FileId);
1333
1334         ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
1335                                        ullIndex,
1336                                        (AFSBTreeEntry **)&pObjectInfo);
1337
1338         if( pObjectInfo != NULL)
1339         {
1340
1341             //
1342             // Reference the node so it won't be torn down
1343             //
1344
1345             lCount = InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
1346
1347             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1348                           AFS_TRACE_LEVEL_VERBOSE,
1349                           "AFSProcessSetFileExtents Increment count on object %08lX Cnt %d\n",
1350                           pObjectInfo,
1351                           lCount);
1352         }
1353
1354         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1355
1356         if( !NT_SUCCESS( ntStatus) ||
1357             pObjectInfo == NULL)
1358         {
1359
1360             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1361                           AFS_TRACE_LEVEL_ERROR,
1362                           "AFSProcessSetFileExtents Set extents for hash %I64X fid %08lX-%08lX-%08lX-%08lX Failed to locate file in volume %08lX\n",
1363                           ullIndex,
1364                           SetExtents->FileId.Cell,
1365                           SetExtents->FileId.Volume,
1366                           SetExtents->FileId.Vnode,
1367                           SetExtents->FileId.Unique,
1368                           pVolumeCB);
1369
1370             try_return( ntStatus = STATUS_UNSUCCESSFUL);
1371         }
1372
1373         pFcb = pObjectInfo->Fcb;
1374
1375         //
1376         // If we have a result failure then don't bother trying to set the extents
1377         //
1378
1379         if( SetExtents->ResultStatus != STATUS_SUCCESS)
1380         {
1381
1382             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1383                           AFS_TRACE_LEVEL_ERROR,
1384                           "AFSProcessSetFileExtents Set extents failure fid %08lX-%08lX-%08lX-%08lX ResultStatus %08lX\n",
1385                           SetExtents->FileId.Cell,
1386                           SetExtents->FileId.Volume,
1387                           SetExtents->FileId.Vnode,
1388                           SetExtents->FileId.Unique,
1389                           SetExtents->ResultStatus);
1390
1391             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1392                           AFS_TRACE_LEVEL_VERBOSE,
1393                           "AFSProcessSetFileExtents Acquiring Fcb extents lock %08lX EXCL %08lX\n",
1394                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1395                           PsGetCurrentThread());
1396
1397             AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource,
1398                             TRUE);
1399
1400             pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_CANCELLED;
1401
1402             KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete,
1403                         0,
1404                         FALSE);
1405
1406             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1407                           AFS_TRACE_LEVEL_VERBOSE,
1408                           "AFSProcessSetFileExtents Releasing Fcb extent lock %08lX EXCL %08lX\n",
1409                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1410                           PsGetCurrentThread());
1411
1412             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
1413
1414             try_return( ntStatus);
1415         }
1416
1417         ntStatus = AFSProcessExtentsResult ( pFcb,
1418                                              SetExtents->ExtentCount,
1419                                              SetExtents->FileExtents );
1420
1421 try_exit:
1422
1423         if( pObjectInfo != NULL)
1424         {
1425
1426             lCount = InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
1427
1428             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1429                           AFS_TRACE_LEVEL_VERBOSE,
1430                           "AFSProcessSetFileExtents Decrement count on object %08lX Cnt %d\n",
1431                           pObjectInfo,
1432                           lCount);
1433         }
1434     }
1435
1436     return ntStatus;
1437 }
1438
1439 //
1440 // Helper fuctions for Usermode initiation of release of extents
1441 //
1442 NTSTATUS
1443 AFSReleaseSpecifiedExtents( IN  AFSReleaseFileExtentsCB *Extents,
1444                             IN  AFSFcb *Fcb,
1445                             OUT AFSFileExtentCB *FileExtents,
1446                             IN  ULONG BufferSize,
1447                             OUT ULONG *ExtentCount,
1448                             OUT BOOLEAN *DirtyExtents)
1449 {
1450     AFSExtent           *pExtent;
1451     LIST_ENTRY          *le;
1452     LIST_ENTRY          *leNext;
1453     ULONG                ulExtentCount = 0;
1454     NTSTATUS             ntStatus = STATUS_SUCCESS;
1455     BOOLEAN              bReleaseAll = FALSE;
1456     AFSDeviceExt        *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1457     LONG                 lCount;
1458
1459     __Enter
1460     {
1461         ASSERT( ExIsResourceAcquiredExclusiveLite( &Fcb->NPFcb->Specific.File.ExtentsResource));
1462
1463         if (BufferSize < (Extents->ExtentCount * sizeof( AFSFileExtentCB)))
1464         {
1465
1466             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1467                           AFS_TRACE_LEVEL_VERBOSE,
1468                           "AFSReleaseSpecifiedExtents Buffer too small\n");
1469
1470             try_return( ntStatus = STATUS_BUFFER_TOO_SMALL);
1471         }
1472
1473         RtlZeroMemory( FileExtents, BufferSize);
1474         *ExtentCount = 0;
1475
1476         *DirtyExtents = FALSE;
1477
1478         //
1479         // iterate until we have dealt with all we were asked for or
1480         // are at the end of the list.  Note that this deals (albeit
1481         // badly) with out of order extents
1482         //
1483
1484         pExtent = AFSExtentForOffset( Fcb,
1485                                       &Extents->FileExtents[0].FileOffset,
1486                                       FALSE);
1487
1488         if (NULL == pExtent)
1489         {
1490             le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1491         }
1492         else
1493         {
1494             le = &pExtent->Lists[AFS_EXTENTS_LIST];
1495         }
1496         ulExtentCount = 0;
1497
1498         if( BooleanFlagOn( Extents->Flags, AFS_RELEASE_EXTENTS_FLAGS_RELEASE_ALL) ||
1499             ( Extents->FileId.Cell   == 0 &&
1500               Extents->FileId.Volume == 0 &&
1501               Extents->FileId.Vnode  == 0 &&
1502               Extents->FileId.Unique == 0))
1503         {
1504
1505             bReleaseAll = TRUE;
1506         }
1507
1508         while( le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST] &&
1509                ulExtentCount < Extents->ExtentCount)
1510
1511         {
1512
1513             pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
1514
1515             if( !bReleaseAll)
1516             {
1517
1518                 if( pExtent->FileOffset.QuadPart < Extents->FileExtents[ulExtentCount].FileOffset.QuadPart)
1519                 {
1520                     //
1521                     // Skip forward through the extent list until we get
1522                     // to the one we want
1523                     //
1524                     le = le->Flink;
1525
1526                     continue;
1527                 }
1528                 else if (pExtent->FileOffset.QuadPart > Extents->FileExtents[ulExtentCount].FileOffset.QuadPart)
1529                 {
1530                     //
1531                     // We don't have the extent asked for so return UNKNOWN
1532                     //
1533
1534                     AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1535                                   AFS_TRACE_LEVEL_VERBOSE,
1536                                   "AFSReleaseSpecifiedExtents Located UNKNOWN extent Offset %I64X Len %08lX\n",
1537                                   Extents->FileExtents[ulExtentCount].FileOffset.QuadPart,
1538                                   Extents->FileExtents[ulExtentCount].Length);
1539
1540                     FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_UNKNOWN;
1541
1542                     FileExtents[*ExtentCount].Length = 0;
1543                     FileExtents[*ExtentCount].CacheOffset.QuadPart = 0;
1544                     FileExtents[*ExtentCount].FileOffset = Extents->FileExtents[ulExtentCount].FileOffset;
1545
1546                     *ExtentCount = (*ExtentCount) + 1;
1547
1548                     ulExtentCount++;
1549
1550                     //
1551                     // Reset where we are looking
1552                     //
1553
1554                     le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1555
1556                     continue;
1557                 }
1558                 else if( pExtent->ActiveCount > 0)
1559                 {
1560
1561                     AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1562                                   AFS_TRACE_LEVEL_VERBOSE,
1563                                   "AFSReleaseSpecifiedExtents Located IN_USE extent Offset %I64X Len %08lX\n",
1564                                   Extents->FileExtents[ulExtentCount].FileOffset.QuadPart,
1565                                   Extents->FileExtents[ulExtentCount].Length);
1566
1567                     FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_IN_USE;
1568
1569                     FileExtents[*ExtentCount].Length = 0;
1570                     FileExtents[*ExtentCount].CacheOffset.QuadPart = 0;
1571                     FileExtents[*ExtentCount].FileOffset = Extents->FileExtents[ulExtentCount].FileOffset;
1572
1573                     *ExtentCount = (*ExtentCount) + 1;
1574
1575                     ulExtentCount++;
1576
1577                     //
1578                     // Reset where we are looking
1579                     //
1580
1581                     le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1582
1583                     continue;
1584                 }
1585             }
1586             else
1587             {
1588
1589                 //
1590                 // If the extent is currently active then skip it
1591                 //
1592
1593                 if( pExtent->ActiveCount > 0)
1594                 {
1595
1596                     le = le->Flink;
1597
1598                     continue;
1599                 }
1600             }
1601
1602             FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_RELEASE;
1603
1604             FileExtents[*ExtentCount].Length = pExtent->Size;
1605             FileExtents[*ExtentCount].DirtyLength = pExtent->Size;
1606             FileExtents[*ExtentCount].DirtyOffset = 0;
1607             FileExtents[*ExtentCount].CacheOffset = pExtent->CacheOffset;
1608             FileExtents[*ExtentCount].FileOffset = pExtent->FileOffset;
1609
1610             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1611                           AFS_TRACE_LEVEL_VERBOSE,
1612                           "AFSReleaseSpecifiedExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
1613                           pExtent,
1614                           Fcb->ObjectInformation->FileId.Cell,
1615                           Fcb->ObjectInformation->FileId.Volume,
1616                           Fcb->ObjectInformation->FileId.Vnode,
1617                           Fcb->ObjectInformation->FileId.Unique,
1618                           FileExtents[*ExtentCount].FileOffset.QuadPart,
1619                           FileExtents[*ExtentCount].Length);
1620
1621             if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
1622             {
1623
1624                 AFSAcquireExcl( &Fcb->NPFcb->Specific.File.DirtyExtentsListLock,
1625                                 TRUE);
1626
1627                 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
1628                 {
1629
1630                     AFSRemoveEntryDirtyList( Fcb,
1631                                              pExtent);
1632
1633                     FileExtents[*ExtentCount].Flags |= AFS_EXTENT_FLAG_DIRTY;
1634
1635                     lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
1636
1637                     *DirtyExtents = TRUE;
1638                 }
1639
1640                 AFSReleaseResource( &Fcb->NPFcb->Specific.File.DirtyExtentsListLock);
1641             }
1642
1643             //
1644             // move forward all three cursors
1645             //
1646             le = le->Flink;
1647             ulExtentCount ++;
1648             *ExtentCount = (*ExtentCount) + 1;
1649
1650             //
1651             // And unpick
1652             //
1653             for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
1654             {
1655                 if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
1656                 {
1657                     RemoveEntryList( &pExtent->Lists[i] );
1658                 }
1659             }
1660
1661             InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
1662
1663             InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
1664
1665             //
1666             // and free
1667             //
1668             AFSExFreePool( pExtent);
1669
1670             lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
1671
1672             lCount = InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount);
1673
1674             if( lCount == 0)
1675             {
1676
1677                 KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
1678                             0,
1679                             FALSE);
1680             }
1681         }
1682
1683 try_exit:
1684
1685         NOTHING;
1686     }
1687
1688     return ntStatus;
1689 }
1690
1691 AFSFcb*
1692 AFSFindFcbToClean(ULONG IgnoreTime, AFSFcb *LastFcb, BOOLEAN Block)
1693 {
1694
1695     AFSFcb *pFcb = NULL;
1696     AFSVolumeCB *pVolumeCB = NULL;
1697     AFSDeviceExt *pRDRDeviceExt = NULL;
1698     AFSDeviceExt *pControlDeviceExt = NULL;
1699     BOOLEAN bLocatedEntry = FALSE;
1700     AFSObjectInfoCB *pCurrentObject = NULL;
1701     BOOLEAN bReleaseVolumeListLock = FALSE;
1702     LONG lCount;
1703
1704     pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1705     pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1706
1707     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1708                   AFS_TRACE_LEVEL_VERBOSE,
1709                   "AFSFindFcbToClean Acquiring RDR VolumeListLock lock %08lX SHARED %08lX\n",
1710                   &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1711                   PsGetCurrentThread());
1712
1713     AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1714                       TRUE);
1715
1716     bReleaseVolumeListLock = TRUE;
1717
1718     pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead;
1719
1720     while( pVolumeCB != NULL)
1721     {
1722
1723         //
1724         // The Volume list may move under our feet.  Lock it.
1725         //
1726
1727         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1728                       AFS_TRACE_LEVEL_VERBOSE,
1729                       "AFSFindFcbToClean Acquiring VolumeRoot ObjectInfoTree lock %08lX SHARED %08lX\n",
1730                       pVolumeCB->ObjectInfoTree.TreeLock,
1731                       PsGetCurrentThread());
1732
1733         lCount = InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
1734
1735         AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1736
1737         bReleaseVolumeListLock = FALSE;
1738
1739         AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1740                           TRUE);
1741
1742         lCount = InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1743
1744         if( NULL == LastFcb)
1745         {
1746
1747             pCurrentObject = pVolumeCB->ObjectInfoListHead;
1748         }
1749         else
1750         {
1751
1752             pCurrentObject = (AFSObjectInfoCB *)LastFcb->ObjectInformation->ListEntry.fLink;
1753         }
1754
1755         pFcb = NULL;
1756
1757         while( pCurrentObject != NULL)
1758         {
1759
1760             pFcb = (AFSFcb *)pCurrentObject->Fcb;
1761
1762             //
1763             // If the FCB is a candidate we try to lock it (but without waiting - which
1764             // means we are deadlock free
1765             //
1766
1767             if( pFcb != NULL &&
1768                 pFcb->Header.NodeTypeCode == AFS_FILE_FCB)
1769             {
1770
1771                 if( Block)
1772                 {
1773
1774                     AFSLockForExtentsTrim( pFcb);
1775                 }
1776                 else
1777                 {
1778
1779                     if( !AFSLockForExtentsTrimNoWait( pFcb))
1780                     {
1781
1782                         pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1783
1784                         pFcb = NULL;
1785
1786                         continue;
1787                     }
1788                 }
1789
1790                 //
1791                 // Need to be sure there are no current flushes in the queue
1792                 //
1793
1794                 if( pFcb->Specific.File.ExtentCount == 0)
1795                 {
1796
1797                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1798                                   AFS_TRACE_LEVEL_VERBOSE,
1799                                   "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n",
1800                                   &pFcb->NPFcb->Specific.File.ExtentsResource,
1801                                   PsGetCurrentThread());
1802
1803                     AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
1804
1805                     pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1806
1807                     pFcb = NULL;
1808
1809                     continue;
1810                 }
1811
1812                 if( pFcb->Specific.File.QueuedFlushCount > 0)
1813                 {
1814
1815                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1816                                   AFS_TRACE_LEVEL_VERBOSE,
1817                                   "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n",
1818                                   &pFcb->NPFcb->Specific.File.ExtentsResource,
1819                                   PsGetCurrentThread());
1820
1821                     AFSReleaseResource(&pFcb->NPFcb->Specific.File.ExtentsResource);
1822
1823                     if( Block)
1824                     {
1825                         AFSWaitOnQueuedFlushes( pFcb);
1826                     }
1827                     else
1828                     {
1829
1830                         pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1831                     }
1832
1833                     pFcb = NULL;
1834
1835                     continue;
1836                 }
1837
1838                 if( pFcb->OpenHandleCount > 0)
1839                 {
1840
1841                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1842                                   AFS_TRACE_LEVEL_VERBOSE,
1843                                   "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n",
1844                                   &pFcb->NPFcb->Specific.File.ExtentsResource,
1845                                   PsGetCurrentThread());
1846
1847                     AFSReleaseResource(&pFcb->NPFcb->Specific.File.ExtentsResource);
1848
1849                     pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1850
1851                     pFcb = NULL;
1852
1853                     continue;
1854                 }
1855
1856                 //
1857                 // A hit a very palpable hit.  Pin it
1858                 //
1859
1860                 lCount = InterlockedIncrement( &pCurrentObject->ObjectReferenceCount);
1861
1862                 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1863                               AFS_TRACE_LEVEL_VERBOSE,
1864                               "AFSFindFcbToClean Increment count on Fcb %08lX Cnt %d\n",
1865                               pCurrentObject,
1866                               lCount);
1867
1868                 bLocatedEntry = TRUE;
1869
1870                 break;
1871             }
1872
1873             pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1874
1875             pFcb = NULL;
1876         }
1877
1878         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1879
1880         if( bLocatedEntry)
1881         {
1882             break;
1883         }
1884
1885         AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1886                           TRUE);
1887
1888         bReleaseVolumeListLock = TRUE;
1889
1890         pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1891     }
1892
1893     if( bReleaseVolumeListLock)
1894     {
1895
1896         AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1897     }
1898
1899     return pFcb;
1900 }
1901
1902 NTSTATUS
1903 AFSProcessExtentFailure( PIRP Irp)
1904 {
1905     AFSExtentFailureCB                *pFailureCB = NULL;
1906     NTSTATUS                           ntStatus = STATUS_SUCCESS;
1907     AFSDeviceExt                      *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension;
1908     PIO_STACK_LOCATION                 pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1909     AFSVolumeCB                       *pVolumeCB = NULL;
1910     ULONGLONG                          ullIndex = 0;
1911     AFSObjectInfoCB                   *pObjectInfo = NULL;
1912     LONG                               lCount;
1913
1914     __Enter
1915     {
1916         if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSExtentFailureCB))
1917         {
1918
1919             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1920                           AFS_TRACE_LEVEL_ERROR,
1921                           "AFSProcessExtentFailure Input buffer too small\n");
1922
1923             try_return( ntStatus = STATUS_INVALID_PARAMETER);
1924         }
1925
1926         pFailureCB = (AFSExtentFailureCB *)Irp->AssociatedIrp.SystemBuffer;
1927
1928         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1929                       AFS_TRACE_LEVEL_ERROR,
1930                       "AFSProcessExtentFailure Service Reports Failure fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
1931                       pFailureCB->FileId.Cell,
1932                       pFailureCB->FileId.Volume,
1933                       pFailureCB->FileId.Vnode,
1934                       pFailureCB->FileId.Unique,
1935                       pFailureCB->FailureStatus);
1936
1937         AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
1938
1939         //
1940         // Locate the volume node
1941         //
1942
1943         ullIndex = AFSCreateHighIndex( &pFailureCB->FileId);
1944
1945         ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
1946                                        ullIndex,
1947                                        (AFSBTreeEntry **)&pVolumeCB);
1948
1949         if( pVolumeCB != NULL)
1950         {
1951
1952             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1953                           AFS_TRACE_LEVEL_VERBOSE,
1954                           "AFSProcessExtentFailure Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n",
1955                           pVolumeCB->ObjectInfoTree.TreeLock,
1956                           PsGetCurrentThread());
1957
1958             lCount = InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
1959         }
1960
1961         AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
1962
1963         if( !NT_SUCCESS( ntStatus) ||
1964             pVolumeCB == NULL)
1965         {
1966
1967             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1968                           AFS_TRACE_LEVEL_ERROR,
1969                           "AFSProcessExtentFailure Invalid volume index %I64X status %08X\n",
1970                           ullIndex, ntStatus);
1971
1972             try_return( ntStatus = STATUS_UNSUCCESSFUL);
1973         }
1974
1975         AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1976                           TRUE);
1977
1978         lCount = InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1979
1980         //
1981         // Now locate the Object in this volume
1982         //
1983
1984         ullIndex = AFSCreateLowIndex( &pFailureCB->FileId);
1985
1986         ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
1987                                        ullIndex,
1988                                        (AFSBTreeEntry **)&pObjectInfo);
1989
1990         if( pObjectInfo != NULL &&
1991             pObjectInfo->Fcb != NULL)
1992         {
1993
1994             //
1995             // Reference the node so it won't be torn down
1996             //
1997
1998             lCount = InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
1999
2000             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2001                           AFS_TRACE_LEVEL_VERBOSE,
2002                           "AFSProcessExtentFailure Increment count on object %08lX Cnt %d\n",
2003                           pObjectInfo,
2004                           lCount);
2005         }
2006
2007         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
2008
2009         if( !NT_SUCCESS( ntStatus) ||
2010             pObjectInfo == NULL ||
2011             pObjectInfo->Fcb == NULL)
2012         {
2013
2014             if( pObjectInfo == NULL)
2015             {
2016                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2017                               AFS_TRACE_LEVEL_ERROR,
2018                               "AFSProcessExtentFailure Invalid file index %I64X\n",
2019                               ullIndex);
2020             }
2021             else
2022             {
2023                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2024                               AFS_TRACE_LEVEL_ERROR,
2025                               "AFSProcessExtentFailure Fcb dealocated for %I64X\n",
2026                               ullIndex);
2027             }
2028
2029             try_return( ntStatus = STATUS_UNSUCCESSFUL);
2030         }
2031
2032         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2033                       AFS_TRACE_LEVEL_VERBOSE,
2034                       "AFSProcessExtentFailure Acquiring Fcb extent lock %08lX EXCL %08lX\n",
2035                       &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
2036                       PsGetCurrentThread());
2037
2038         AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
2039                         TRUE);
2040
2041         pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = pFailureCB->FailureStatus;
2042
2043         RtlCopyMemory( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2044                        &pFailureCB->AuthGroup,
2045                        sizeof( GUID));
2046
2047         KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
2048                     0,
2049                     FALSE);
2050
2051         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2052                       AFS_TRACE_LEVEL_VERBOSE,
2053                       "AFSProcessExtentFailure Releasing Fcb extent lock %08lX EXCL %08lX\n",
2054                       &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
2055                       PsGetCurrentThread());
2056
2057         AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource);
2058
2059         lCount = InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
2060
2061         AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2062                       AFS_TRACE_LEVEL_VERBOSE,
2063                       "AFSProcessExtentFailure Decrement count on object %08lX Cnt %d\n",
2064                       pObjectInfo,
2065                       lCount);
2066
2067 try_exit:
2068
2069         NOTHING;
2070     }
2071
2072     return ntStatus;
2073 }
2074
2075 NTSTATUS
2076 AFSProcessReleaseFileExtents( IN PIRP Irp)
2077 {
2078     NTSTATUS                           ntStatus = STATUS_SUCCESS;
2079     PIO_STACK_LOCATION                 pIrpSp = IoGetCurrentIrpStackLocation( Irp);
2080     PFILE_OBJECT                       pFileObject = pIrpSp->FileObject;
2081     AFSFcb                            *pFcb = NULL;
2082     AFSVolumeCB                       *pVolumeCB = NULL;
2083     AFSDeviceExt                      *pDevExt;
2084     AFSReleaseFileExtentsCB           *pExtents;
2085     AFSReleaseFileExtentsResultCB     *pResult = NULL;
2086     AFSReleaseFileExtentsResultFileCB *pFile = NULL;
2087     ULONG                              ulSz = 0;
2088     ULONGLONG                          ullIndex = 0;
2089     AFSObjectInfoCB                   *pObjectInfo = NULL;
2090     BOOLEAN                            bLocked = FALSE;
2091     BOOLEAN                            bDirtyExtents = FALSE;
2092     GUID                               stAuthGroup;
2093     LONG                               lCount;
2094
2095     __Enter
2096     {
2097
2098         pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension;
2099
2100         pExtents = (AFSReleaseFileExtentsCB*) Irp->AssociatedIrp.SystemBuffer;
2101
2102         if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2103                                             sizeof( AFSReleaseFileExtentsCB))
2104         {
2105
2106             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2107                           AFS_TRACE_LEVEL_ERROR,
2108                           "AFSProcessReleaseFileExtents INPUT Buffer too small\n");
2109
2110             try_return( ntStatus = STATUS_INVALID_PARAMETER );
2111         }
2112
2113         if ( pIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
2114                                         sizeof(AFSReleaseFileExtentsResultCB))
2115         {
2116
2117             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2118                           AFS_TRACE_LEVEL_ERROR,
2119                           "AFSProcessReleaseFileExtents OUTPUT Buffer too small [1]\n");
2120
2121             //
2122             // Must have space for one extent in one file
2123             //
2124
2125             try_return( ntStatus = STATUS_BUFFER_TOO_SMALL);
2126         }
2127
2128         if (pExtents->ExtentCount == 0)
2129         {
2130
2131             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2132                           AFS_TRACE_LEVEL_ERROR,
2133                           "AFSProcessReleaseFileExtents Extent count zero\n");
2134
2135             try_return( ntStatus = STATUS_INVALID_PARAMETER);
2136         }
2137
2138         if (pExtents->FileId.Cell   != 0 ||
2139             pExtents->FileId.Volume != 0 ||
2140             pExtents->FileId.Vnode  != 0 ||
2141             pExtents->FileId.Unique != 0)
2142         {
2143
2144             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2145                           AFS_TRACE_LEVEL_VERBOSE,
2146                           "AFSProcessReleaseFileExtents Processing FID %08lX:%08lX:%08lX:%08lX\n",
2147                           pExtents->FileId.Cell,
2148                           pExtents->FileId.Volume,
2149                           pExtents->FileId.Vnode,
2150                           pExtents->FileId.Unique);
2151
2152             if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2153                             ( FIELD_OFFSET( AFSReleaseFileExtentsCB, ExtentCount) + sizeof(ULONG)) ||
2154                 pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2155                             ( FIELD_OFFSET( AFSReleaseFileExtentsCB, ExtentCount) + sizeof(ULONG) +
2156                                                             sizeof (AFSFileExtentCB) * pExtents->ExtentCount))
2157             {
2158
2159                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2160                               AFS_TRACE_LEVEL_ERROR,
2161                               "AFSProcessReleaseFileExtents Buffer too small for FID %08lX:%08lx:%08lX:%08lX\n",
2162                               pExtents->FileId.Cell,
2163                               pExtents->FileId.Volume,
2164                               pExtents->FileId.Vnode,
2165                               pExtents->FileId.Unique);
2166
2167                 try_return( ntStatus = STATUS_INVALID_PARAMETER );
2168             }
2169
2170             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2171                           AFS_TRACE_LEVEL_VERBOSE,
2172                           "AFSProcessReleaseFileExtents Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n",
2173                           &pDevExt->Specific.RDR.VolumeTreeLock,
2174                           PsGetCurrentThread());
2175
2176             AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
2177
2178             //
2179             // Locate the volume node
2180             //
2181
2182             ullIndex = AFSCreateHighIndex( &pExtents->FileId);
2183
2184             ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
2185                                            ullIndex,
2186                                            (AFSBTreeEntry **)&pVolumeCB);
2187
2188             if( pVolumeCB != NULL)
2189             {
2190
2191                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2192                               AFS_TRACE_LEVEL_VERBOSE,
2193                               "AFSProcessReleaseFileExtents Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n",
2194                               pVolumeCB->ObjectInfoTree.TreeLock,
2195                               PsGetCurrentThread());
2196
2197                 lCount = InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
2198             }
2199
2200             AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
2201
2202             if( !NT_SUCCESS( ntStatus) ||
2203                 pVolumeCB == NULL)
2204             {
2205
2206                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2207                               AFS_TRACE_LEVEL_ERROR,
2208                               "AFSProcessReleaseFileExtents Invalid volume index %I64X status %08X\n",
2209                               ullIndex, ntStatus);
2210
2211                 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2212             }
2213
2214             AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
2215                               TRUE);
2216
2217             lCount = InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
2218
2219             //
2220             // Now locate the Object in this volume
2221             //
2222
2223             ullIndex = AFSCreateLowIndex( &pExtents->FileId);
2224
2225             ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
2226                                            ullIndex,
2227                                            (AFSBTreeEntry **)&pObjectInfo);
2228
2229             if( pObjectInfo != NULL)
2230             {
2231
2232                 //
2233                 // Reference the node so it won't be torn down
2234                 //
2235
2236                 lCount = InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
2237
2238                 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2239                               AFS_TRACE_LEVEL_VERBOSE,
2240                               "AFSProcessReleaseFileExtents Increment count on object %08lX Cnt %d\n",
2241                               pObjectInfo,
2242                               lCount);
2243             }
2244
2245             AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
2246
2247             if( !NT_SUCCESS( ntStatus) ||
2248                 pObjectInfo == NULL)
2249             {
2250
2251                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2252                               AFS_TRACE_LEVEL_ERROR,
2253                               "AFSProcessReleaseFileExtents Invalid file index %I64X\n",
2254                               ullIndex);
2255
2256                 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2257             }
2258
2259             pFcb = pObjectInfo->Fcb;
2260
2261             if( pFcb == NULL)
2262             {
2263
2264                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2265                               AFS_TRACE_LEVEL_ERROR,
2266                               "AFSProcessReleaseFileExtents Fcb not initialied (NO EXTENTS) for FID %08lX:%08lx:%08lX:%08lX\n",
2267                               pExtents->FileId.Cell,
2268                               pExtents->FileId.Volume,
2269                               pExtents->FileId.Vnode,
2270                               pExtents->FileId.Unique);
2271
2272                 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2273             }
2274
2275             AFSLockForExtentsTrim( pFcb );
2276
2277             bLocked = TRUE;
2278         }
2279         else
2280         {
2281
2282             //
2283             // Locate an Fcb to trim down
2284             //
2285
2286             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2287                           AFS_TRACE_LEVEL_VERBOSE,
2288                           "AFSProcessReleaseFileExtents Searching for a Fcb to Trim Down\n");
2289
2290             pFcb = AFSFindFcbToClean( 0, NULL, FALSE);
2291
2292             if( pFcb == NULL)
2293             {
2294
2295                 pFcb = AFSFindFcbToClean( 0, NULL, TRUE);
2296             }
2297
2298             if( pFcb == NULL)
2299             {
2300
2301                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2302                               AFS_TRACE_LEVEL_ERROR,
2303                               "AFSProcessReleaseFileExtents Failed to locate Fcb for release ...\n");
2304
2305                 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2306             }
2307
2308             pObjectInfo = pFcb->ObjectInformation;
2309
2310             bLocked = TRUE;
2311         }
2312
2313         //
2314         // Allocate a scratch buffer to move in the extent information
2315         //
2316
2317         ulSz = (pExtents->ExtentCount-1) * sizeof(AFSFileExtentCB);
2318         ulSz += sizeof(AFSReleaseFileExtentsResultCB);
2319
2320         if (ulSz > pIrpSp->Parameters.DeviceIoControl.OutputBufferLength)
2321         {
2322             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2323                           AFS_TRACE_LEVEL_ERROR,
2324                           "AFSProcessReleaseFileExtents OUTPUT Buffer too small [2]\n");
2325
2326             try_return( ntStatus = STATUS_BUFFER_TOO_SMALL );
2327         }
2328
2329         pResult = (AFSReleaseFileExtentsResultCB*) AFSExAllocatePoolWithTag( PagedPool,
2330                                                                              ulSz,
2331                                                                              AFS_EXTENTS_RESULT_TAG);
2332         if (NULL == pResult)
2333         {
2334
2335             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2336                           AFS_TRACE_LEVEL_ERROR,
2337                           "AFSProcessReleaseFileExtents Failed to allocate result block\n");
2338
2339             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2340         }
2341
2342         //
2343         // Set up the header (for an array of one)
2344         //
2345         pResult->FileCount = 1;
2346         pResult->Flags = AFS_EXTENT_FLAG_RELEASE;
2347         ulSz -= FIELD_OFFSET(AFSReleaseFileExtentsResultCB, Files);
2348
2349         //
2350         // Setup the first (and only) file
2351         //
2352         pFile = pResult->Files;
2353         pFile->FileId = pObjectInfo->FileId;
2354         pFile->Flags = AFS_EXTENT_FLAG_RELEASE;
2355
2356         //
2357         // Stash away the auth group
2358         //
2359
2360         RtlZeroMemory( &stAuthGroup,
2361                        sizeof( GUID));
2362
2363         ntStatus = AFSRetrieveValidAuthGroup( pFcb,
2364                                               NULL,
2365                                               TRUE,
2366                                               &stAuthGroup);
2367
2368         if( !NT_SUCCESS( ntStatus))
2369         {
2370             try_return( ntStatus);
2371         }
2372
2373         RtlCopyMemory( &pFile->AuthGroup,
2374                        &stAuthGroup,
2375                        sizeof( GUID));
2376
2377         //
2378         // Update the metadata for this call
2379         //
2380
2381         pFile->AllocationSize = pFcb->ObjectInformation->EndOfFile;
2382         pFile->CreateTime = pFcb->ObjectInformation->CreationTime;
2383         pFile->ChangeTime = pFcb->ObjectInformation->ChangeTime;
2384         pFile->LastAccessTime = pFcb->ObjectInformation->LastAccessTime;
2385         pFile->LastWriteTime = pFcb->ObjectInformation->LastWriteTime;
2386
2387         ulSz -= FIELD_OFFSET(AFSReleaseFileExtentsResultFileCB, FileExtents);
2388
2389         ntStatus = AFSReleaseSpecifiedExtents( pExtents,
2390                                                pFcb,
2391                                                pFile->FileExtents,
2392                                                ulSz,
2393                                                &pFile->ExtentCount,
2394                                                &bDirtyExtents);
2395
2396         if (!NT_SUCCESS(ntStatus))
2397         {
2398
2399             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2400                           AFS_TRACE_LEVEL_ERROR,
2401                           "AFSProcessReleaseFileExtents Failed to release extents Status %08lX\n",
2402                           ntStatus);
2403
2404             try_return( ntStatus );
2405         }
2406
2407         if( pExtents->ExtentCount == 0)
2408         {
2409
2410             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2411                           AFS_TRACE_LEVEL_WARNING,
2412                           "AFSProcessReleaseFileExtents Failed to release ANY extents\n");
2413         }
2414
2415         ulSz = sizeof(AFSReleaseFileExtentsResultCB);
2416
2417         if( pExtents->ExtentCount > 0)
2418         {
2419             ulSz += ((pExtents->ExtentCount-1) * sizeof(AFSFileExtentCB));
2420         }
2421
2422         RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer,
2423                        pResult,
2424                        ulSz);
2425
2426 try_exit:
2427
2428         if( bLocked)
2429         {
2430
2431             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2432                           AFS_TRACE_LEVEL_VERBOSE,
2433                           "AFSProcessReleaseFileExtents Releasing Fcb extent lock %08lX thread %08lX\n",
2434                           &pFcb->NPFcb->Specific.File.ExtentsResource,
2435                           PsGetCurrentThread());
2436
2437             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
2438         }
2439
2440         if( NULL != pResult &&
2441             Irp->AssociatedIrp.SystemBuffer != pResult)
2442         {
2443
2444             AFSExFreePool(pResult);
2445         }
2446
2447         if (NT_SUCCESS(ntStatus))
2448         {
2449             Irp->IoStatus.Information = ulSz;
2450         }
2451         else
2452         {
2453             Irp->IoStatus.Information = 0;
2454         }
2455
2456         Irp->IoStatus.Status = ntStatus;
2457
2458         if( pObjectInfo != NULL)
2459         {
2460
2461             lCount = InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
2462
2463             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2464                           AFS_TRACE_LEVEL_VERBOSE,
2465                           "AFSProcessReleaseFileExtents Decrement count on object %08lX Cnt %d\n",
2466                           pObjectInfo,
2467                           lCount);
2468         }
2469     }
2470
2471     return ntStatus;
2472 }
2473
2474 NTSTATUS
2475 AFSWaitForExtentMapping( AFSFcb *Fcb,
2476                          AFSCcb *Ccb)
2477 {
2478     NTSTATUS ntStatus = STATUS_SUCCESS;
2479     LARGE_INTEGER liTimeOut;
2480     ULONGLONG            ullProcessId = (ULONGLONG)PsGetCurrentProcessId();
2481
2482     __Enter
2483     {
2484
2485         ASSERT( !ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
2486
2487         if (!NT_SUCCESS( Fcb->NPFcb->Specific.File.ExtentsRequestStatus))
2488         {
2489
2490             //
2491             // If this isn't the same authgroup which caused the failure
2492             // then try to request them again
2493             //
2494
2495             if( RtlCompareMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2496                                   &Ccb->AuthGroup,
2497                                   sizeof( GUID)) == sizeof( GUID))
2498             {
2499
2500                 ntStatus = Fcb->NPFcb->Specific.File.ExtentsRequestStatus;
2501
2502                 Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
2503
2504                 RtlZeroMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2505                                sizeof( GUID));
2506
2507                 try_return( ntStatus);
2508             }
2509         }
2510
2511         liTimeOut.QuadPart = -(1 * AFS_ONE_SECOND);
2512
2513         ntStatus = KeWaitForSingleObject( &Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
2514                                           Executive,
2515                                           KernelMode,
2516                                           FALSE,
2517                                           &liTimeOut);
2518
2519         if (!NT_SUCCESS( Fcb->NPFcb->Specific.File.ExtentsRequestStatus))
2520         {
2521
2522             //
2523             // If this isn't the same authgroup which caused the failure
2524             // or the System Process,
2525             // then try to request the extents again
2526             //
2527
2528             if( RtlCompareMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2529                                   &Ccb->AuthGroup,
2530                                   sizeof( GUID)) == sizeof( GUID) ||
2531                 ullProcessId == (ULONGLONG)AFSSysProcess)
2532             {
2533
2534                 ntStatus = Fcb->NPFcb->Specific.File.ExtentsRequestStatus;
2535
2536                 Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
2537
2538                 RtlZeroMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2539                                sizeof( GUID));
2540
2541                 try_return( ntStatus);
2542             }
2543         }
2544
2545         if( ntStatus == STATUS_TIMEOUT)
2546         {
2547
2548             ntStatus = STATUS_SUCCESS;
2549         }
2550
2551 try_exit:
2552
2553         NOTHING;
2554     }
2555
2556     return ntStatus;
2557 }
2558
2559 NTSTATUS
2560 AFSFlushExtents( IN AFSFcb *Fcb,
2561                  IN GUID *AuthGroup)
2562 {
2563     AFSNonPagedFcb      *pNPFcb = Fcb->NPFcb;
2564     AFSExtent           *pExtent, *pNextExtent;
2565     LIST_ENTRY          *le;
2566     AFSReleaseExtentsCB *pRelease = NULL;
2567     ULONG                count = 0;
2568     ULONG                initialDirtyCount = 0;
2569     BOOLEAN              bExtentsLocked = FALSE;
2570     ULONG                total = 0;
2571     ULONG                sz = 0;
2572     NTSTATUS             ntStatus = STATUS_SUCCESS;
2573     LARGE_INTEGER        liLastFlush;
2574     AFSExtent           *pDirtyListHead = NULL, *pDirtyListTail = NULL;
2575     AFSDeviceExt        *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2576     GUID                *pAuthGroup = AuthGroup;
2577     GUID                 stAuthGroup;
2578     LONG                 lCount;
2579
2580     ASSERT( Fcb->Header.NodeTypeCode == AFS_FILE_FCB);
2581
2582     //
2583     // Save, then reset the flush time
2584     //
2585
2586     liLastFlush = Fcb->Specific.File.LastServerFlush;
2587
2588     KeQueryTickCount( &Fcb->Specific.File.LastServerFlush);
2589
2590     __Enter
2591     {
2592
2593         if( pAuthGroup == NULL ||
2594             RtlCompareMemory( pAuthGroup,
2595                               &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2596                               sizeof( GUID)) == sizeof( GUID))
2597         {
2598
2599             RtlZeroMemory( &stAuthGroup,
2600                            sizeof( GUID));
2601
2602             ntStatus = AFSRetrieveValidAuthGroup( Fcb,
2603                                                   NULL,
2604                                                   TRUE,
2605                                                   &stAuthGroup);
2606
2607             if( !NT_SUCCESS( ntStatus))
2608             {
2609                 try_return( ntStatus);
2610             }
2611
2612             pAuthGroup = &stAuthGroup;
2613         }
2614
2615         //
2616         // Lock extents while we count and set up the array to send to
2617         // the service
2618         //
2619
2620         AFSLockForExtentsTrim( Fcb);
2621
2622         bExtentsLocked = TRUE;
2623
2624         lCount = InterlockedIncrement( &Fcb->Specific.File.QueuedFlushCount);
2625
2626         //
2627         // Clear our queued flush event
2628         //
2629
2630         KeClearEvent( &Fcb->NPFcb->Specific.File.QueuedFlushEvent);
2631
2632         //
2633         // Look for a start in the list to flush entries
2634         //
2635
2636         total = count;
2637
2638         sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
2639
2640         pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
2641                                                                     sz,
2642                                                                     AFS_EXTENT_RELEASE_TAG);
2643         if( NULL == pRelease)
2644         {
2645
2646             try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2647         }
2648
2649         initialDirtyCount = Fcb->Specific.File.ExtentsDirtyCount;
2650
2651         while( Fcb->Specific.File.ExtentsDirtyCount > 0)
2652         {
2653
2654             pRelease->Flags = AFS_EXTENT_FLAG_DIRTY;
2655
2656             if( BooleanFlagOn( Fcb->Flags, AFS_FCB_FILE_CLOSED))
2657             {
2658
2659                 pRelease->Flags |= AFS_EXTENT_FLAG_FLUSH;
2660             }
2661
2662             //
2663             // Update the metadata for this call
2664             //
2665
2666             pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
2667             pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
2668             pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
2669             pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
2670             pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
2671
2672             count = 0;
2673
2674             AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
2675                             TRUE);
2676
2677             pExtent = (AFSExtent *)pNPFcb->Specific.File.DirtyListHead;
2678
2679             while( count < AFS_MAXIMUM_EXTENT_RELEASE_COUNT)
2680             {
2681
2682                 if ( pExtent == NULL)
2683                 {
2684
2685                     break;
2686                 }
2687
2688                 pNextExtent = (AFSExtent *)pExtent->DirtyList.fLink;
2689
2690                 if ( pExtent->ActiveCount > 0)
2691                 {
2692                     pExtent = pNextExtent;
2693                     continue;
2694                 }
2695
2696                 AFSRemoveEntryDirtyList( Fcb, pExtent);
2697
2698                 pExtent->DirtyList.fLink = NULL;
2699                 pExtent->DirtyList.bLink = NULL;
2700
2701                 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
2702
2703                 //
2704                 // Clear the flag in advance of the write. If we do
2705                 // things this was we know that the clear is
2706                 // pessimistic (any write which happens from now on
2707                 // will set the flag dirty again).
2708                 //
2709
2710                 pExtent->Flags &= ~AFS_EXTENT_DIRTY;
2711
2712                 pRelease->FileExtents[count].Flags = AFS_EXTENT_FLAG_DIRTY;
2713
2714                 pRelease->FileExtents[count].Length = pExtent->Size;
2715                 pRelease->FileExtents[count].DirtyLength = pExtent->Size;
2716                 pRelease->FileExtents[count].DirtyOffset = 0;
2717                 pRelease->FileExtents[count].CacheOffset = pExtent->CacheOffset;
2718                 pRelease->FileExtents[count].FileOffset = pExtent->FileOffset;
2719
2720 #if GEN_MD5
2721                 RtlCopyMemory( pRelease->FileExtents[count].MD5,
2722                                pExtent->MD5,
2723                                sizeof(pExtent->MD5));
2724
2725                 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_MD5_SET;
2726 #endif
2727
2728                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2729                               AFS_TRACE_LEVEL_VERBOSE,
2730                               "AFSFlushExtents Releasing DIRTY extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
2731                               pExtent,
2732                               Fcb->ObjectInformation->FileId.Cell,
2733                               Fcb->ObjectInformation->FileId.Volume,
2734                               Fcb->ObjectInformation->FileId.Vnode,
2735                               Fcb->ObjectInformation->FileId.Unique,
2736                               pExtent->FileOffset.QuadPart,
2737                               pExtent->Size);
2738
2739                 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_RELEASE;
2740
2741                 //
2742                 // Need to pull this extent from the main list as well
2743                 //
2744
2745                 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
2746                 {
2747                     if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
2748                     {
2749                         RemoveEntryList( &pExtent->Lists[i] );
2750                     }
2751                 }
2752
2753                 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
2754
2755                 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
2756
2757                 AFSExFreePool( pExtent);
2758
2759                 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
2760
2761                 lCount = InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount);
2762
2763                 if( lCount == 0)
2764                 {
2765
2766                     KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
2767                                 0,
2768                                 FALSE);
2769                 }
2770
2771                 count ++;
2772
2773                 pExtent = pNextExtent;
2774             }
2775
2776             AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
2777
2778             //
2779             // If we are done then get out
2780             //
2781
2782             if( count == 0)
2783             {
2784
2785                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2786                               AFS_TRACE_LEVEL_VERBOSE,
2787                               "AFSFlushExtents No more dirty extents found\n");
2788
2789                 break;
2790             }
2791
2792             //
2793             // Fire off the request synchronously
2794             //
2795
2796             sz = sizeof( AFSReleaseExtentsCB ) + (count * sizeof ( AFSFileExtentCB ));
2797
2798             pRelease->ExtentCount = count;
2799
2800             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2801                           AFS_TRACE_LEVEL_VERBOSE,
2802                           "AFSFlushExtents Releasing(1) Fcb extents lock %08lX SHARED %08lX\n",
2803                           &pNPFcb->Specific.File.ExtentsResource,
2804                           PsGetCurrentThread());
2805
2806             AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource);
2807             bExtentsLocked = FALSE;
2808
2809             KeSetEvent( &pNPFcb->Specific.File.FlushEvent,
2810                         0,
2811                         FALSE);
2812
2813             ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS,
2814                                           AFS_REQUEST_FLAG_SYNCHRONOUS,
2815                                           pAuthGroup,
2816                                           NULL,
2817                                           &Fcb->ObjectInformation->FileId,
2818                                           pRelease,
2819                                           sz,
2820                                           NULL,
2821                                           NULL);
2822
2823             if( !NT_SUCCESS(ntStatus))
2824             {
2825
2826                 //
2827                 // Regardless of whether or not the AFSProcessRequest() succeeded, the extents
2828                 // were released (if AFS_EXTENT_FLAG_RELEASE was set).  Log the error so it is known.
2829                 //
2830
2831                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2832                               AFS_TRACE_LEVEL_ERROR,
2833                               "AFSFlushExtents AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
2834                               Fcb->ObjectInformation->FileId.Cell,
2835                               Fcb->ObjectInformation->FileId.Volume,
2836                               Fcb->ObjectInformation->FileId.Vnode,
2837                               Fcb->ObjectInformation->FileId.Unique,
2838                               ntStatus);
2839
2840             }
2841             AFSLockForExtentsTrim( Fcb);
2842
2843             bExtentsLocked = TRUE;
2844         }
2845
2846 try_exit:
2847
2848         lCount = InterlockedDecrement( &Fcb->Specific.File.QueuedFlushCount);
2849
2850         if( lCount == 0)
2851         {
2852
2853             KeSetEvent( &pNPFcb->Specific.File.QueuedFlushEvent,
2854                         0,
2855                         FALSE);
2856         }
2857
2858         KeSetEvent( &pNPFcb->Specific.File.FlushEvent,
2859                     0,
2860                     FALSE);
2861
2862         if (bExtentsLocked)
2863         {
2864
2865             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2866                           AFS_TRACE_LEVEL_VERBOSE,
2867                           "AFSFlushExtents Releasing(2) Fcb extents lock %08lX SHARED %08lX\n",
2868                           &pNPFcb->Specific.File.ExtentsResource,
2869                           PsGetCurrentThread());
2870
2871             AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
2872         }
2873
2874         if (pRelease)
2875         {
2876             AFSExFreePool( pRelease);
2877         }
2878     }
2879
2880     return ntStatus;
2881 }
2882
2883 NTSTATUS
2884 AFSReleaseExtentsWithFlush( IN AFSFcb *Fcb,
2885                             IN GUID *AuthGroup)
2886 {
2887     AFSNonPagedFcb      *pNPFcb = Fcb->NPFcb;
2888     AFSExtent           *pExtent;
2889     LIST_ENTRY          *le;
2890     AFSReleaseExtentsCB *pRelease = NULL;
2891     ULONG                count = 0;
2892     ULONG                initialDirtyCount = 0;
2893     BOOLEAN              bExtentsLocked = FALSE;
2894     ULONG                total = 0;
2895     ULONG                sz = 0;
2896     NTSTATUS             ntStatus = STATUS_SUCCESS;
2897     LARGE_INTEGER        liLastFlush;
2898     ULONG                ulRemainingExtentLength = 0;
2899     AFSDeviceExt        *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2900     GUID                *pAuthGroup = AuthGroup;
2901     GUID                 stAuthGroup;
2902     LONG                 lCount;
2903
2904     ASSERT( Fcb->Header.NodeTypeCode == AFS_FILE_FCB);
2905
2906     //
2907     // Save, then reset the flush time
2908     //
2909
2910     liLastFlush = Fcb->Specific.File.LastServerFlush;
2911
2912     KeQueryTickCount( &Fcb->Specific.File.LastServerFlush);
2913
2914     __Enter
2915     {
2916
2917         if( pAuthGroup == NULL ||
2918             RtlCompareMemory( pAuthGroup,
2919                               &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2920                               sizeof( GUID)) == sizeof( GUID))
2921         {
2922
2923             RtlZeroMemory( &stAuthGroup,
2924                            sizeof( GUID));
2925
2926             ntStatus = AFSRetrieveValidAuthGroup( Fcb,
2927                                                   NULL,
2928                                                   TRUE,
2929                                                   &stAuthGroup);
2930
2931             if( !NT_SUCCESS( ntStatus))
2932             {
2933                 try_return( ntStatus);
2934             }
2935
2936             pAuthGroup = &stAuthGroup;
2937         }
2938
2939         //
2940         // Look for a start in the list to flush entries
2941         //
2942
2943         total = count;
2944
2945         sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
2946
2947         pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
2948                                                                     sz,
2949                                                                     AFS_EXTENT_RELEASE_TAG);
2950         if( NULL == pRelease)
2951         {
2952
2953             try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2954         }
2955
2956         if( Fcb->OpenHandleCount > 0)
2957         {
2958
2959             //
2960             // Don't release everything ...
2961             //
2962
2963             //
2964             // For now release everything
2965             //
2966
2967             //ulRemainingExtentLength = 1500;
2968         }
2969
2970         while( Fcb->Specific.File.ExtentLength > (LONG)ulRemainingExtentLength)
2971         {
2972
2973             AFSLockForExtentsTrim( Fcb);
2974
2975             bExtentsLocked = TRUE;
2976
2977             pRelease->Flags = AFS_EXTENT_FLAG_RELEASE;
2978
2979             //
2980             // Update the metadata for this call
2981             //
2982
2983             pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
2984             pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
2985             pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
2986             pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
2987             pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
2988
2989             count = 0;
2990
2991             le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
2992
2993             while( count < AFS_MAXIMUM_EXTENT_RELEASE_COUNT &&
2994                    le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
2995             {
2996
2997                 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
2998
2999                 le = le->Flink;
3000
3001                 if( pExtent->ActiveCount > 0)
3002                 {
3003
3004                     continue;
3005                 }
3006
3007                 pRelease->FileExtents[count].Flags = AFS_EXTENT_FLAG_RELEASE;
3008
3009                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3010                               AFS_TRACE_LEVEL_VERBOSE,
3011                               "AFSReleaseExtentsWithFlush Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
3012                               pExtent,
3013                               Fcb->ObjectInformation->FileId.Cell,
3014                               Fcb->ObjectInformation->FileId.Volume,
3015                               Fcb->ObjectInformation->FileId.Vnode,
3016                               Fcb->ObjectInformation->FileId.Unique,
3017                               pExtent->FileOffset.QuadPart,
3018                               pExtent->Size);
3019
3020                 pRelease->FileExtents[count].Length = pExtent->Size;
3021                 pRelease->FileExtents[count].DirtyLength = pExtent->Size;
3022                 pRelease->FileExtents[count].DirtyOffset = 0;
3023                 pRelease->FileExtents[count].CacheOffset = pExtent->CacheOffset;
3024                 pRelease->FileExtents[count].FileOffset = pExtent->FileOffset;
3025
3026 #if GEN_MD5
3027                 RtlCopyMemory( pRelease->FileExtents[count].MD5,
3028                                pExtent->MD5,
3029                                sizeof(pExtent->MD5));
3030
3031                 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_MD5_SET;
3032 #endif
3033
3034                 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3035                 {
3036
3037                     AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
3038                                     TRUE);
3039
3040                     if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3041                     {
3042
3043                         AFSRemoveEntryDirtyList( Fcb,
3044                                                  pExtent);
3045
3046                         pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_DIRTY;
3047
3048                         lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
3049                     }
3050
3051                     AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
3052                 }
3053
3054                 //
3055                 // Need to pull this extent from the main list as well
3056                 //
3057
3058                 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
3059                 {
3060                     if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
3061                     {
3062                         RemoveEntryList( &pExtent->Lists[i] );
3063                     }
3064                 }
3065
3066                 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
3067
3068                 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
3069
3070                 AFSExFreePool( pExtent);
3071
3072                 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
3073
3074                 lCount = InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount);
3075
3076                 if( lCount == 0)
3077                 {
3078
3079                     KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
3080                                 0,
3081                                 FALSE);
3082                 }
3083
3084                 count ++;
3085             }
3086
3087             //
3088             // If we are done then get out
3089             //
3090
3091             if( count == 0)
3092             {
3093
3094                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3095                 &nbs