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