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