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