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