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