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