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