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