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