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