0b7cfc6406c48bef6c0c4c0757679154bc47f057
[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 = AFSVolumeIncrement( pVolumeCB,
1430                                          AFS_VOLUME_REFERENCE_EXTENTS);
1431
1432             AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING,
1433                           AFS_TRACE_LEVEL_VERBOSE,
1434                           "AFSProcessSetFileExtents Increment count on volume %p Cnt %d\n",
1435                           pVolumeCB,
1436                           lCount);
1437         }
1438
1439         AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
1440
1441         if( !NT_SUCCESS( ntStatus) ||
1442             pVolumeCB == NULL)
1443         {
1444
1445             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1446                           AFS_TRACE_LEVEL_ERROR,
1447                           "AFSProcessSetFileExtents Set extents for fid %08lX-%08lX-%08lX-%08lX Failed to locate volume Status %08lX\n",
1448                           SetExtents->FileId.Cell,
1449                           SetExtents->FileId.Volume,
1450                           SetExtents->FileId.Vnode,
1451                           SetExtents->FileId.Unique,
1452                           ntStatus);
1453
1454             try_return( ntStatus = STATUS_UNSUCCESSFUL);
1455         }
1456
1457         AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1458                           TRUE);
1459
1460         //
1461         // Now locate the Object in this volume
1462         //
1463
1464         ullIndex = AFSCreateLowIndex( &SetExtents->FileId);
1465
1466         ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
1467                                        ullIndex,
1468                                        (AFSBTreeEntry **)&pObjectInfo);
1469
1470         if( pObjectInfo != NULL)
1471         {
1472
1473             //
1474             // Reference the node so it won't be torn down
1475             //
1476
1477             lCount = AFSObjectInfoIncrement( pObjectInfo,
1478                                              AFS_OBJECT_REFERENCE_EXTENTS);
1479
1480             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1481                           AFS_TRACE_LEVEL_VERBOSE,
1482                           "AFSProcessSetFileExtents Increment count on object %p Cnt %d\n",
1483                           pObjectInfo,
1484                           lCount);
1485         }
1486
1487         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1488
1489         if( !NT_SUCCESS( ntStatus) ||
1490             pObjectInfo == NULL)
1491         {
1492
1493             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1494                           AFS_TRACE_LEVEL_ERROR,
1495                           "AFSProcessSetFileExtents Set extents for hash %I64X fid %08lX-%08lX-%08lX-%08lX Failed to locate file in volume %p\n",
1496                           ullIndex,
1497                           SetExtents->FileId.Cell,
1498                           SetExtents->FileId.Volume,
1499                           SetExtents->FileId.Vnode,
1500                           SetExtents->FileId.Unique,
1501                           pVolumeCB);
1502
1503             try_return( ntStatus = STATUS_UNSUCCESSFUL);
1504         }
1505
1506         pFcb = pObjectInfo->Fcb;
1507
1508         //
1509         // If we have a result failure then don't bother trying to set the extents
1510         //
1511
1512         if( SetExtents->ResultStatus != STATUS_SUCCESS)
1513         {
1514
1515             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1516                           AFS_TRACE_LEVEL_ERROR,
1517                           "AFSProcessSetFileExtents Set extents failure fid %08lX-%08lX-%08lX-%08lX ResultStatus %08lX\n",
1518                           SetExtents->FileId.Cell,
1519                           SetExtents->FileId.Volume,
1520                           SetExtents->FileId.Vnode,
1521                           SetExtents->FileId.Unique,
1522                           SetExtents->ResultStatus);
1523
1524             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1525                           AFS_TRACE_LEVEL_VERBOSE,
1526                           "AFSProcessSetFileExtents Acquiring Fcb extents lock %p EXCL %08lX\n",
1527                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1528                           PsGetCurrentThread());
1529
1530             AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource,
1531                             TRUE);
1532
1533             pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_CANCELLED;
1534
1535             KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete,
1536                         0,
1537                         FALSE);
1538
1539             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1540                           AFS_TRACE_LEVEL_VERBOSE,
1541                           "AFSProcessSetFileExtents Releasing Fcb extent lock %p EXCL %08lX\n",
1542                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1543                           PsGetCurrentThread());
1544
1545             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
1546
1547             try_return( ntStatus);
1548         }
1549
1550         ntStatus = AFSProcessExtentsResult ( pFcb,
1551                                              SetExtents->ExtentCount,
1552                                              SetExtents->FileExtents );
1553
1554 try_exit:
1555
1556         if( pObjectInfo != NULL)
1557         {
1558
1559             lCount = AFSObjectInfoDecrement( pObjectInfo,
1560                                              AFS_OBJECT_REFERENCE_EXTENTS);
1561
1562             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1563                           AFS_TRACE_LEVEL_VERBOSE,
1564                           "AFSProcessSetFileExtents Decrement count on object %p Cnt %d\n",
1565                           pObjectInfo,
1566                           lCount);
1567         }
1568
1569         if ( pVolumeCB)
1570         {
1571
1572             lCount = AFSVolumeDecrement( pVolumeCB,
1573                                          AFS_VOLUME_REFERENCE_EXTENTS);
1574
1575             AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING,
1576                           AFS_TRACE_LEVEL_VERBOSE,
1577                           "AFSProcessSetFileExtents Decrement count on volume %p Cnt %d\n",
1578                           pVolumeCB,
1579                           lCount);
1580         }
1581     }
1582
1583     return ntStatus;
1584 }
1585
1586 //
1587 // Helper fuctions for Usermode initiation of release of extents
1588 //
1589 NTSTATUS
1590 AFSReleaseSpecifiedExtents( IN  AFSReleaseFileExtentsCB *Extents,
1591                             IN  AFSFcb *Fcb,
1592                             OUT AFSFileExtentCB *FileExtents,
1593                             IN  ULONG BufferSize,
1594                             OUT ULONG *ExtentCount,
1595                             OUT BOOLEAN *DirtyExtents)
1596 {
1597     AFSExtent           *pExtent;
1598     LIST_ENTRY          *le;
1599     ULONG                ulExtentCount = 0;
1600     NTSTATUS             ntStatus = STATUS_SUCCESS;
1601     BOOLEAN              bReleaseAll = FALSE;
1602     LONG                 lCount;
1603
1604     __Enter
1605     {
1606         ASSERT( ExIsResourceAcquiredExclusiveLite( &Fcb->NPFcb->Specific.File.ExtentsResource));
1607
1608         if (BufferSize < (Extents->ExtentCount * sizeof( AFSFileExtentCB)))
1609         {
1610
1611             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1612                           AFS_TRACE_LEVEL_VERBOSE,
1613                           "AFSReleaseSpecifiedExtents Buffer too small\n");
1614
1615             try_return( ntStatus = STATUS_BUFFER_TOO_SMALL);
1616         }
1617
1618         RtlZeroMemory( FileExtents, BufferSize);
1619         *ExtentCount = 0;
1620
1621         *DirtyExtents = FALSE;
1622
1623         //
1624         // iterate until we have dealt with all we were asked for or
1625         // are at the end of the list.  Note that this deals (albeit
1626         // badly) with out of order extents
1627         //
1628
1629         pExtent = AFSExtentForOffset( Fcb,
1630                                       &Extents->FileExtents[0].FileOffset,
1631                                       FALSE);
1632
1633         if (NULL == pExtent)
1634         {
1635             le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1636         }
1637         else
1638         {
1639             le = &pExtent->Lists[AFS_EXTENTS_LIST];
1640         }
1641         ulExtentCount = 0;
1642
1643         if( BooleanFlagOn( Extents->Flags, AFS_RELEASE_EXTENTS_FLAGS_RELEASE_ALL) ||
1644             ( Extents->FileId.Cell   == 0 &&
1645               Extents->FileId.Volume == 0 &&
1646               Extents->FileId.Vnode  == 0 &&
1647               Extents->FileId.Unique == 0))
1648         {
1649
1650             bReleaseAll = TRUE;
1651         }
1652
1653         while( le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST] &&
1654                ulExtentCount < Extents->ExtentCount)
1655
1656         {
1657
1658             pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
1659
1660             if( !bReleaseAll)
1661             {
1662
1663                 if( pExtent->FileOffset.QuadPart < Extents->FileExtents[ulExtentCount].FileOffset.QuadPart)
1664                 {
1665                     //
1666                     // Skip forward through the extent list until we get
1667                     // to the one we want
1668                     //
1669                     le = le->Flink;
1670
1671                     continue;
1672                 }
1673                 else if (pExtent->FileOffset.QuadPart > Extents->FileExtents[ulExtentCount].FileOffset.QuadPart)
1674                 {
1675                     //
1676                     // We don't have the extent asked for so return UNKNOWN
1677                     //
1678
1679                     AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1680                                   AFS_TRACE_LEVEL_VERBOSE,
1681                                   "AFSReleaseSpecifiedExtents Located UNKNOWN extent Offset %I64X Len %08lX\n",
1682                                   Extents->FileExtents[ulExtentCount].FileOffset.QuadPart,
1683                                   Extents->FileExtents[ulExtentCount].Length);
1684
1685                     FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_UNKNOWN;
1686
1687                     FileExtents[*ExtentCount].Length = 0;
1688                     FileExtents[*ExtentCount].CacheOffset.QuadPart = 0;
1689                     FileExtents[*ExtentCount].FileOffset = Extents->FileExtents[ulExtentCount].FileOffset;
1690
1691                     *ExtentCount = (*ExtentCount) + 1;
1692
1693                     ulExtentCount++;
1694
1695                     //
1696                     // Reset where we are looking
1697                     //
1698
1699                     le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1700
1701                     continue;
1702                 }
1703                 else if( pExtent->ActiveCount > 0)
1704                 {
1705
1706                     AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1707                                   AFS_TRACE_LEVEL_VERBOSE,
1708                                   "AFSReleaseSpecifiedExtents Located IN_USE extent Offset %I64X Len %08lX\n",
1709                                   Extents->FileExtents[ulExtentCount].FileOffset.QuadPart,
1710                                   Extents->FileExtents[ulExtentCount].Length);
1711
1712                     FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_IN_USE;
1713
1714                     FileExtents[*ExtentCount].Length = 0;
1715                     FileExtents[*ExtentCount].CacheOffset.QuadPart = 0;
1716                     FileExtents[*ExtentCount].FileOffset = Extents->FileExtents[ulExtentCount].FileOffset;
1717
1718                     *ExtentCount = (*ExtentCount) + 1;
1719
1720                     ulExtentCount++;
1721
1722                     //
1723                     // Reset where we are looking
1724                     //
1725
1726                     le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1727
1728                     continue;
1729                 }
1730             }
1731             else
1732             {
1733
1734                 //
1735                 // If the extent is currently active then skip it
1736                 //
1737
1738                 if( pExtent->ActiveCount > 0)
1739                 {
1740
1741                     le = le->Flink;
1742
1743                     continue;
1744                 }
1745             }
1746
1747             FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_RELEASE;
1748
1749             FileExtents[*ExtentCount].Length = pExtent->Size;
1750             FileExtents[*ExtentCount].DirtyLength = pExtent->Size;
1751             FileExtents[*ExtentCount].DirtyOffset = 0;
1752             FileExtents[*ExtentCount].CacheOffset = pExtent->CacheOffset;
1753             FileExtents[*ExtentCount].FileOffset = pExtent->FileOffset;
1754
1755             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1756                           AFS_TRACE_LEVEL_VERBOSE,
1757                           "AFSReleaseSpecifiedExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
1758                           pExtent,
1759                           Fcb->ObjectInformation->FileId.Cell,
1760                           Fcb->ObjectInformation->FileId.Volume,
1761                           Fcb->ObjectInformation->FileId.Vnode,
1762                           Fcb->ObjectInformation->FileId.Unique,
1763                           FileExtents[*ExtentCount].FileOffset.QuadPart,
1764                           FileExtents[*ExtentCount].Length);
1765
1766             if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
1767             {
1768
1769                 AFSAcquireExcl( &Fcb->NPFcb->Specific.File.DirtyExtentsListLock,
1770                                 TRUE);
1771
1772                 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
1773                 {
1774
1775                     AFSRemoveEntryDirtyList( Fcb,
1776                                              pExtent);
1777
1778                     FileExtents[*ExtentCount].Flags |= AFS_EXTENT_FLAG_DIRTY;
1779
1780                     lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
1781
1782                     *DirtyExtents = TRUE;
1783                 }
1784
1785                 AFSReleaseResource( &Fcb->NPFcb->Specific.File.DirtyExtentsListLock);
1786             }
1787
1788             //
1789             // move forward all three cursors
1790             //
1791             le = le->Flink;
1792             ulExtentCount ++;
1793             *ExtentCount = (*ExtentCount) + 1;
1794
1795             AFSFreeExtent( Fcb,
1796                            pExtent);
1797         }
1798
1799 try_exit:
1800
1801         NOTHING;
1802     }
1803
1804     return ntStatus;
1805 }
1806
1807 AFSFcb*
1808 AFSFindFcbToClean(ULONG IgnoreTime, AFSFcb *LastFcb, BOOLEAN Block)
1809 {
1810
1811     UNREFERENCED_PARAMETER(IgnoreTime);
1812     AFSFcb *pFcb = NULL;
1813     AFSVolumeCB *pVolumeCB = NULL;
1814     AFSDeviceExt *pRDRDeviceExt = NULL;
1815     AFSDeviceExt *pControlDeviceExt = NULL;
1816     BOOLEAN bLocatedEntry = FALSE;
1817     AFSObjectInfoCB *pCurrentObject = NULL;
1818     BOOLEAN bReleaseVolumeListLock = FALSE;
1819     LONG lCount;
1820
1821     pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1822     pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1823
1824     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1825                   AFS_TRACE_LEVEL_VERBOSE,
1826                   "AFSFindFcbToClean Acquiring RDR VolumeListLock lock %p SHARED %08lX\n",
1827                   &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1828                   PsGetCurrentThread());
1829
1830     AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1831                       TRUE);
1832
1833     bReleaseVolumeListLock = TRUE;
1834
1835     pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead;
1836
1837     while( pVolumeCB != NULL)
1838     {
1839
1840         //
1841         // The Volume list may move under our feet.  Lock it.
1842         //
1843
1844         lCount = AFSVolumeIncrement( pVolumeCB,
1845                                      AFS_VOLUME_REFERENCE_EXTENTS);
1846
1847         AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING,
1848                       AFS_TRACE_LEVEL_VERBOSE,
1849                       "AFSFindFcbToClean Increment count on volume %p Cnt %d\n",
1850                       pVolumeCB,
1851                       lCount);
1852
1853         AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1854
1855         bReleaseVolumeListLock = FALSE;
1856
1857         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1858                       AFS_TRACE_LEVEL_VERBOSE,
1859                       "AFSFindFcbToClean Acquiring VolumeRoot ObjectInfoTree lock %p SHARED %08lX\n",
1860                       pVolumeCB->ObjectInfoTree.TreeLock,
1861                       PsGetCurrentThread());
1862
1863         AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1864                           TRUE);
1865
1866         lCount = AFSVolumeDecrement( pVolumeCB,
1867                                      AFS_VOLUME_REFERENCE_EXTENTS);
1868
1869         AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING,
1870                       AFS_TRACE_LEVEL_VERBOSE,
1871                       "AFSFindFcbToClean Decrement count on volume %p Cnt %d\n",
1872                       pVolumeCB,
1873                       lCount);
1874
1875         if( NULL == LastFcb)
1876         {
1877
1878             pCurrentObject = pVolumeCB->ObjectInfoListHead;
1879         }
1880         else
1881         {
1882
1883             pCurrentObject = (AFSObjectInfoCB *)LastFcb->ObjectInformation->ListEntry.fLink;
1884         }
1885
1886         pFcb = NULL;
1887
1888         while( pCurrentObject != NULL)
1889         {
1890
1891             pFcb = (AFSFcb *)pCurrentObject->Fcb;
1892
1893             //
1894             // If the FCB is a candidate we try to lock it (but without waiting - which
1895             // means we are deadlock free
1896             //
1897
1898             if( pFcb != NULL &&
1899                 pFcb->Header.NodeTypeCode == AFS_FILE_FCB)
1900             {
1901
1902                 if( Block)
1903                 {
1904
1905                     AFSLockForExtentsTrim( pFcb);
1906                 }
1907                 else
1908                 {
1909
1910                     if( !AFSLockForExtentsTrimNoWait( pFcb))
1911                     {
1912
1913                         pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1914
1915                         pFcb = NULL;
1916
1917                         continue;
1918                     }
1919                 }
1920
1921                 //
1922                 // Need to be sure there are no current flushes in the queue
1923                 //
1924
1925                 if( pFcb->Specific.File.ExtentCount == 0)
1926                 {
1927
1928                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1929                                   AFS_TRACE_LEVEL_VERBOSE,
1930                                   "AFSFindFcbToClean Releasing Fcb extent lock %p thread %08lX\n",
1931                                   &pFcb->NPFcb->Specific.File.ExtentsResource,
1932                                   PsGetCurrentThread());
1933
1934                     AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
1935
1936                     pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1937
1938                     pFcb = NULL;
1939
1940                     continue;
1941                 }
1942
1943                 if( pFcb->Specific.File.QueuedFlushCount > 0)
1944                 {
1945
1946                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1947                                   AFS_TRACE_LEVEL_VERBOSE,
1948                                   "AFSFindFcbToClean Releasing Fcb extent lock %p thread %08lX\n",
1949                                   &pFcb->NPFcb->Specific.File.ExtentsResource,
1950                                   PsGetCurrentThread());
1951
1952                     AFSReleaseResource(&pFcb->NPFcb->Specific.File.ExtentsResource);
1953
1954                     if( Block)
1955                     {
1956                         AFSWaitOnQueuedFlushes( pFcb);
1957                     }
1958                     else
1959                     {
1960
1961                         pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1962                     }
1963
1964                     pFcb = NULL;
1965
1966                     continue;
1967                 }
1968
1969                 if( pFcb->OpenHandleCount > 0)
1970                 {
1971
1972                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1973                                   AFS_TRACE_LEVEL_VERBOSE,
1974                                   "AFSFindFcbToClean Releasing Fcb extent lock %p thread %08lX\n",
1975                                   &pFcb->NPFcb->Specific.File.ExtentsResource,
1976                                   PsGetCurrentThread());
1977
1978                     AFSReleaseResource(&pFcb->NPFcb->Specific.File.ExtentsResource);
1979
1980                     pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1981
1982                     pFcb = NULL;
1983
1984                     continue;
1985                 }
1986
1987                 //
1988                 // A hit a very palpable hit.  Pin it
1989                 //
1990
1991                 lCount = AFSObjectInfoIncrement( pFcb->ObjectInformation,
1992                                                  AFS_OBJECT_REFERENCE_EXTENTS);
1993
1994                 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1995                               AFS_TRACE_LEVEL_VERBOSE,
1996                               "AFSFindFcbToClean Increment count on Fcb %p object %pCnt %d\n",
1997                               pFcb,
1998                               pFcb->ObjectInformation,
1999                               lCount);
2000
2001                 bLocatedEntry = TRUE;
2002
2003                 break;
2004             }
2005
2006             pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
2007
2008             pFcb = NULL;
2009         }
2010
2011         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
2012
2013         if( bLocatedEntry)
2014         {
2015             break;
2016         }
2017
2018         AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
2019                           TRUE);
2020
2021         bReleaseVolumeListLock = TRUE;
2022
2023         pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
2024     }
2025
2026     if( bReleaseVolumeListLock)
2027     {
2028
2029         AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
2030     }
2031
2032     return pFcb;
2033 }
2034
2035 NTSTATUS
2036 AFSProcessExtentFailure( PIRP Irp)
2037 {
2038     AFSExtentFailureCB                *pFailureCB = NULL;
2039     NTSTATUS                           ntStatus = STATUS_SUCCESS;
2040     AFSDeviceExt                      *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension;
2041     PIO_STACK_LOCATION                 pIrpSp = IoGetCurrentIrpStackLocation( Irp);
2042     AFSVolumeCB                       *pVolumeCB = NULL;
2043     ULONGLONG                          ullIndex = 0;
2044     AFSObjectInfoCB                   *pObjectInfo = NULL;
2045     LONG                               lCount;
2046
2047     __Enter
2048     {
2049         if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSExtentFailureCB))
2050         {
2051
2052             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2053                           AFS_TRACE_LEVEL_ERROR,
2054                           "AFSProcessExtentFailure Input buffer too small\n");
2055
2056             try_return( ntStatus = STATUS_INVALID_PARAMETER);
2057         }
2058
2059         pFailureCB = (AFSExtentFailureCB *)Irp->AssociatedIrp.SystemBuffer;
2060
2061         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2062                       AFS_TRACE_LEVEL_ERROR,
2063                       "AFSProcessExtentFailure Service Reports Failure fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
2064                       pFailureCB->FileId.Cell,
2065                       pFailureCB->FileId.Volume,
2066                       pFailureCB->FileId.Vnode,
2067                       pFailureCB->FileId.Unique,
2068                       pFailureCB->FailureStatus);
2069
2070         AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
2071
2072         //
2073         // Locate the volume node
2074         //
2075
2076         ullIndex = AFSCreateHighIndex( &pFailureCB->FileId);
2077
2078         ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
2079                                        ullIndex,
2080                                        (AFSBTreeEntry **)&pVolumeCB);
2081
2082         if( pVolumeCB != NULL)
2083         {
2084
2085             lCount = AFSVolumeIncrement( pVolumeCB,
2086                                          AFS_VOLUME_REFERENCE_EXTENTS);
2087
2088             AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING,
2089                           AFS_TRACE_LEVEL_VERBOSE,
2090                           "AFSProcessExtentFailure Increment count on volume %p Cnt %d\n",
2091                           pVolumeCB,
2092                           lCount);
2093         }
2094
2095         AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
2096
2097         if( !NT_SUCCESS( ntStatus) ||
2098             pVolumeCB == NULL)
2099         {
2100
2101             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2102                           AFS_TRACE_LEVEL_ERROR,
2103                           "AFSProcessExtentFailure Invalid volume index %I64X status %08X\n",
2104                           ullIndex, ntStatus);
2105
2106             try_return( ntStatus = STATUS_UNSUCCESSFUL);
2107         }
2108
2109         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2110                       AFS_TRACE_LEVEL_VERBOSE,
2111                       "AFSProcessExtentFailure Acquiring VolumeRoot FileIDTree.TreeLock lock %p SHARED %08lX\n",
2112                       pVolumeCB->ObjectInfoTree.TreeLock,
2113                       PsGetCurrentThread());
2114
2115         AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
2116                           TRUE);
2117
2118         //
2119         // Now locate the Object in this volume
2120         //
2121
2122         ullIndex = AFSCreateLowIndex( &pFailureCB->FileId);
2123
2124         ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
2125                                        ullIndex,
2126                                        (AFSBTreeEntry **)&pObjectInfo);
2127
2128         if( pObjectInfo != NULL &&
2129             pObjectInfo->Fcb != NULL)
2130         {
2131
2132             //
2133             // Reference the node so it won't be torn down
2134             //
2135
2136             lCount = AFSObjectInfoIncrement( pObjectInfo,
2137                                              AFS_OBJECT_REFERENCE_EXTENTS);
2138
2139             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2140                           AFS_TRACE_LEVEL_VERBOSE,
2141                           "AFSProcessExtentFailure Increment count on object %p Cnt %d\n",
2142                           pObjectInfo,
2143                           lCount);
2144         }
2145
2146         AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
2147
2148         if( !NT_SUCCESS( ntStatus) ||
2149             pObjectInfo == NULL ||
2150             pObjectInfo->Fcb == NULL)
2151         {
2152
2153             if( pObjectInfo == NULL)
2154             {
2155                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2156                               AFS_TRACE_LEVEL_ERROR,
2157                               "AFSProcessExtentFailure Invalid file index %I64X\n",
2158                               ullIndex);
2159             }
2160             else
2161             {
2162                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2163                               AFS_TRACE_LEVEL_ERROR,
2164                               "AFSProcessExtentFailure Fcb dealocated for %I64X\n",
2165                               ullIndex);
2166             }
2167
2168             try_return( ntStatus = STATUS_UNSUCCESSFUL);
2169         }
2170
2171         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2172                       AFS_TRACE_LEVEL_VERBOSE,
2173                       "AFSProcessExtentFailure Acquiring Fcb extent lock %p EXCL %08lX\n",
2174                       &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
2175                       PsGetCurrentThread());
2176
2177         AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
2178                         TRUE);
2179
2180         pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = pFailureCB->FailureStatus;
2181
2182         RtlCopyMemory( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2183                        &pFailureCB->AuthGroup,
2184                        sizeof( GUID));
2185
2186         KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
2187                     0,
2188                     FALSE);
2189
2190         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2191                       AFS_TRACE_LEVEL_VERBOSE,
2192                       "AFSProcessExtentFailure Releasing Fcb extent lock %p EXCL %08lX\n",
2193                       &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
2194                       PsGetCurrentThread());
2195
2196         AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource);
2197
2198         lCount = AFSObjectInfoDecrement( pObjectInfo,
2199                                          AFS_OBJECT_REFERENCE_EXTENTS);
2200
2201         AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2202                       AFS_TRACE_LEVEL_VERBOSE,
2203                       "AFSProcessExtentFailure Decrement count on object %p Cnt %d\n",
2204                       pObjectInfo,
2205                       lCount);
2206
2207 try_exit:
2208
2209         if ( pVolumeCB)
2210         {
2211
2212             lCount = AFSVolumeDecrement( pVolumeCB,
2213                                          AFS_VOLUME_REFERENCE_EXTENTS);
2214
2215             AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING,
2216                           AFS_TRACE_LEVEL_VERBOSE,
2217                           "AFSProcessExtentFailure Decrement count on volume %p Cnt %d\n",
2218                           pVolumeCB,
2219                           lCount);
2220         }
2221     }
2222
2223     return ntStatus;
2224 }
2225
2226 NTSTATUS
2227 AFSProcessReleaseFileExtents( IN PIRP Irp)
2228 {
2229     NTSTATUS                           ntStatus = STATUS_SUCCESS;
2230     PIO_STACK_LOCATION                 pIrpSp = IoGetCurrentIrpStackLocation( Irp);
2231     AFSFcb                            *pFcb = NULL;
2232     AFSVolumeCB                       *pVolumeCB = NULL;
2233     AFSDeviceExt                      *pDevExt;
2234     AFSReleaseFileExtentsCB           *pExtents;
2235     AFSReleaseFileExtentsResultCB     *pResult = NULL;
2236     AFSReleaseFileExtentsResultFileCB *pFile = NULL;
2237     ULONG                              ulSz = 0;
2238     ULONGLONG                          ullIndex = 0;
2239     AFSObjectInfoCB                   *pObjectInfo = NULL;
2240     BOOLEAN                            bLocked = FALSE;
2241     BOOLEAN                            bDirtyExtents = FALSE;
2242     GUID                               stAuthGroup;
2243     LONG                               lCount;
2244
2245     __Enter
2246     {
2247
2248         pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension;
2249
2250         pExtents = (AFSReleaseFileExtentsCB*) Irp->AssociatedIrp.SystemBuffer;
2251
2252         if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2253                                             sizeof( AFSReleaseFileExtentsCB))
2254         {
2255
2256             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2257                           AFS_TRACE_LEVEL_ERROR,
2258                           "AFSProcessReleaseFileExtents INPUT Buffer too small\n");
2259
2260             try_return( ntStatus = STATUS_INVALID_PARAMETER );
2261         }
2262
2263         if ( pIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
2264                                         sizeof(AFSReleaseFileExtentsResultCB))
2265         {
2266
2267             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2268                           AFS_TRACE_LEVEL_ERROR,
2269                           "AFSProcessReleaseFileExtents OUTPUT Buffer too small [1]\n");
2270
2271             //
2272             // Must have space for one extent in one file
2273             //
2274
2275             try_return( ntStatus = STATUS_BUFFER_TOO_SMALL);
2276         }
2277
2278         if (pExtents->ExtentCount == 0)
2279         {
2280
2281             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2282                           AFS_TRACE_LEVEL_ERROR,
2283                           "AFSProcessReleaseFileExtents Extent count zero\n");
2284
2285             try_return( ntStatus = STATUS_INVALID_PARAMETER);
2286         }
2287
2288         if (pExtents->FileId.Cell   != 0 ||
2289             pExtents->FileId.Volume != 0 ||
2290             pExtents->FileId.Vnode  != 0 ||
2291             pExtents->FileId.Unique != 0)
2292         {
2293
2294             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2295                           AFS_TRACE_LEVEL_VERBOSE,
2296                           "AFSProcessReleaseFileExtents Processing FID %08lX:%08lX:%08lX:%08lX\n",
2297                           pExtents->FileId.Cell,
2298                           pExtents->FileId.Volume,
2299                           pExtents->FileId.Vnode,
2300                           pExtents->FileId.Unique);
2301
2302             if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2303                             ( FIELD_OFFSET( AFSReleaseFileExtentsCB, ExtentCount) + sizeof(ULONG)) ||
2304                 pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2305                             ( FIELD_OFFSET( AFSReleaseFileExtentsCB, ExtentCount) + sizeof(ULONG) +
2306                                                             sizeof (AFSFileExtentCB) * pExtents->ExtentCount))
2307             {
2308
2309                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2310                               AFS_TRACE_LEVEL_ERROR,
2311                               "AFSProcessReleaseFileExtents Buffer too small for FID %08lX:%08lx:%08lX:%08lX\n",
2312                               pExtents->FileId.Cell,
2313                               pExtents->FileId.Volume,
2314                               pExtents->FileId.Vnode,
2315                               pExtents->FileId.Unique);
2316
2317                 try_return( ntStatus = STATUS_INVALID_PARAMETER );
2318             }
2319
2320             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2321                           AFS_TRACE_LEVEL_VERBOSE,
2322                           "AFSProcessReleaseFileExtents Acquiring RDR VolumeTreeLock lock %p SHARED %08lX\n",
2323                           &pDevExt->Specific.RDR.VolumeTreeLock,
2324                           PsGetCurrentThread());
2325
2326             AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
2327
2328             //
2329             // Locate the volume node
2330             //
2331
2332             ullIndex = AFSCreateHighIndex( &pExtents->FileId);
2333
2334             ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
2335                                            ullIndex,
2336                                            (AFSBTreeEntry **)&pVolumeCB);
2337
2338             if( pVolumeCB != NULL)
2339             {
2340
2341                 lCount = AFSVolumeIncrement( pVolumeCB,
2342                                              AFS_VOLUME_REFERENCE_EXTENTS);
2343
2344                 AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING,
2345                               AFS_TRACE_LEVEL_VERBOSE,
2346                               "AFSProcessReleaseFileExtents Increment count on volume %p Cnt %d\n",
2347                               pVolumeCB,
2348                               lCount);
2349             }
2350
2351             AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
2352
2353             if( !NT_SUCCESS( ntStatus) ||
2354                 pVolumeCB == NULL)
2355             {
2356
2357                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2358                               AFS_TRACE_LEVEL_ERROR,
2359                               "AFSProcessReleaseFileExtents Invalid volume index %I64X status %08X\n",
2360                               ullIndex, ntStatus);
2361
2362                 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2363             }
2364
2365             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2366                           AFS_TRACE_LEVEL_VERBOSE,
2367                           "AFSProcessReleaseFileExtents Acquiring VolumeRoot FileIDTree.TreeLock lock %p SHARED %08lX\n",
2368                           pVolumeCB->ObjectInfoTree.TreeLock,
2369                           PsGetCurrentThread());
2370
2371             AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
2372                               TRUE);
2373
2374             //
2375             // Now locate the Object in this volume
2376             //
2377
2378             ullIndex = AFSCreateLowIndex( &pExtents->FileId);
2379
2380             ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
2381                                            ullIndex,
2382                                            (AFSBTreeEntry **)&pObjectInfo);
2383
2384             if( pObjectInfo != NULL)
2385             {
2386
2387                 //
2388                 // Reference the node so it won't be torn down
2389                 //
2390
2391                 lCount = AFSObjectInfoIncrement( pObjectInfo,
2392                                                  AFS_OBJECT_REFERENCE_EXTENTS);
2393
2394                 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2395                               AFS_TRACE_LEVEL_VERBOSE,
2396                               "AFSProcessReleaseFileExtents Increment count on object %p Cnt %d\n",
2397                               pObjectInfo,
2398                               lCount);
2399             }
2400
2401             AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
2402
2403             if( !NT_SUCCESS( ntStatus) ||
2404                 pObjectInfo == NULL)
2405             {
2406
2407                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2408                               AFS_TRACE_LEVEL_ERROR,
2409                               "AFSProcessReleaseFileExtents Invalid file index %I64X\n",
2410                               ullIndex);
2411
2412                 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2413             }
2414
2415             pFcb = pObjectInfo->Fcb;
2416
2417             if( pFcb == NULL)
2418             {
2419
2420                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2421                               AFS_TRACE_LEVEL_ERROR,
2422                               "AFSProcessReleaseFileExtents Fcb not initialied (NO EXTENTS) for FID %08lX:%08lx:%08lX:%08lX\n",
2423                               pExtents->FileId.Cell,
2424                               pExtents->FileId.Volume,
2425                               pExtents->FileId.Vnode,
2426                               pExtents->FileId.Unique);
2427
2428                 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2429             }
2430
2431             AFSLockForExtentsTrim( pFcb );
2432
2433             bLocked = TRUE;
2434         }
2435         else
2436         {
2437
2438             //
2439             // Locate an Fcb to trim down
2440             //
2441
2442             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2443                           AFS_TRACE_LEVEL_VERBOSE,
2444                           "AFSProcessReleaseFileExtents Searching for a Fcb to Trim Down\n");
2445
2446             pFcb = AFSFindFcbToClean( 0, NULL, FALSE);
2447
2448             if( pFcb == NULL)
2449             {
2450
2451                 pFcb = AFSFindFcbToClean( 0, NULL, TRUE);
2452             }
2453
2454             if( pFcb == NULL)
2455             {
2456
2457                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2458                               AFS_TRACE_LEVEL_ERROR,
2459                               "AFSProcessReleaseFileExtents Failed to locate Fcb for release ...\n");
2460
2461                 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2462             }
2463
2464             pObjectInfo = pFcb->ObjectInformation;
2465
2466             bLocked = TRUE;
2467         }
2468
2469         //
2470         // Allocate a scratch buffer to move in the extent information
2471         //
2472
2473         ulSz = (pExtents->ExtentCount-1) * sizeof(AFSFileExtentCB);
2474         ulSz += sizeof(AFSReleaseFileExtentsResultCB);
2475
2476         if (ulSz > pIrpSp->Parameters.DeviceIoControl.OutputBufferLength)
2477         {
2478             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2479                           AFS_TRACE_LEVEL_ERROR,
2480                           "AFSProcessReleaseFileExtents OUTPUT Buffer too small [2]\n");
2481
2482             try_return( ntStatus = STATUS_BUFFER_TOO_SMALL );
2483         }
2484
2485         pResult = (AFSReleaseFileExtentsResultCB*) AFSExAllocatePoolWithTag( PagedPool,
2486                                                                              ulSz,
2487                                                                              AFS_EXTENTS_RESULT_TAG);
2488         if (NULL == pResult)
2489         {
2490
2491             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2492                           AFS_TRACE_LEVEL_ERROR,
2493                           "AFSProcessReleaseFileExtents Failed to allocate result block\n");
2494
2495             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2496         }
2497
2498         //
2499         // Set up the header (for an array of one)
2500         //
2501         pResult->FileCount = 1;
2502         pResult->Flags = AFS_EXTENT_FLAG_RELEASE;
2503         ulSz -= FIELD_OFFSET(AFSReleaseFileExtentsResultCB, Files);
2504
2505         //
2506         // Setup the first (and only) file
2507         //
2508         pFile = pResult->Files;
2509         pFile->FileId = pObjectInfo->FileId;
2510         pFile->Flags = AFS_EXTENT_FLAG_RELEASE;
2511
2512         //
2513         // Stash away the auth group
2514         //
2515
2516         RtlZeroMemory( &stAuthGroup,
2517                        sizeof( GUID));
2518
2519         ntStatus = AFSRetrieveValidAuthGroup( pFcb,
2520                                               NULL,
2521                                               TRUE,
2522                                               &stAuthGroup);
2523
2524         if( !NT_SUCCESS( ntStatus))
2525         {
2526             try_return( ntStatus);
2527         }
2528
2529         RtlCopyMemory( &pFile->AuthGroup,
2530                        &stAuthGroup,
2531                        sizeof( GUID));
2532
2533         //
2534         // Update the metadata for this call
2535         //
2536
2537         pFile->AllocationSize = pFcb->ObjectInformation->EndOfFile;
2538         pFile->CreateTime = pFcb->ObjectInformation->CreationTime;
2539         pFile->ChangeTime = pFcb->ObjectInformation->ChangeTime;
2540         pFile->LastAccessTime = pFcb->ObjectInformation->LastAccessTime;
2541         pFile->LastWriteTime = pFcb->ObjectInformation->LastWriteTime;
2542
2543         ulSz -= FIELD_OFFSET(AFSReleaseFileExtentsResultFileCB, FileExtents);
2544
2545         ntStatus = AFSReleaseSpecifiedExtents( pExtents,
2546                                                pFcb,
2547                                                pFile->FileExtents,
2548                                                ulSz,
2549                                                &pFile->ExtentCount,
2550                                                &bDirtyExtents);
2551
2552         if (!NT_SUCCESS(ntStatus))
2553         {
2554
2555             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2556                           AFS_TRACE_LEVEL_ERROR,
2557                           "AFSProcessReleaseFileExtents Failed to release extents Status %08lX\n",
2558                           ntStatus);
2559
2560             try_return( ntStatus );
2561         }
2562
2563         if( pExtents->ExtentCount == 0)
2564         {
2565
2566             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2567                           AFS_TRACE_LEVEL_WARNING,
2568                           "AFSProcessReleaseFileExtents Failed to release ANY extents\n");
2569         }
2570
2571         ulSz = sizeof(AFSReleaseFileExtentsResultCB);
2572
2573         if( pExtents->ExtentCount > 0)
2574         {
2575             ulSz += ((pExtents->ExtentCount-1) * sizeof(AFSFileExtentCB));
2576         }
2577
2578         RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer,
2579                        pResult,
2580                        ulSz);
2581
2582 try_exit:
2583
2584         if( bLocked)
2585         {
2586
2587             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2588                           AFS_TRACE_LEVEL_VERBOSE,
2589                           "AFSProcessReleaseFileExtents Releasing Fcb extent lock %p thread %08lX\n",
2590                           &pFcb->NPFcb->Specific.File.ExtentsResource,
2591                           PsGetCurrentThread());
2592
2593             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
2594         }
2595
2596         if( NULL != pResult &&
2597             Irp->AssociatedIrp.SystemBuffer != pResult)
2598         {
2599
2600             AFSExFreePoolWithTag(pResult, AFS_EXTENTS_RESULT_TAG);
2601         }
2602
2603         if (NT_SUCCESS(ntStatus))
2604         {
2605             Irp->IoStatus.Information = ulSz;
2606         }
2607         else
2608         {
2609             Irp->IoStatus.Information = 0;
2610         }
2611
2612         Irp->IoStatus.Status = ntStatus;
2613
2614         if( pObjectInfo != NULL)
2615         {
2616
2617             lCount = AFSObjectInfoDecrement( pObjectInfo,
2618                                              AFS_OBJECT_REFERENCE_EXTENTS);
2619
2620             AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2621                           AFS_TRACE_LEVEL_VERBOSE,
2622                           "AFSProcessReleaseFileExtents Decrement count on object %p Cnt %d\n",
2623                           pObjectInfo,
2624                           lCount);
2625         }
2626
2627         if ( pVolumeCB)
2628         {
2629
2630             lCount = AFSVolumeDecrement( pVolumeCB,
2631                                          AFS_VOLUME_REFERENCE_EXTENTS);
2632
2633             AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING,
2634                           AFS_TRACE_LEVEL_VERBOSE,
2635                           "AFSProcessReleaseFileExtents Decrement count on volume %p Cnt %d\n",
2636                           pVolumeCB,
2637                           lCount);
2638
2639         }
2640     }
2641
2642     return ntStatus;
2643 }
2644
2645 NTSTATUS
2646 AFSWaitForExtentMapping( AFSFcb *Fcb,
2647                          AFSCcb *Ccb)
2648 {
2649     NTSTATUS ntStatus = STATUS_SUCCESS;
2650     LARGE_INTEGER liTimeOut;
2651     ULONGLONG            ullProcessId = (ULONGLONG)PsGetCurrentProcessId();
2652
2653     __Enter
2654     {
2655
2656         ASSERT( !ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
2657
2658         if (!NT_SUCCESS( Fcb->NPFcb->Specific.File.ExtentsRequestStatus))
2659         {
2660
2661             //
2662             // If this isn't the same authgroup which caused the failure
2663             // then try to request them again
2664             //
2665
2666             if( RtlCompareMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2667                                   &Ccb->AuthGroup,
2668                                   sizeof( GUID)) == sizeof( GUID))
2669             {
2670
2671                 ntStatus = Fcb->NPFcb->Specific.File.ExtentsRequestStatus;
2672
2673                 Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
2674
2675                 RtlZeroMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2676                                sizeof( GUID));
2677
2678                 try_return( ntStatus);
2679             }
2680         }
2681
2682         liTimeOut.QuadPart = -(1 * AFS_ONE_SECOND);
2683
2684         ntStatus = KeWaitForSingleObject( &Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
2685                                           Executive,
2686                                           KernelMode,
2687                                           FALSE,
2688                                           &liTimeOut);
2689
2690         if (!NT_SUCCESS( Fcb->NPFcb->Specific.File.ExtentsRequestStatus))
2691         {
2692
2693             //
2694             // If this isn't the same authgroup which caused the failure
2695             // or the System Process,
2696             // then try to request the extents again
2697             //
2698
2699             if( RtlCompareMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2700                                   &Ccb->AuthGroup,
2701                                   sizeof( GUID)) == sizeof( GUID) ||
2702                 ullProcessId == (ULONGLONG)AFSSysProcess)
2703             {
2704
2705                 ntStatus = Fcb->NPFcb->Specific.File.ExtentsRequestStatus;
2706
2707                 Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
2708
2709                 RtlZeroMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2710                                sizeof( GUID));
2711
2712                 try_return( ntStatus);
2713             }
2714         }
2715
2716         if( ntStatus == STATUS_TIMEOUT)
2717         {
2718
2719             ntStatus = STATUS_SUCCESS;
2720         }
2721
2722 try_exit:
2723
2724         NOTHING;
2725     }
2726
2727     return ntStatus;
2728 }
2729
2730 NTSTATUS
2731 AFSFlushExtents( IN AFSFcb *Fcb,
2732                  IN GUID *AuthGroup)
2733 {
2734     AFSNonPagedFcb      *pNPFcb = Fcb->NPFcb;
2735     AFSExtent           *pExtent, *pNextExtent;
2736     AFSReleaseExtentsCB *pRelease = NULL;
2737     ULONG                count = 0;
2738     ULONG                initialDirtyCount = 0;
2739     BOOLEAN              bExtentsLocked = FALSE;
2740     ULONG                total = 0;
2741     ULONG                sz = 0;
2742     NTSTATUS             ntStatus = STATUS_SUCCESS;
2743     LARGE_INTEGER        liLastFlush;
2744     GUID                *pAuthGroup = AuthGroup;
2745     GUID                 stAuthGroup;
2746     LONG                 lCount;
2747
2748     ASSERT( Fcb->Header.NodeTypeCode == AFS_FILE_FCB);
2749
2750     //
2751     // Save, then reset the flush time
2752     //
2753
2754     liLastFlush = Fcb->Specific.File.LastServerFlush;
2755
2756     KeQueryTickCount( &Fcb->Specific.File.LastServerFlush);
2757
2758     __Enter
2759     {
2760
2761         lCount = InterlockedIncrement( &Fcb->Specific.File.QueuedFlushCount);
2762
2763         if( pAuthGroup == NULL ||
2764             RtlCompareMemory( pAuthGroup,
2765                               &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2766                               sizeof( GUID)) == sizeof( GUID))
2767         {
2768
2769             RtlZeroMemory( &stAuthGroup,
2770                            sizeof( GUID));
2771
2772             ntStatus = AFSRetrieveValidAuthGroup( Fcb,
2773                                                   NULL,
2774                                                   TRUE,
2775                                                   &stAuthGroup);
2776
2777             if( !NT_SUCCESS( ntStatus))
2778             {
2779                 try_return( ntStatus);
2780             }
2781
2782             pAuthGroup = &stAuthGroup;
2783         }
2784
2785         //
2786         // Lock extents while we count and set up the array to send to
2787         // the service
2788         //
2789
2790         AFSLockForExtentsTrim( Fcb);
2791
2792         bExtentsLocked = TRUE;
2793
2794         //
2795         // Clear our queued flush event
2796         //
2797
2798         KeClearEvent( &Fcb->NPFcb->Specific.File.QueuedFlushEvent);
2799
2800         //
2801         // Look for a start in the list to flush entries
2802         //
2803
2804         total = count;
2805
2806         sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
2807
2808         pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
2809                                                                     sz,
2810                                                                     AFS_EXTENT_RELEASE_TAG);
2811         if( NULL == pRelease)
2812         {
2813
2814             try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2815         }
2816
2817         initialDirtyCount = Fcb->Specific.File.ExtentsDirtyCount;
2818
2819         while( Fcb->Specific.File.ExtentsDirtyCount > 0)
2820         {
2821
2822             pRelease->Flags = AFS_EXTENT_FLAG_DIRTY;
2823
2824             if( BooleanFlagOn( Fcb->Flags, AFS_FCB_FILE_CLOSED))
2825             {
2826
2827                 pRelease->Flags |= AFS_EXTENT_FLAG_FLUSH;
2828             }
2829
2830             //
2831             // Update the metadata for this call
2832             //
2833
2834             pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
2835             pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
2836             pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
2837             pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
2838             pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
2839
2840             count = 0;
2841
2842             AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
2843                             TRUE);
2844
2845             pExtent = (AFSExtent *)pNPFcb->Specific.File.DirtyListHead;
2846
2847             while( count < AFS_MAXIMUM_EXTENT_RELEASE_COUNT)
2848             {
2849
2850                 if ( pExtent == NULL)
2851                 {
2852
2853                     break;
2854                 }
2855
2856                 pNextExtent = (AFSExtent *)pExtent->DirtyList.fLink;
2857
2858                 if ( pExtent->ActiveCount > 0)
2859                 {
2860                     pExtent = pNextExtent;
2861                     continue;
2862                 }
2863
2864                 AFSRemoveEntryDirtyList( Fcb, pExtent);
2865
2866                 pExtent->DirtyList.fLink = NULL;
2867                 pExtent->DirtyList.bLink = NULL;
2868
2869                 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
2870
2871                 //
2872                 // Clear the flag in advance of the write. If we do
2873                 // things this was we know that the clear is
2874                 // pessimistic (any write which happens from now on
2875                 // will set the flag dirty again).
2876                 //
2877
2878                 pExtent->Flags &= ~AFS_EXTENT_DIRTY;
2879
2880                 pRelease->FileExtents[count].Flags = AFS_EXTENT_FLAG_DIRTY;
2881
2882                 pRelease->FileExtents[count].Length = pExtent->Size;
2883                 pRelease->FileExtents[count].DirtyLength = pExtent->Size;
2884                 pRelease->FileExtents[count].DirtyOffset = 0;
2885                 pRelease->FileExtents[count].CacheOffset = pExtent->CacheOffset;
2886                 pRelease->FileExtents[count].FileOffset = pExtent->FileOffset;
2887
2888 #if GEN_MD5
2889                 RtlCopyMemory( pRelease->FileExtents[count].MD5,
2890                                pExtent->MD5,
2891                                sizeof(pExtent->MD5));
2892
2893                 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_MD5_SET;
2894 #endif
2895
2896                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2897                               AFS_TRACE_LEVEL_VERBOSE,
2898                               "AFSFlushExtents Releasing DIRTY extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
2899                               pExtent,
2900                               Fcb->ObjectInformation->FileId.Cell,
2901                               Fcb->ObjectInformation->FileId.Volume,
2902                               Fcb->ObjectInformation->FileId.Vnode,
2903                               Fcb->ObjectInformation->FileId.Unique,
2904                               pExtent->FileOffset.QuadPart,
2905                               pExtent->Size);
2906
2907                 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_RELEASE;
2908
2909                 AFSFreeExtent( Fcb,
2910                                pExtent);
2911
2912                 count ++;
2913
2914                 pExtent = pNextExtent;
2915             }
2916
2917             AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
2918
2919             //
2920             // If we are done then get out
2921             //
2922
2923             if( count == 0)
2924             {
2925
2926                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2927                               AFS_TRACE_LEVEL_VERBOSE,
2928                               "AFSFlushExtents No more dirty extents found\n");
2929
2930                 break;
2931             }
2932
2933             //
2934             // Fire off the request synchronously
2935             //
2936
2937             sz = sizeof( AFSReleaseExtentsCB ) + (count * sizeof ( AFSFileExtentCB ));
2938
2939             pRelease->ExtentCount = count;
2940
2941             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2942                           AFS_TRACE_LEVEL_VERBOSE,
2943                           "AFSFlushExtents Releasing(1) Fcb extents lock %p SHARED %08lX\n",
2944                           &pNPFcb->Specific.File.ExtentsResource,
2945                           PsGetCurrentThread());
2946
2947             AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource);
2948             bExtentsLocked = FALSE;
2949
2950             KeSetEvent( &pNPFcb->Specific.File.FlushEvent,
2951                         0,
2952                         FALSE);
2953
2954             ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS,
2955                                           AFS_REQUEST_FLAG_SYNCHRONOUS,
2956                                           pAuthGroup,
2957                                           NULL,
2958                                           &Fcb->ObjectInformation->FileId,
2959                                           pRelease,
2960                                           sz,
2961                                           NULL,
2962                                           NULL);
2963
2964             if( !NT_SUCCESS(ntStatus))
2965             {
2966
2967                 //
2968                 // Regardless of whether or not the AFSProcessRequest() succeeded, the extents
2969                 // were released (if AFS_EXTENT_FLAG_RELEASE was set).  Log the error so it is known.
2970                 //
2971
2972                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2973                               AFS_TRACE_LEVEL_ERROR,
2974                               "AFSFlushExtents AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
2975                               Fcb->ObjectInformation->FileId.Cell,
2976                               Fcb->ObjectInformation->FileId.Volume,
2977                               Fcb->ObjectInformation->FileId.Vnode,
2978                               Fcb->ObjectInformation->FileId.Unique,
2979                               ntStatus);
2980
2981             }
2982
2983             AFSLockForExtentsTrim( Fcb);
2984
2985             bExtentsLocked = TRUE;
2986         }
2987
2988 try_exit:
2989
2990         lCount = InterlockedDecrement( &Fcb->Specific.File.QueuedFlushCount);
2991
2992         ASSERT( lCount >= 0);
2993
2994         if( lCount == 0)
2995         {
2996
2997             KeSetEvent( &pNPFcb->Specific.File.QueuedFlushEvent,
2998                         0,
2999                         FALSE);
3000         }
3001
3002         KeSetEvent( &pNPFcb->Specific.File.FlushEvent,
3003                     0,
3004                     FALSE);
3005
3006         if (bExtentsLocked)
3007         {
3008
3009             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3010                           AFS_TRACE_LEVEL_VERBOSE,
3011                           "AFSFlushExtents Releasing(2) Fcb extents lock %p SHARED %08lX\n",
3012                           &pNPFcb->Specific.File.ExtentsResource,
3013                           PsGetCurrentThread());
3014
3015             AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
3016         }
3017
3018         if (pRelease)
3019         {
3020             AFSExFreePoolWithTag( pRelease, AFS_EXTENT_RELEASE_TAG);
3021         }
3022     }
3023
3024     return ntStatus;
3025 }
3026
3027 NTSTATUS
3028 AFSReleaseExtentsWithFlush( IN AFSFcb *Fcb,
3029                             IN GUID *AuthGroup,
3030                             IN BOOLEAN bReleaseAll)
3031 {
3032     AFSNonPagedFcb      *pNPFcb = Fcb->NPFcb;
3033     AFSExtent           *pExtent;
3034     LIST_ENTRY          *le;
3035     AFSReleaseExtentsCB *pRelease = NULL;
3036     ULONG                count = 0;
3037     BOOLEAN              bExtentsLocked = FALSE;
3038     ULONG                total = 0;
3039     ULONG                sz = 0;
3040     NTSTATUS             ntStatus = STATUS_SUCCESS;
3041     LARGE_INTEGER        liLastFlush;
3042     ULONG                ulRemainingExtentLength = 0;
3043     GUID                *pAuthGroup = AuthGroup;
3044     GUID                 stAuthGroup;
3045     LONG                 lCount;
3046
3047     ASSERT( Fcb->Header.NodeTypeCode == AFS_FILE_FCB);
3048
3049     //
3050     // Save, then reset the flush time
3051     //
3052
3053     liLastFlush = Fcb->Specific.File.LastServerFlush;
3054
3055     KeQueryTickCount( &Fcb->Specific.File.LastServerFlush);
3056
3057     __Enter
3058     {
3059
3060         if( pAuthGroup == NULL ||
3061             RtlCompareMemory( pAuthGroup,
3062                               &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
3063                               sizeof( GUID)) == sizeof( GUID))
3064         {
3065
3066             RtlZeroMemory( &stAuthGroup,
3067                            sizeof( GUID));
3068
3069             ntStatus = AFSRetrieveValidAuthGroup( Fcb,
3070                                                   NULL,
3071                                                   TRUE,
3072                                                   &stAuthGroup);
3073
3074             if( !NT_SUCCESS( ntStatus))
3075             {
3076                 try_return( ntStatus);
3077             }
3078
3079             pAuthGroup = &stAuthGroup;
3080         }
3081
3082         //
3083         // Look for a start in the list to flush entries
3084         //
3085
3086         total = count;
3087
3088         sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
3089
3090         pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
3091                                                                     sz,
3092                                                                     AFS_EXTENT_RELEASE_TAG);
3093         if( NULL == pRelease)
3094         {
3095
3096             try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
3097         }
3098
3099         if( Fcb->OpenHandleCount > 0 &&
3100             !bReleaseAll)
3101         {
3102
3103             //
3104             // Don't release everything ...
3105             //
3106
3107             ulRemainingExtentLength = 1024;
3108         }
3109
3110         while( Fcb->Specific.File.ExtentLength > (LONG)ulRemainingExtentLength)
3111         {
3112
3113             AFSLockForExtentsTrim( Fcb);
3114
3115             bExtentsLocked = TRUE;
3116
3117             pRelease->Flags = AFS_EXTENT_FLAG_RELEASE;
3118
3119             //
3120             // Update the metadata for this call
3121             //
3122
3123             pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
3124             pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
3125             pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
3126             pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
3127             pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
3128
3129             count = 0;
3130
3131             le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
3132
3133             while( count < AFS_MAXIMUM_EXTENT_RELEASE_COUNT &&
3134                    le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
3135             {
3136
3137                 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
3138
3139                 le = le->Flink;
3140
3141                 if( pExtent->ActiveCount > 0)
3142                 {
3143
3144                     continue;
3145                 }
3146
3147                 pRelease->FileExtents[count].Flags = AFS_EXTENT_FLAG_RELEASE;
3148
3149                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3150                               AFS_TRACE_LEVEL_VERBOSE,
3151                               "AFSReleaseExtentsWithFlush Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
3152                               pExtent,
3153                               Fcb->ObjectInformation->FileId.Cell,
3154                               Fcb->ObjectInformation->FileId.Volume,
3155                               Fcb->ObjectInformation->FileId.Vnode,
3156                               Fcb->ObjectInformation->FileId.Unique,
3157                               pExtent->FileOffset.QuadPart,
3158                               pExtent->Size);
3159
3160                 pRelease->FileExtents[count].Length = pExtent->Size;
3161                 pRelease->FileExtents[count].DirtyLength = pExtent->Size;
3162                 pRelease->FileExtents[count].DirtyOffset = 0;
3163                 pRelease->FileExtents[count].CacheOffset = pExtent->CacheOffset;
3164                 pRelease->FileExtents[count].FileOffset = pExtent->FileOffset;
3165
3166 #if GEN_MD5
3167                 RtlCopyMemory( pRelease->FileExtents[count].MD5,
3168                                pExtent->MD5,
3169                                sizeof(pExtent->MD5));
3170
3171                 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_MD5_SET;
3172 #endif
3173
3174                 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3175                 {
3176
3177                     AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
3178                                     TRUE);
3179
3180                     if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3181                     {
3182
3183                         AFSRemoveEntryDirtyList( Fcb,
3184                                                  pExtent);
3185
3186                         pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_DIRTY;
3187
3188                         lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
3189                     }
3190
3191                     AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
3192                 }
3193
3194                 AFSFreeExtent( Fcb,
3195                                pExtent);
3196
3197                 count ++;
3198             }
3199
3200             //
3201             // If we are done then get out
3202             //
3203
3204             if( count == 0)
3205             {
3206
3207                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3208                               AFS_TRACE_LEVEL_VERBOSE,
3209                               "AFSReleaseExtentsWithFlush No more dirty extents found\n");
3210
3211                 break;
3212             }
3213
3214             //
3215             // Fire off the request synchronously
3216             //
3217
3218             sz = sizeof( AFSReleaseExtentsCB ) + (count * sizeof ( AFSFileExtentCB ));
3219
3220             pRelease->ExtentCount = count;
3221
3222             //
3223             // Drop the extents lock for the duration of the call to
3224             // the network.  We have pinned the extents so, even
3225             // though we might get extents added during this period,
3226             // but none will be removed.  Hence we can carry on from
3227             // le.
3228             //
3229
3230             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3231                           AFS_TRACE_LEVEL_VERBOSE,
3232                           "AFSReleaseExtentsWithFlush Releasing Fcb extents lock %p thread %08lX\n",
3233                           &pNPFcb->Specific.File.ExtentsResource,
3234                           PsGetCurrentThread());
3235
3236             AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource);
3237             bExtentsLocked = FALSE;
3238
3239             ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS,
3240                                           AFS_REQUEST_FLAG_SYNCHRONOUS,
3241                                           pAuthGroup,
3242                                           NULL,
3243                                           &Fcb->ObjectInformation->FileId,
3244                                           pRelease,
3245                                           sz,
3246                                           NULL,
3247                                           NULL);
3248
3249             if( !NT_SUCCESS(ntStatus))
3250             {
3251
3252                 //
3253                 // Regardless of whether or not the AFSProcessRequest() succeeded, the extents
3254                 // were released (if AFS_EXTENT_FLAG_RELEASE was set).  Log the error so it is known.
3255                 //
3256
3257                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3258                               AFS_TRACE_LEVEL_ERROR,
3259                               "AFSReleaseExtentsWithFlush AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
3260                               Fcb->ObjectInformation->FileId.Cell,
3261                               Fcb->ObjectInformation->FileId.Volume,
3262                               Fcb->ObjectInformation->FileId.Vnode,
3263                               Fcb->ObjectInformation->FileId.Unique,
3264                               ntStatus);
3265             }
3266         }
3267
3268 try_exit:
3269
3270         if (bExtentsLocked)
3271         {
3272
3273             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3274                           AFS_TRACE_LEVEL_VERBOSE,
3275                           "AFSReleaseExtentsWithFlush Releasing Fcb extents lock %p thread %08lX\n",
3276                           &pNPFcb->Specific.File.ExtentsResource,
3277                           PsGetCurrentThread());
3278
3279             AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
3280         }
3281
3282         if (pRelease)
3283         {
3284             AFSExFreePoolWithTag( pRelease, AFS_EXTENT_RELEASE_TAG);
3285         }
3286     }
3287
3288     return ntStatus;
3289 }
3290
3291 NTSTATUS
3292 AFSReleaseCleanExtents( IN AFSFcb *Fcb,
3293                         IN GUID *AuthGroup)
3294 {
3295     AFSNonPagedFcb      *pNPFcb = Fcb->NPFcb;
3296     AFSExtent           *pExtent;
3297     LIST_ENTRY          *le;
3298     AFSReleaseExtentsCB *pRelease = NULL;
3299     ULONG                count = 0;
3300     BOOLEAN              bExtentsLocked = FALSE;
3301     ULONG                total = 0;
3302     ULONG                sz = 0;
3303     NTSTATUS             ntStatus = STATUS_SUCCESS;
3304     LARGE_INTEGER        liLastFlush;
3305     ULONG                ulRemainingExtentLength = 0;
3306     GUID                *pAuthGroup = AuthGroup;
3307     GUID                 stAuthGroup;
3308
3309     ASSERT( Fcb->Header.NodeTypeCode == AFS_FILE_FCB);
3310
3311     //
3312     // Save, then reset the flush time
3313     //
3314
3315     liLastFlush = Fcb->Specific.File.LastServerFlush;
3316
3317     KeQueryTickCount( &Fcb->Specific.File.LastServerFlush);
3318
3319     __Enter
3320     {
3321
3322         if( pAuthGroup == NULL ||
3323             RtlCompareMemory( pAuthGroup,
3324                               &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
3325                               sizeof( GUID)) == sizeof( GUID))
3326         {
3327
3328             RtlZeroMemory( &stAuthGroup,
3329                            sizeof( GUID));
3330
3331             ntStatus = AFSRetrieveValidAuthGroup( Fcb,
3332                                                   NULL,
3333                                                   TRUE,
3334                                                   &stAuthGroup);
3335
3336             if( !NT_SUCCESS( ntStatus))
3337             {
3338                 try_return( ntStatus);
3339             }
3340
3341             pAuthGroup = &stAuthGroup;
3342         }
3343
3344         //
3345         // Look for a start in the list to flush entries
3346         //
3347
3348         total = count;
3349
3350         sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
3351
3352         pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
3353                                                                     sz,
3354                                                                     AFS_EXTENT_RELEASE_TAG);
3355         if( NULL == pRelease)
3356         {
3357
3358             try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
3359         }
3360
3361         while( Fcb->Specific.File.ExtentLength > (LONG)ulRemainingExtentLength)
3362         {
3363
3364             AFSLockForExtentsTrim( Fcb);
3365
3366             bExtentsLocked = TRUE;
3367
3368             pRelease->Flags = AFS_EXTENT_FLAG_RELEASE;
3369
3370             //
3371             // Update the metadata for this call
3372             //
3373
3374             pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
3375             pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
3376             pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
3377             pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
3378             pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
3379
3380             count = 0;
3381
3382             le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
3383
3384             while( count < AFS_MAXIMUM_EXTENT_RELEASE_COUNT &&
3385                    le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
3386             {
3387
3388                 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
3389
3390                 le = le->Flink;
3391
3392                 if( pExtent->ActiveCount > 0 ||
3393                     BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3394                 {
3395                     continue;
3396                 }
3397
3398                 pRelease->FileExtents[count].Flags = AFS_EXTENT_FLAG_RELEASE;
3399
3400                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3401                               AFS_TRACE_LEVEL_VERBOSE,
3402                               "AFSReleaseCleanExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
3403                               pExtent,
3404                               Fcb->ObjectInformation->FileId.Cell,
3405                               Fcb->ObjectInformation->FileId.Volume,
3406                               Fcb->ObjectInformation->FileId.Vnode,
3407                               Fcb->ObjectInformation->FileId.Unique,
3408                               pExtent->FileOffset.QuadPart,
3409                               pExtent->Size);
3410
3411                 pRelease->FileExtents[count].Length = pExtent->Size;
3412                 pRelease->FileExtents[count].DirtyLength = pExtent->Size;
3413                 pRelease->FileExtents[count].DirtyOffset = 0;
3414                 pRelease->FileExtents[count].CacheOffset = pExtent->CacheOffset;
3415                 pRelease->FileExtents[count].FileOffset = pExtent->FileOffset;
3416
3417 #if GEN_MD5
3418                 RtlCopyMemory( pRelease->FileExtents[count].MD5,
3419                                pExtent->MD5,
3420                                sizeof(pExtent->MD5));
3421
3422                 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_MD5_SET;
3423 #endif
3424
3425                 AFSFreeExtent( Fcb,
3426                                pExtent);
3427
3428                 count ++;
3429             }
3430
3431             //
3432             // If we are done then get out
3433             //
3434
3435             if( count == 0)
3436             {
3437
3438                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3439                               AFS_TRACE_LEVEL_VERBOSE,
3440                               "AFSReleaseCleanExtents No more dirty extents found\n");
3441
3442                 break;
3443             }
3444
3445             //
3446             // Fire off the request synchronously
3447             //
3448
3449             sz = sizeof( AFSReleaseExtentsCB ) + (count * sizeof ( AFSFileExtentCB ));
3450
3451             pRelease->ExtentCount = count;
3452
3453             //
3454             // Drop the extents lock for the duration of the call to
3455             // the network.  We have pinned the extents so, even
3456             // though we might get extents added during this period,
3457             // but none will be removed.  Hence we can carry on from
3458             // le.
3459             //
3460
3461             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3462                           AFS_TRACE_LEVEL_VERBOSE,
3463                           "AFSReleaseCleanExtents Releasing Fcb extents lock %p thread %08lX\n",
3464                           &pNPFcb->Specific.File.ExtentsResource,
3465                           PsGetCurrentThread());
3466
3467             AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource);
3468             bExtentsLocked = FALSE;
3469
3470             ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS,
3471                                           AFS_REQUEST_FLAG_SYNCHRONOUS,
3472                                           pAuthGroup,
3473                                           NULL,
3474                                           &Fcb->ObjectInformation->FileId,
3475                                           pRelease,
3476                                           sz,
3477                                           NULL,
3478                                           NULL);
3479
3480             if( !NT_SUCCESS(ntStatus))
3481             {
3482
3483                 //
3484                 // Regardless of whether or not the AFSProcessRequest() succeeded, the extents
3485                 // were released (if AFS_EXTENT_FLAG_RELEASE was set).  Log the error so it is known.
3486                 //
3487
3488                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3489                               AFS_TRACE_LEVEL_ERROR,
3490                               "AFSReleaseCleanExtents AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
3491                               Fcb->ObjectInformation->FileId.Cell,
3492                               Fcb->ObjectInformation->FileId.Volume,
3493                               Fcb->ObjectInformation->FileId.Vnode,
3494                               Fcb->ObjectInformation->FileId.Unique,
3495                               ntStatus);
3496             }
3497         }
3498
3499 try_exit:
3500
3501         if (bExtentsLocked)
3502         {
3503
3504             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3505                           AFS_TRACE_LEVEL_VERBOSE,
3506                           "AFSReleaseCleanExtents Releasing Fcb extents lock %p thread %08lX\n",
3507                           &pNPFcb->Specific.File.ExtentsResource,
3508                           PsGetCurrentThread());
3509
3510             AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
3511         }
3512
3513         if (pRelease)
3514         {
3515             AFSExFreePoolWithTag( pRelease, AFS_EXTENT_RELEASE_TAG);
3516         }
3517     }
3518
3519     return ntStatus;
3520 }
3521
3522 VOID
3523 AFSMarkDirty( IN AFSFcb *Fcb,
3524               IN AFSExtent *StartExtent,
3525               IN ULONG ExtentsCount,
3526               IN LARGE_INTEGER *StartingByte,
3527               IN BOOLEAN DerefExtents)
3528 {
3529
3530     AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
3531     AFSExtent     *pExtent = StartExtent;
3532     AFSExtent     *pNextExtent, *pCurrentExtent = NULL;
3533     ULONG ulCount = 0;
3534     BOOLEAN bInsertTail = FALSE, bInsertHead = FALSE;
3535     LONG lCount;
3536
3537     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3538                   AFS_TRACE_LEVEL_VERBOSE,
3539                   "AFSMarkDirty Acquiring Fcb extents lock %p SHARED %08lX\n",
3540                   &Fcb->NPFcb->Specific.File.ExtentsResource,
3541                   PsGetCurrentThread());
3542
3543     ASSERT( ExIsResourceAcquiredLite( &pNPFcb->Specific.File.ExtentsResource));
3544
3545     AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
3546                     TRUE);
3547
3548     __try
3549     {
3550         //
3551         // Find the insertion point
3552         //
3553
3554         if( pNPFcb->Specific.File.DirtyListHead == NULL)
3555         {
3556
3557             bInsertTail = TRUE;
3558         }
3559         else if( StartingByte->QuadPart == 0)
3560         {
3561