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