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