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