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