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