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