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