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