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