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