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