2 * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3 * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
14 * this list of conditions and the following disclaimer in the
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.
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.
36 // File: AFSCommSupport.cpp
38 #include "AFSCommon.h"
40 #define AFS_MAX_FCBS_TO_DROP 10
42 static AFSExtent *NextExtent( AFSExtent *Extent, ULONG SkipList );
43 static ULONG ExtentsMasks[AFS_NUM_EXTENT_LISTS] = AFS_EXTENTS_MASKS;
44 static VOID VerifyExtentsLists(AFSFcb *Fcb);
45 static AFSExtent *DirtyExtentFor(PLIST_ENTRY le);
48 AFSEntryForOffset( IN AFSFcb *Fcb,
49 IN PLARGE_INTEGER Offset);
53 // Returns with Extents lock EX and no one using them.
57 AFSLockForExtentsTrim( IN AFSFcb *Fcb)
60 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
62 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
63 AFS_TRACE_LEVEL_VERBOSE,
64 "AFSLockForExtentsTrim Acquiring Fcb extents lock %08lX EXCL %08lX\n",
65 &pNPFcb->Specific.File.ExtentsResource,
66 PsGetCurrentThread());
68 AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, TRUE );
74 // return FALSE *or* with Extents lock EX and noone using them
77 AFSLockForExtentsTrimNoWait( IN AFSFcb *Fcb)
79 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
81 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
82 AFS_TRACE_LEVEL_VERBOSE,
83 "AFSLockForExtentsTrimNoWait Attempting to acquire Fcb extent lock %08lX EXCL %08lX\n",
84 &pNPFcb->Specific.File.ExtentsResource,
85 PsGetCurrentThread());
87 if (!AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, FALSE ))
90 // Couldn't lock immediately
93 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
94 AFS_TRACE_LEVEL_VERBOSE,
95 "AFSLockForExtentsTrimNoWait Refused to wait for Fcb extent lock %08lX EXCL %08lX\n",
96 &pNPFcb->Specific.File.ExtentsResource,
97 PsGetCurrentThread());
105 // Pull all the extents away from the FCB.
108 AFSTearDownFcbExtents( IN AFSFcb *Fcb,
111 BOOLEAN bFoundExtents = FALSE;
112 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
115 ULONG ulCount = 0, ulReleaseCount = 0, ulProcessCount = 0;
117 AFSReleaseExtentsCB *pRelease = NULL;
118 BOOLEAN locked = FALSE;
120 AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
121 GUID *pAuthGroup = AuthGroup;
128 if( pAuthGroup == NULL ||
129 RtlCompareMemory( pAuthGroup,
130 &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
131 sizeof( GUID)) == sizeof( GUID))
134 RtlZeroMemory( &stAuthGroup,
137 ntStatus = AFSRetrieveValidAuthGroup( Fcb,
142 if( !NT_SUCCESS( ntStatus))
144 try_return( ntStatus);
147 pAuthGroup = &stAuthGroup;
151 // Ensure that no one is working with the extents and grab the
155 AFSLockForExtentsTrim( Fcb );
159 if (0 == Fcb->Specific.File.ExtentCount)
161 try_return ( ntStatus = STATUS_SUCCESS);
165 // Release a max of 100 extents at a time
168 sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
170 pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
172 AFS_EXTENT_RELEASE_TAG);
173 if (NULL == pRelease)
176 try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
179 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
181 ulCount = Fcb->Specific.File.ExtentCount;
183 while( ulReleaseCount < ulCount)
186 bFoundExtents = TRUE;
188 RtlZeroMemory( pRelease,
189 sizeof( AFSReleaseExtentsCB ) +
190 (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB )));
192 if( ulCount - ulReleaseCount <= AFS_MAXIMUM_EXTENT_RELEASE_COUNT)
194 ulProcessCount = ulCount - ulReleaseCount;
198 ulProcessCount = AFS_MAXIMUM_EXTENT_RELEASE_COUNT;
201 pRelease->Flags = AFS_EXTENT_FLAG_RELEASE;
202 pRelease->ExtentCount = ulProcessCount;
205 // Update the metadata for this call
208 pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
209 pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
210 pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
211 pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
212 pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
216 while (ulProcessCount < pRelease->ExtentCount)
218 pEntry = ExtentFor( le, AFS_EXTENTS_LIST );
220 pRelease->FileExtents[ulProcessCount].Flags = AFS_EXTENT_FLAG_RELEASE;
223 RtlCopyMemory( pRelease->FileExtents[ulProcessCount].MD5,
225 sizeof(pEntry->MD5));
227 pRelease->FileExtents[ulProcessCount].Flags |= AFS_EXTENT_FLAG_MD5_SET;
230 if( BooleanFlagOn( pEntry->Flags, AFS_EXTENT_DIRTY))
233 AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
236 if( BooleanFlagOn( pEntry->Flags, AFS_EXTENT_DIRTY))
241 AFSRemoveEntryDirtyList( Fcb,
244 pRelease->FileExtents[ulProcessCount].Flags |= AFS_EXTENT_FLAG_DIRTY;
246 dirtyCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
248 ASSERT( dirtyCount >= 0);
251 AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
254 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
255 AFS_TRACE_LEVEL_VERBOSE,
256 "AFSTearDownFcbExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %08lX-%08lX Len %08lX\n",
258 Fcb->ObjectInformation->FileId.Cell,
259 Fcb->ObjectInformation->FileId.Volume,
260 Fcb->ObjectInformation->FileId.Vnode,
261 Fcb->ObjectInformation->FileId.Unique,
262 pEntry->FileOffset.HighPart,
263 pEntry->FileOffset.LowPart,
266 pRelease->FileExtents[ulProcessCount].Length = pEntry->Size;
267 pRelease->FileExtents[ulProcessCount].DirtyLength = pEntry->Size;
268 pRelease->FileExtents[ulProcessCount].DirtyOffset = 0;
269 pRelease->FileExtents[ulProcessCount].CacheOffset = pEntry->CacheOffset;
270 pRelease->FileExtents[ulProcessCount].FileOffset = pEntry->FileOffset;
272 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pEntry->Size/1024)));
274 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pEntry->Size/1024)));
276 ASSERT( pEntry->ActiveCount == 0);
280 AFSExFreePool( pEntry);
282 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
284 lCount = InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount);
289 KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
296 // Send the request down. We cannot send this down
297 // asynchronously - if we did that we could request them
298 // back before the service got this request and then this
299 // request would be a corruption.
302 sz = sizeof( AFSReleaseExtentsCB ) + (ulProcessCount * sizeof ( AFSFileExtentCB ));
304 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS,
305 AFS_REQUEST_FLAG_SYNCHRONOUS,
308 &Fcb->ObjectInformation->FileId,
314 if( !NT_SUCCESS(ntStatus))
318 // Regardless of whether or not the AFSProcessRequest() succeeded, the extents
319 // were released (if AFS_EXTENT_FLAG_RELEASE was set). Log the error so it is known.
322 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
323 AFS_TRACE_LEVEL_ERROR,
324 "AFSTearDownFcbExtents AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
325 Fcb->ObjectInformation->FileId.Cell,
326 Fcb->ObjectInformation->FileId.Volume,
327 Fcb->ObjectInformation->FileId.Vnode,
328 Fcb->ObjectInformation->FileId.Unique,
333 ulReleaseCount += ulProcessCount;
337 // Reinitialize the skip lists
340 ASSERT( Fcb->Specific.File.ExtentCount == 0);
342 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i++)
344 InitializeListHead(&Fcb->Specific.File.ExtentsLists[i]);
348 // Reinitialize the dirty list as well
351 AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
354 ASSERT( Fcb->Specific.File.ExtentsDirtyCount == 0);
356 Fcb->NPFcb->Specific.File.DirtyListHead = NULL;
357 Fcb->NPFcb->Specific.File.DirtyListTail = NULL;
359 AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
361 Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
368 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
369 AFS_TRACE_LEVEL_VERBOSE,
370 "AFSTearDownFcbExtents Releasing Fcb extent lock %08lX thread %08lX\n",
371 &Fcb->NPFcb->Specific.File.ExtentsResource,
372 PsGetCurrentThread());
374 AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource );
380 AFSExFreePool( pRelease);
384 return bFoundExtents;
388 ExtentForOffsetInList( IN AFSFcb *Fcb,
391 IN PLARGE_INTEGER Offset)
394 // Return the extent that maps the offset, that
395 // - Contains the offset
396 // - or is immediately ahead of the offset (in this list)
397 // - otherwise return NULL.
400 PLIST_ENTRY pLe = List;
401 AFSExtent *pPrevious = NULL;
403 ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
405 while (pLe != &Fcb->Specific.File.ExtentsLists[ListNumber])
409 entry = ExtentFor( pLe, ListNumber );
416 if (Offset->QuadPart < entry->FileOffset.QuadPart)
419 // Offset is ahead of entry. Return previous
424 if (Offset->QuadPart >= (entry->FileOffset.QuadPart + entry->Size))
427 // We start after this extent - carry on round
435 // Otherwise its a match
442 // Got to the end. Return Previous
448 AFSExtentContains( IN AFSExtent *Extent, IN PLARGE_INTEGER Offset)
454 return (Extent->FileOffset.QuadPart <= Offset->QuadPart &&
455 (Extent->FileOffset.QuadPart + Extent->Size) > Offset->QuadPart);
460 // Return the extent that contains the offset
463 AFSExtentForOffsetHint( IN AFSFcb *Fcb,
464 IN PLARGE_INTEGER Offset,
465 IN BOOLEAN ReturnPrevious,
468 AFSExtent *pPrevious = Hint;
472 ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
474 #if AFS_VALIDATE_EXTENTS
475 VerifyExtentsLists(Fcb);
479 // So we will go across the skip lists until we find an
480 // appropriate entry (previous or direct match). If it's a match
481 // we are done, other wise we start on the next layer down
483 for (i = AFS_NUM_EXTENT_LISTS-1; i >= AFS_EXTENTS_LIST; i--)
485 if (NULL == pPrevious)
488 // We haven't found anything in the previous layers
490 pLe = Fcb->Specific.File.ExtentsLists[i].Flink;
492 else if (NULL == pPrevious->Lists[i].Flink)
494 ASSERT(AFS_EXTENTS_LIST != i);
496 // The hint doesn't exist at this level, next one down
503 // take the previous into the next
505 pLe = &pPrevious->Lists[i];
508 pPrevious = ExtentForOffsetInList( Fcb, pLe, i, Offset);
510 if (NULL != pPrevious && AFSExtentContains(pPrevious, Offset))
513 // Found it immediately. Stop here
519 if (NULL == pPrevious || ReturnPrevious )
524 ASSERT( !AFSExtentContains(pPrevious, Offset) );
530 AFSEntryForOffset( IN AFSFcb *Fcb,
531 IN PLARGE_INTEGER Offset)
533 AFSExtent *pPrevious = NULL;
537 ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
539 #if AFS_VALIDATE_EXTENTS
540 VerifyExtentsLists(Fcb);
544 // So we will go across the skip lists until we find an
545 // appropriate entry (previous or direct match). If it's a match
546 // we are done, other wise we start on the next layer down
548 for (i = AFS_NUM_EXTENT_LISTS-1; i >= AFS_EXTENTS_LIST; i--)
550 if (NULL == pPrevious)
553 // We haven't found anything in the previous layers
555 pLe = Fcb->Specific.File.ExtentsLists[i].Flink;
557 else if (NULL == pPrevious->Lists[i].Flink)
559 ASSERT(AFS_EXTENTS_LIST != i);
561 // The hint doesn't exist at this level, next one down
568 // take the previous into the next
570 pLe = &pPrevious->Lists[i];
573 pPrevious = ExtentForOffsetInList( Fcb, pLe, i, Offset);
575 if (NULL != pPrevious && AFSExtentContains(pPrevious, Offset))
578 // Found it immediately. Stop here
588 AFSExtentForOffset( IN AFSFcb *Fcb,
589 IN PLARGE_INTEGER Offset,
590 IN BOOLEAN ReturnPrevious)
592 return AFSExtentForOffsetHint(Fcb, Offset, ReturnPrevious, NULL);
596 BOOLEAN AFSDoExtentsMapRegion(IN AFSFcb *Fcb,
597 IN PLARGE_INTEGER Offset,
599 IN OUT AFSExtent **FirstExtent,
600 OUT AFSExtent **LastExtent)
603 // Return TRUE region is completely mapped. FALSE
604 // otherwise. If the region isn't mapped then the last
605 // extent to map part of the region is returned.
607 // *LastExtent as input is where to start looking.
608 // *LastExtent as output is either the extent which
609 // contains the Offset, or the last one which doesn't
613 BOOLEAN retVal = FALSE;
618 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
619 AFS_TRACE_LEVEL_VERBOSE,
620 "AFSDoExtentsMapRegion Acquiring Fcb extent lock %08lX SHARED %08lX\n",
621 &Fcb->NPFcb->Specific.File.ExtentsResource,
622 PsGetCurrentThread());
624 AFSAcquireShared( &Fcb->NPFcb->Specific.File.ExtentsResource, TRUE );
626 entry = AFSExtentForOffsetHint(Fcb, Offset, TRUE, *FirstExtent);
627 *FirstExtent = entry;
629 if (NULL == entry || !AFSExtentContains(entry, Offset))
631 try_return (retVal = FALSE);
634 ASSERT(Offset->QuadPart >= entry->FileOffset.QuadPart);
638 if ((entry->FileOffset.QuadPart + entry->Size) >=
639 (Offset->QuadPart + Size))
642 // The end is inside the extent
644 try_return (retVal = TRUE);
647 if (entry->Lists[AFS_EXTENTS_LIST].Flink == &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
650 // Run out of extents
652 try_return (retVal = FALSE);
655 newEntry = NextExtent( entry, AFS_EXTENTS_LIST );
657 if (newEntry->FileOffset.QuadPart !=
658 (entry->FileOffset.QuadPart + entry->Size))
663 try_return (retVal = FALSE);
671 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
672 AFS_TRACE_LEVEL_VERBOSE,
673 "AFSDoExtentsMapRegion Releasing Fcb extent lock %08lX SHARED %08lX\n",
674 &Fcb->NPFcb->Specific.File.ExtentsResource,
675 PsGetCurrentThread());
677 AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource );
686 AFSRequestExtentsAsync( IN AFSFcb *Fcb,
688 IN PLARGE_INTEGER Offset,
692 AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
693 NTSTATUS ntStatus = STATUS_SUCCESS;
694 AFSExtent *pExtent = NULL;
695 AFSRequestExtentsCB request;
696 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
697 AFSExtent *pFirstExtent = NULL;
698 LARGE_INTEGER liAlignedOffset;
699 ULONG ulAlignedLength = 0;
700 BOOLEAN bRegionMapped = FALSE;
701 ULONGLONG ullProcessId = (ULONGLONG)PsGetCurrentProcessId();
706 ASSERT( !ExIsResourceAcquiredLite( &pNPFcb->Specific.File.ExtentsResource ));
709 // If the service set a failure on the file since the last
710 // CreateFile was issued, return it now.
713 if (!NT_SUCCESS( pNPFcb->Specific.File.ExtentsRequestStatus))
717 // If this isn't the same authgroup which caused the failure
718 // then try to request them again
721 if( RtlCompareMemory( &pNPFcb->Specific.File.ExtentsRequestAuthGroup,
723 sizeof( GUID)) == sizeof( GUID))
726 ntStatus = pNPFcb->Specific.File.ExtentsRequestStatus;
728 pNPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
730 RtlZeroMemory( &pNPFcb->Specific.File.ExtentsRequestAuthGroup,
733 try_return( ntStatus);
738 // Check if we are already mapped
741 bRegionMapped = AFSDoExtentsMapRegion( Fcb, Offset, Size, &pFirstExtent, &pExtent);
746 try_return( ntStatus = STATUS_SUCCESS);
750 // Align our request on extent size boundary
753 ulAlignedLength = Size;
755 liAlignedOffset = *Offset;
757 if( liAlignedOffset.QuadPart % pDevExt->Specific.RDR.CacheBlockSize != 0)
760 liAlignedOffset.QuadPart = (ULONGLONG)( (ULONGLONG)(liAlignedOffset.QuadPart / pDevExt->Specific.RDR.CacheBlockSize) * (ULONGLONG)pDevExt->Specific.RDR.CacheBlockSize);
762 ulAlignedLength += (ULONG)(Offset->QuadPart - liAlignedOffset.QuadPart);
765 if( ulAlignedLength % pDevExt->Specific.RDR.CacheBlockSize != 0)
768 ulAlignedLength = (ULONG)(((ulAlignedLength / pDevExt->Specific.RDR.CacheBlockSize) + 1) * pDevExt->Specific.RDR.CacheBlockSize);
771 RtlZeroMemory( &request,
772 sizeof( AFSRequestExtentsCB));
774 request.ByteOffset = liAlignedOffset;
775 request.Length = ulAlignedLength;
777 if( !AFSIsExtentRequestQueued( &Fcb->ObjectInformation->FileId,
782 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
783 AFS_TRACE_LEVEL_VERBOSE,
784 "AFSRequestExtentsAsync Request extents for fid %08lX-%08lX-%08lX-%08lX Offset %08lX Len %08lX Thread %08lX\n",
785 Fcb->ObjectInformation->FileId.Cell,
786 Fcb->ObjectInformation->FileId.Volume,
787 Fcb->ObjectInformation->FileId.Vnode,
788 Fcb->ObjectInformation->FileId.Unique,
789 request.ByteOffset.LowPart,
791 PsGetCurrentThread());
793 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_REQUEST_FILE_EXTENTS,
797 &Fcb->ObjectInformation->FileId,
799 sizeof( AFSRequestExtentsCB ),
803 if ( ntStatus == STATUS_ACCESS_DENIED)
808 ntStatus2 = AFSRetrieveValidAuthGroup( Fcb,
813 if ( NT_SUCCESS( ntStatus2) &&
814 RtlCompareMemory( &stAuthGroup,
816 sizeof( GUID)) != sizeof( GUID))
819 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_REQUEST_FILE_EXTENTS,
823 &Fcb->ObjectInformation->FileId,
825 sizeof( AFSRequestExtentsCB ),
831 if( NT_SUCCESS( ntStatus))
834 KeClearEvent( &pNPFcb->Specific.File.ExtentsRequestComplete );
840 KeClearEvent( &pNPFcb->Specific.File.ExtentsRequestComplete );
852 AFSProcessExtentsResult( IN AFSFcb *Fcb,
854 IN AFSFileExtentCB *Result)
856 NTSTATUS ntStatus = STATUS_SUCCESS;
857 AFSFileExtentCB *pFileExtents = Result;
860 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
861 ULONG fileExtentsUsed = 0;
862 BOOLEAN bFoundExtent = FALSE;
863 LIST_ENTRY *pSkipEntries[AFS_NUM_EXTENT_LISTS] = { 0 };
864 AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
868 // Grab the extents exclusive for the duration
871 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
872 AFS_TRACE_LEVEL_VERBOSE,
873 "AFSProcessExtentsResult Acquiring Fcb extent lock %08lX EXCL %08lX\n",
874 &pNPFcb->Specific.File.ExtentsResource,
875 PsGetCurrentThread());
877 AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, TRUE );
883 // Find where to put the extents
885 for (ULONG i = AFS_EXTENTS_LIST; i < AFS_NUM_EXTENT_LISTS; i++)
888 pSkipEntries[i] = Fcb->Specific.File.ExtentsLists[i].Flink;
891 le = pSkipEntries[AFS_EXTENTS_LIST];
893 if (le == &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
896 // No extents. Insert at head of list (which is where the skip lists point!)
900 else if (0 != pFileExtents->FileOffset.QuadPart)
903 // We want to find the best extents immediately *behind* this offset
905 LARGE_INTEGER offset = pFileExtents->FileOffset;
908 // Ask in the top skip list first, then work down
910 for (LONG i = AFS_NUM_EXTENT_LISTS-1; i >= AFS_EXTENTS_LIST; i--)
912 pExtent = ExtentForOffsetInList( Fcb,
920 // No dice. Header has to become the head of the list
922 pSkipEntries[i] = &Fcb->Specific.File.ExtentsLists[i];
924 // And as a loop invariant we should never have found an extent
926 ASSERT(!bFoundExtent);
931 // pExtent is where to start to insert at this level
933 pSkipEntries[i] = &pExtent->Lists[i];
936 // And also where to start to look at the next level
939 if (i > AFS_EXTENTS_LIST)
941 pSkipEntries[i-1] = &pExtent->Lists[i-1];
949 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
954 le = pExtent->Lists[AFS_EXTENTS_LIST].Blink;
960 // Looking at offset 0, so we must start at the beginning
963 pExtent = ExtentFor(le, AFS_EXTENTS_LIST);
967 // And set up the skip lists
970 for (ULONG i = AFS_EXTENTS_LIST; i < AFS_NUM_EXTENT_LISTS; i++)
972 pSkipEntries[i] = &Fcb->Specific.File.ExtentsLists[i];
976 while (fileExtentsUsed < Count)
980 // Loop invariant - le points to where to insert after and
981 // pExtent points to le->fLink
984 ASSERT (NULL == pExtent ||
985 le->Flink == &pExtent->Lists[AFS_EXTENTS_LIST]);
987 if (NULL == pExtent ||
988 pExtent->FileOffset.QuadPart > pFileExtents->FileOffset.QuadPart)
991 // We need to insert a new extent at le. Start with
992 // some sanity check on spanning
994 if (NULL != pExtent &&
995 ((pFileExtents->FileOffset.QuadPart + pFileExtents->Length) >
996 pExtent->FileOffset.QuadPart))
999 // File Extents overlaps pExtent
1001 ASSERT( (pFileExtents->FileOffset.QuadPart + pFileExtents->Length) <=
1002 pExtent->FileOffset.QuadPart);
1004 try_return (ntStatus = STATUS_INVALID_PARAMETER);
1008 // File offset is entirely in front of this extent. Create
1009 // a new one (remember le is the previous list entry)
1011 pExtent = (AFSExtent *) AFSExAllocatePoolWithTag( NonPagedPool,
1014 if (NULL == pExtent)
1019 try_return (ntStatus = STATUS_INSUFFICIENT_RESOURCES );
1022 RtlZeroMemory( pExtent, sizeof( AFSExtent ));
1024 pExtent->FileOffset = pFileExtents->FileOffset;
1025 pExtent->CacheOffset = pFileExtents->CacheOffset;
1026 pExtent->Size = pFileExtents->Length;
1028 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1029 AFS_TRACE_LEVEL_VERBOSE,
1030 "AFSProcessExtentsResult Received extent for fid %08lX-%08lX-%08lX-%08lX File Offset %I64X Cache Offset %I64X Len %08lX\n",
1031 Fcb->ObjectInformation->FileId.Cell,
1032 Fcb->ObjectInformation->FileId.Volume,
1033 Fcb->ObjectInformation->FileId.Vnode,
1034 Fcb->ObjectInformation->FileId.Unique,
1035 pFileExtents->FileOffset.QuadPart,
1036 pFileExtents->CacheOffset.QuadPart,
1037 pFileExtents->Length);
1039 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, (LONG)(pExtent->Size/1024));
1041 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, (LONG)(pExtent->Size/1024));
1043 lCount = InterlockedIncrement( &Fcb->Specific.File.ExtentCount);
1045 lCount = InterlockedIncrement( &pControlDevExt->Specific.Control.ExtentCount);
1050 KeClearEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent);
1056 InsertHeadList(le, &pExtent->Lists[AFS_EXTENTS_LIST]);
1057 ASSERT(le->Flink == &pExtent->Lists[AFS_EXTENTS_LIST]);
1058 ASSERT(0 == (pExtent->FileOffset.LowPart & ExtentsMasks[AFS_EXTENTS_LIST]));
1061 // Do not move the cursor - we will do it next time
1065 // And into the (upper) skip lists - Again, do not move the cursor
1067 for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--)
1069 if (0 == (pExtent->FileOffset.LowPart & ExtentsMasks[i]))
1071 InsertHeadList(pSkipEntries[i], &pExtent->Lists[i]);
1072 #if AFS_VALIDATE_EXTENTS
1073 VerifyExtentsLists(Fcb);
1078 else if (pExtent->FileOffset.QuadPart == pFileExtents->FileOffset.QuadPart)
1081 if (pExtent->Size != pFileExtents->Length)
1084 ASSERT (pExtent->Size == pFileExtents->Length);
1086 try_return (ntStatus = STATUS_INVALID_PARAMETER);
1090 // Move both cursors forward.
1092 // First the extent pointer
1095 le = &pExtent->Lists[AFS_EXTENTS_LIST];
1098 // Then the skip lists cursors forward if needed
1100 for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--)
1102 if (0 == (pExtent->FileOffset.LowPart & ExtentsMasks[i]))
1105 // Check sanity before
1107 #if AFS_VALIDATE_EXTENTS
1108 VerifyExtentsLists(Fcb);
1112 // Skip list should point to us
1114 //ASSERT(pSkipEntries[i] == &pExtent->Lists[i]);
1116 // Move forward cursor
1118 pSkipEntries[i] = pSkipEntries[i]->Flink;
1120 // Check sanity before
1122 #if AFS_VALIDATE_EXTENTS
1123 VerifyExtentsLists(Fcb);
1129 // And then the cursor in the supplied array
1135 // setup pExtent if there is one
1137 if (le->Flink != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
1139 pExtent = NextExtent( pExtent, AFS_EXTENTS_LIST ) ;
1149 ASSERT( pExtent->FileOffset.QuadPart < pFileExtents->FileOffset.QuadPart );
1152 // Sanity check on spanning
1154 if ((pExtent->FileOffset.QuadPart + pExtent->Size) >
1155 pFileExtents->FileOffset.QuadPart)
1158 ASSERT( (pExtent->FileOffset.QuadPart + pExtent->Size) <=
1159 pFileExtents->FileOffset.QuadPart);
1161 try_return (ntStatus = STATUS_INVALID_PARAMETER);
1165 // Move le and pExtent forward
1167 le = &pExtent->Lists[AFS_EXTENTS_LIST];
1171 // Then the check the skip lists cursors
1173 for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--)
1175 if (0 == (pFileExtents->FileOffset.LowPart & ExtentsMasks[i]))
1179 // - empty list (pSkipEntries[i]->Flink == pSkipEntries[i]->Flink == fcb->lists[i]
1180 // - We are the last on the list (pSkipEntries[i]->Flink == fcb->lists[i])
1181 // - We are not the last on the list. In that case we have to be strictly less than
1183 if (pSkipEntries[i]->Flink != &Fcb->Specific.File.ExtentsLists[i]) {
1185 AFSExtent *otherExtent = ExtentFor(pSkipEntries[i]->Flink, i);
1186 ASSERT(pFileExtents->FileOffset.QuadPart < otherExtent->FileOffset.QuadPart);
1193 // setup pExtent if there is one
1196 if (le->Flink != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
1198 pExtent = NextExtent( pExtent, AFS_EXTENTS_LIST ) ;
1208 // All done, signal that we are done drop the lock, exit
1213 if( !NT_SUCCESS( ntStatus))
1217 // If we failed the service is going to drop all extents so trim away the
1221 AFSTrimSpecifiedExtents( Fcb,
1226 #if AFS_VALIDATE_EXTENTS
1227 VerifyExtentsLists(Fcb);
1230 KeSetEvent( &pNPFcb->Specific.File.ExtentsRequestComplete,
1234 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1235 AFS_TRACE_LEVEL_VERBOSE,
1236 "AFSProcessExtentsResult Releasing Fcb extent lock %08lX EXCL %08lX\n",
1237 &pNPFcb->Specific.File.ExtentsResource,
1238 PsGetCurrentThread());
1240 AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
1247 AFSProcessSetFileExtents( IN AFSSetFileExtentsCB *SetExtents )
1249 AFSFcb *pFcb = NULL;
1250 AFSVolumeCB *pVolumeCB = NULL;
1251 NTSTATUS ntStatus = STATUS_SUCCESS;
1252 AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1253 ULONGLONG ullIndex = 0;
1254 AFSObjectInfoCB *pObjectInfo = NULL;
1260 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1261 AFS_TRACE_LEVEL_VERBOSE,
1262 "AFSProcessSetFileExtents Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n",
1263 &pDevExt->Specific.RDR.VolumeTreeLock,
1264 PsGetCurrentThread());
1266 AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
1268 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1269 AFS_TRACE_LEVEL_VERBOSE,
1270 "AFSProcessSetFileExtents Set extents for fid %08lX-%08lX-%08lX-%08lX\n",
1271 SetExtents->FileId.Cell,
1272 SetExtents->FileId.Volume,
1273 SetExtents->FileId.Vnode,
1274 SetExtents->FileId.Unique);
1277 // Locate the volume node
1280 ullIndex = AFSCreateHighIndex( &SetExtents->FileId);
1282 ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
1284 (AFSBTreeEntry **)&pVolumeCB);
1286 if( pVolumeCB != NULL)
1289 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1290 AFS_TRACE_LEVEL_VERBOSE,
1291 "AFSProcessSetFileExtents Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n",
1292 pVolumeCB->ObjectInfoTree.TreeLock,
1293 PsGetCurrentThread());
1295 lCount = InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
1298 AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
1300 if( !NT_SUCCESS( ntStatus) ||
1304 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1305 AFS_TRACE_LEVEL_ERROR,
1306 "AFSProcessSetFileExtents Set extents for fid %08lX-%08lX-%08lX-%08lX Failed to locate volume Status %08lX\n",
1307 SetExtents->FileId.Cell,
1308 SetExtents->FileId.Volume,
1309 SetExtents->FileId.Vnode,
1310 SetExtents->FileId.Unique,
1313 try_return( ntStatus = STATUS_UNSUCCESSFUL);
1316 AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1319 lCount = InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1322 // Now locate the Object in this volume
1325 ullIndex = AFSCreateLowIndex( &SetExtents->FileId);
1327 ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
1329 (AFSBTreeEntry **)&pObjectInfo);
1331 if( pObjectInfo != NULL)
1335 // Reference the node so it won't be torn down
1338 lCount = InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
1340 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1341 AFS_TRACE_LEVEL_VERBOSE,
1342 "AFSProcessSetFileExtents Increment count on object %08lX Cnt %d\n",
1347 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1349 if( !NT_SUCCESS( ntStatus) ||
1350 pObjectInfo == NULL)
1353 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1354 AFS_TRACE_LEVEL_ERROR,
1355 "AFSProcessSetFileExtents Set extents for hash %I64X fid %08lX-%08lX-%08lX-%08lX Failed to locate file in volume %08lX\n",
1357 SetExtents->FileId.Cell,
1358 SetExtents->FileId.Volume,
1359 SetExtents->FileId.Vnode,
1360 SetExtents->FileId.Unique,
1363 try_return( ntStatus = STATUS_UNSUCCESSFUL);
1366 pFcb = pObjectInfo->Fcb;
1369 // If we have a result failure then don't bother trying to set the extents
1372 if( SetExtents->ResultStatus != STATUS_SUCCESS)
1375 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1376 AFS_TRACE_LEVEL_ERROR,
1377 "AFSProcessSetFileExtents Set extents failure fid %08lX-%08lX-%08lX-%08lX ResultStatus %08lX\n",
1378 SetExtents->FileId.Cell,
1379 SetExtents->FileId.Volume,
1380 SetExtents->FileId.Vnode,
1381 SetExtents->FileId.Unique,
1382 SetExtents->ResultStatus);
1384 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1385 AFS_TRACE_LEVEL_VERBOSE,
1386 "AFSProcessSetFileExtents Acquiring Fcb extents lock %08lX EXCL %08lX\n",
1387 &pFcb->NPFcb->Specific.File.ExtentsResource,
1388 PsGetCurrentThread());
1390 AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource,
1393 pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_CANCELLED;
1395 KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete,
1399 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1400 AFS_TRACE_LEVEL_VERBOSE,
1401 "AFSProcessSetFileExtents Releasing Fcb extent lock %08lX EXCL %08lX\n",
1402 &pFcb->NPFcb->Specific.File.ExtentsResource,
1403 PsGetCurrentThread());
1405 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
1407 try_return( ntStatus);
1410 ntStatus = AFSProcessExtentsResult ( pFcb,
1411 SetExtents->ExtentCount,
1412 SetExtents->FileExtents );
1416 if( pObjectInfo != NULL)
1419 lCount = InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
1421 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1422 AFS_TRACE_LEVEL_VERBOSE,
1423 "AFSProcessSetFileExtents Decrement count on object %08lX Cnt %d\n",
1433 // Helper fuctions for Usermode initiation of release of extents
1436 AFSReleaseSpecifiedExtents( IN AFSReleaseFileExtentsCB *Extents,
1438 OUT AFSFileExtentCB *FileExtents,
1439 IN ULONG BufferSize,
1440 OUT ULONG *ExtentCount,
1441 OUT BOOLEAN *DirtyExtents)
1446 ULONG ulExtentCount = 0;
1447 NTSTATUS ntStatus = STATUS_SUCCESS;
1448 BOOLEAN bReleaseAll = FALSE;
1449 AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1454 ASSERT( ExIsResourceAcquiredExclusiveLite( &Fcb->NPFcb->Specific.File.ExtentsResource));
1456 if (BufferSize < (Extents->ExtentCount * sizeof( AFSFileExtentCB)))
1459 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1460 AFS_TRACE_LEVEL_VERBOSE,
1461 "AFSReleaseSpecifiedExtents Buffer too small\n");
1463 try_return( ntStatus = STATUS_BUFFER_TOO_SMALL);
1466 RtlZeroMemory( FileExtents, BufferSize);
1469 *DirtyExtents = FALSE;
1472 // iterate until we have dealt with all we were asked for or
1473 // are at the end of the list. Note that this deals (albeit
1474 // badly) with out of order extents
1477 pExtent = AFSExtentForOffset( Fcb,
1478 &Extents->FileExtents[0].FileOffset,
1481 if (NULL == pExtent)
1483 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1487 le = &pExtent->Lists[AFS_EXTENTS_LIST];
1491 if( BooleanFlagOn( Extents->Flags, AFS_RELEASE_EXTENTS_FLAGS_RELEASE_ALL) ||
1492 ( Extents->FileId.Cell == 0 &&
1493 Extents->FileId.Volume == 0 &&
1494 Extents->FileId.Vnode == 0 &&
1495 Extents->FileId.Unique == 0))
1501 while( le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST] &&
1502 ulExtentCount < Extents->ExtentCount)
1506 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
1511 if( pExtent->FileOffset.QuadPart < Extents->FileExtents[ulExtentCount].FileOffset.QuadPart)
1514 // Skip forward through the extent list until we get
1515 // to the one we want
1521 else if (pExtent->FileOffset.QuadPart > Extents->FileExtents[ulExtentCount].FileOffset.QuadPart)
1524 // We don't have the extent asked for so return UNKNOWN
1527 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1528 AFS_TRACE_LEVEL_VERBOSE,
1529 "AFSReleaseSpecifiedExtents Located UNKNOWN extent Offset %I64X Len %08lX\n",
1530 Extents->FileExtents[ulExtentCount].FileOffset.QuadPart,
1531 Extents->FileExtents[ulExtentCount].Length);
1533 FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_UNKNOWN;
1535 FileExtents[*ExtentCount].Length = 0;
1536 FileExtents[*ExtentCount].CacheOffset.QuadPart = 0;
1537 FileExtents[*ExtentCount].FileOffset = Extents->FileExtents[ulExtentCount].FileOffset;
1539 *ExtentCount = (*ExtentCount) + 1;
1544 // Reset where we are looking
1547 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1551 else if( pExtent->ActiveCount > 0)
1554 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1555 AFS_TRACE_LEVEL_VERBOSE,
1556 "AFSReleaseSpecifiedExtents Located IN_USE extent Offset %I64X Len %08lX\n",
1557 Extents->FileExtents[ulExtentCount].FileOffset.QuadPart,
1558 Extents->FileExtents[ulExtentCount].Length);
1560 FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_IN_USE;
1562 FileExtents[*ExtentCount].Length = 0;
1563 FileExtents[*ExtentCount].CacheOffset.QuadPart = 0;
1564 FileExtents[*ExtentCount].FileOffset = Extents->FileExtents[ulExtentCount].FileOffset;
1566 *ExtentCount = (*ExtentCount) + 1;
1571 // Reset where we are looking
1574 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1583 // If the extent is currently active then skip it
1586 if( pExtent->ActiveCount > 0)
1595 FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_RELEASE;
1597 FileExtents[*ExtentCount].Length = pExtent->Size;
1598 FileExtents[*ExtentCount].DirtyLength = pExtent->Size;
1599 FileExtents[*ExtentCount].DirtyOffset = 0;
1600 FileExtents[*ExtentCount].CacheOffset = pExtent->CacheOffset;
1601 FileExtents[*ExtentCount].FileOffset = pExtent->FileOffset;
1603 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1604 AFS_TRACE_LEVEL_VERBOSE,
1605 "AFSReleaseSpecifiedExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
1607 Fcb->ObjectInformation->FileId.Cell,
1608 Fcb->ObjectInformation->FileId.Volume,
1609 Fcb->ObjectInformation->FileId.Vnode,
1610 Fcb->ObjectInformation->FileId.Unique,
1611 FileExtents[*ExtentCount].FileOffset.QuadPart,
1612 FileExtents[*ExtentCount].Length);
1614 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
1617 AFSAcquireExcl( &Fcb->NPFcb->Specific.File.DirtyExtentsListLock,
1620 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
1623 AFSRemoveEntryDirtyList( Fcb,
1626 FileExtents[*ExtentCount].Flags |= AFS_EXTENT_FLAG_DIRTY;
1628 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
1630 *DirtyExtents = TRUE;
1633 AFSReleaseResource( &Fcb->NPFcb->Specific.File.DirtyExtentsListLock);
1637 // move forward all three cursors
1641 *ExtentCount = (*ExtentCount) + 1;
1646 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
1648 if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
1650 RemoveEntryList( &pExtent->Lists[i] );
1654 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
1656 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
1661 AFSExFreePool( pExtent);
1663 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
1665 lCount = InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount);
1670 KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
1685 AFSFindFcbToClean(ULONG IgnoreTime, AFSFcb *LastFcb, BOOLEAN Block)
1688 AFSFcb *pFcb = NULL;
1689 AFSVolumeCB *pVolumeCB = NULL;
1690 AFSDeviceExt *pRDRDeviceExt = NULL;
1691 AFSDeviceExt *pControlDeviceExt = NULL;
1692 BOOLEAN bLocatedEntry = FALSE;
1693 AFSObjectInfoCB *pCurrentObject = NULL;
1694 BOOLEAN bReleaseVolumeListLock = FALSE;
1697 pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1698 pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1700 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1701 AFS_TRACE_LEVEL_VERBOSE,
1702 "AFSFindFcbToClean Acquiring RDR VolumeListLock lock %08lX SHARED %08lX\n",
1703 &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1704 PsGetCurrentThread());
1706 AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1709 bReleaseVolumeListLock = TRUE;
1711 pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead;
1713 while( pVolumeCB != NULL)
1717 // The Volume list may move under our feet. Lock it.
1720 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1721 AFS_TRACE_LEVEL_VERBOSE,
1722 "AFSFindFcbToClean Acquiring VolumeRoot ObjectInfoTree lock %08lX SHARED %08lX\n",
1723 pVolumeCB->ObjectInfoTree.TreeLock,
1724 PsGetCurrentThread());
1726 lCount = InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
1728 AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1730 bReleaseVolumeListLock = FALSE;
1732 AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1735 lCount = InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1737 if( NULL == LastFcb)
1740 pCurrentObject = pVolumeCB->ObjectInfoListHead;
1745 pCurrentObject = (AFSObjectInfoCB *)LastFcb->ObjectInformation->ListEntry.fLink;
1750 while( pCurrentObject != NULL)
1753 pFcb = (AFSFcb *)pCurrentObject->Fcb;
1756 // If the FCB is a candidate we try to lock it (but without waiting - which
1757 // means we are deadlock free
1761 pFcb->Header.NodeTypeCode == AFS_FILE_FCB)
1767 AFSLockForExtentsTrim( pFcb);
1772 if( !AFSLockForExtentsTrimNoWait( pFcb))
1775 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1784 // Need to be sure there are no current flushes in the queue
1787 if( pFcb->Specific.File.ExtentCount == 0)
1790 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1791 AFS_TRACE_LEVEL_VERBOSE,
1792 "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n",
1793 &pFcb->NPFcb->Specific.File.ExtentsResource,
1794 PsGetCurrentThread());
1796 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
1798 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1805 if( pFcb->Specific.File.QueuedFlushCount > 0)
1808 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1809 AFS_TRACE_LEVEL_VERBOSE,
1810 "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n",
1811 &pFcb->NPFcb->Specific.File.ExtentsResource,
1812 PsGetCurrentThread());
1814 AFSReleaseResource(&pFcb->NPFcb->Specific.File.ExtentsResource);
1818 AFSWaitOnQueuedFlushes( pFcb);
1823 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1831 if( pFcb->OpenHandleCount > 0)
1834 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1835 AFS_TRACE_LEVEL_VERBOSE,
1836 "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n",
1837 &pFcb->NPFcb->Specific.File.ExtentsResource,
1838 PsGetCurrentThread());
1840 AFSReleaseResource(&pFcb->NPFcb->Specific.File.ExtentsResource);
1842 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1850 // A hit a very palpable hit. Pin it
1853 lCount = InterlockedIncrement( &pCurrentObject->ObjectReferenceCount);
1855 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1856 AFS_TRACE_LEVEL_VERBOSE,
1857 "AFSFindFcbToClean Increment count on Fcb %08lX Cnt %d\n",
1861 bLocatedEntry = TRUE;
1866 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1871 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1878 AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1881 bReleaseVolumeListLock = TRUE;
1883 pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1886 if( bReleaseVolumeListLock)
1889 AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1896 AFSProcessExtentFailure( PIRP Irp)
1898 AFSExtentFailureCB *pFailureCB = NULL;
1899 NTSTATUS ntStatus = STATUS_SUCCESS;
1900 AFSDeviceExt *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension;
1901 PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1902 AFSVolumeCB *pVolumeCB = NULL;
1903 ULONGLONG ullIndex = 0;
1904 AFSObjectInfoCB *pObjectInfo = NULL;
1909 if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSExtentFailureCB))
1912 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1913 AFS_TRACE_LEVEL_ERROR,
1914 "AFSProcessExtentFailure Input buffer too small\n");
1916 try_return( ntStatus = STATUS_INVALID_PARAMETER);
1919 pFailureCB = (AFSExtentFailureCB *)Irp->AssociatedIrp.SystemBuffer;
1921 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1922 AFS_TRACE_LEVEL_ERROR,
1923 "AFSProcessExtentFailure Service Reports Failure fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
1924 pFailureCB->FileId.Cell,
1925 pFailureCB->FileId.Volume,
1926 pFailureCB->FileId.Vnode,
1927 pFailureCB->FileId.Unique,
1928 pFailureCB->FailureStatus);
1930 AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
1933 // Locate the volume node
1936 ullIndex = AFSCreateHighIndex( &pFailureCB->FileId);
1938 ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
1940 (AFSBTreeEntry **)&pVolumeCB);
1942 if( pVolumeCB != NULL)
1945 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1946 AFS_TRACE_LEVEL_VERBOSE,
1947 "AFSProcessExtentFailure Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n",
1948 pVolumeCB->ObjectInfoTree.TreeLock,
1949 PsGetCurrentThread());
1951 lCount = InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
1954 AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
1956 if( !NT_SUCCESS( ntStatus) ||
1960 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1961 AFS_TRACE_LEVEL_ERROR,
1962 "AFSProcessExtentFailure Invalid volume index %I64X status %08X\n",
1963 ullIndex, ntStatus);
1965 try_return( ntStatus = STATUS_UNSUCCESSFUL);
1968 AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1971 lCount = InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1974 // Now locate the Object in this volume
1977 ullIndex = AFSCreateLowIndex( &pFailureCB->FileId);
1979 ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
1981 (AFSBTreeEntry **)&pObjectInfo);
1983 if( pObjectInfo != NULL &&
1984 pObjectInfo->Fcb != NULL)
1988 // Reference the node so it won't be torn down
1991 lCount = InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
1993 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1994 AFS_TRACE_LEVEL_VERBOSE,
1995 "AFSProcessExtentFailure Increment count on object %08lX Cnt %d\n",
2000 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
2002 if( !NT_SUCCESS( ntStatus) ||
2003 pObjectInfo == NULL ||
2004 pObjectInfo->Fcb == NULL)
2007 if( pObjectInfo == NULL)
2009 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2010 AFS_TRACE_LEVEL_ERROR,
2011 "AFSProcessExtentFailure Invalid file index %I64X\n",
2016 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2017 AFS_TRACE_LEVEL_ERROR,
2018 "AFSProcessExtentFailure Fcb dealocated for %I64X\n",
2022 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2025 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2026 AFS_TRACE_LEVEL_VERBOSE,
2027 "AFSProcessExtentFailure Acquiring Fcb extent lock %08lX EXCL %08lX\n",
2028 &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
2029 PsGetCurrentThread());
2031 AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
2034 pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = pFailureCB->FailureStatus;
2036 RtlCopyMemory( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2037 &pFailureCB->AuthGroup,
2040 KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
2044 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2045 AFS_TRACE_LEVEL_VERBOSE,
2046 "AFSProcessExtentFailure Releasing Fcb extent lock %08lX EXCL %08lX\n",
2047 &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
2048 PsGetCurrentThread());
2050 AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource);
2052 lCount = InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
2054 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2055 AFS_TRACE_LEVEL_VERBOSE,
2056 "AFSProcessExtentFailure Decrement count on object %08lX Cnt %d\n",
2069 AFSProcessReleaseFileExtents( IN PIRP Irp)
2071 NTSTATUS ntStatus = STATUS_SUCCESS;
2072 PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
2073 PFILE_OBJECT pFileObject = pIrpSp->FileObject;
2074 AFSFcb *pFcb = NULL;
2075 AFSVolumeCB *pVolumeCB = NULL;
2076 AFSDeviceExt *pDevExt;
2077 AFSReleaseFileExtentsCB *pExtents;
2078 AFSReleaseFileExtentsResultCB *pResult = NULL;
2079 AFSReleaseFileExtentsResultFileCB *pFile = NULL;
2081 ULONGLONG ullIndex = 0;
2082 AFSObjectInfoCB *pObjectInfo = NULL;
2083 BOOLEAN bLocked = FALSE;
2084 BOOLEAN bDirtyExtents = FALSE;
2091 pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension;
2093 pExtents = (AFSReleaseFileExtentsCB*) Irp->AssociatedIrp.SystemBuffer;
2095 if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2096 sizeof( AFSReleaseFileExtentsCB))
2099 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2100 AFS_TRACE_LEVEL_ERROR,
2101 "AFSProcessReleaseFileExtents INPUT Buffer too small\n");
2103 try_return( ntStatus = STATUS_INVALID_PARAMETER );
2106 if ( pIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
2107 sizeof(AFSReleaseFileExtentsResultCB))
2110 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2111 AFS_TRACE_LEVEL_ERROR,
2112 "AFSProcessReleaseFileExtents OUTPUT Buffer too small [1]\n");
2115 // Must have space for one extent in one file
2118 try_return( ntStatus = STATUS_BUFFER_TOO_SMALL);
2121 if (pExtents->ExtentCount == 0)
2124 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2125 AFS_TRACE_LEVEL_ERROR,
2126 "AFSProcessReleaseFileExtents Extent count zero\n");
2128 try_return( ntStatus = STATUS_INVALID_PARAMETER);
2131 if (pExtents->FileId.Cell != 0 ||
2132 pExtents->FileId.Volume != 0 ||
2133 pExtents->FileId.Vnode != 0 ||
2134 pExtents->FileId.Unique != 0)
2137 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2138 AFS_TRACE_LEVEL_VERBOSE,
2139 "AFSProcessReleaseFileExtents Processing FID %08lX:%08lX:%08lX:%08lX\n",
2140 pExtents->FileId.Cell,
2141 pExtents->FileId.Volume,
2142 pExtents->FileId.Vnode,
2143 pExtents->FileId.Unique);
2145 if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2146 ( FIELD_OFFSET( AFSReleaseFileExtentsCB, ExtentCount) + sizeof(ULONG)) ||
2147 pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2148 ( FIELD_OFFSET( AFSReleaseFileExtentsCB, ExtentCount) + sizeof(ULONG) +
2149 sizeof (AFSFileExtentCB) * pExtents->ExtentCount))
2152 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2153 AFS_TRACE_LEVEL_ERROR,
2154 "AFSProcessReleaseFileExtents Buffer too small for FID %08lX:%08lx:%08lX:%08lX\n",
2155 pExtents->FileId.Cell,
2156 pExtents->FileId.Volume,
2157 pExtents->FileId.Vnode,
2158 pExtents->FileId.Unique);
2160 try_return( ntStatus = STATUS_INVALID_PARAMETER );
2163 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2164 AFS_TRACE_LEVEL_VERBOSE,
2165 "AFSProcessReleaseFileExtents Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n",
2166 &pDevExt->Specific.RDR.VolumeTreeLock,
2167 PsGetCurrentThread());
2169 AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
2172 // Locate the volume node
2175 ullIndex = AFSCreateHighIndex( &pExtents->FileId);
2177 ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
2179 (AFSBTreeEntry **)&pVolumeCB);
2181 if( pVolumeCB != NULL)
2184 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2185 AFS_TRACE_LEVEL_VERBOSE,
2186 "AFSProcessReleaseFileExtents Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n",
2187 pVolumeCB->ObjectInfoTree.TreeLock,
2188 PsGetCurrentThread());
2190 lCount = InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
2193 AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
2195 if( !NT_SUCCESS( ntStatus) ||
2199 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2200 AFS_TRACE_LEVEL_ERROR,
2201 "AFSProcessReleaseFileExtents Invalid volume index %I64X status %08X\n",
2202 ullIndex, ntStatus);
2204 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2207 AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
2210 lCount = InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
2213 // Now locate the Object in this volume
2216 ullIndex = AFSCreateLowIndex( &pExtents->FileId);
2218 ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
2220 (AFSBTreeEntry **)&pObjectInfo);
2222 if( pObjectInfo != NULL)
2226 // Reference the node so it won't be torn down
2229 lCount = InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
2231 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2232 AFS_TRACE_LEVEL_VERBOSE,
2233 "AFSProcessReleaseFileExtents Increment count on object %08lX Cnt %d\n",
2238 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
2240 if( !NT_SUCCESS( ntStatus) ||
2241 pObjectInfo == NULL)
2244 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2245 AFS_TRACE_LEVEL_ERROR,
2246 "AFSProcessReleaseFileExtents Invalid file index %I64X\n",
2249 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2252 pFcb = pObjectInfo->Fcb;
2257 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2258 AFS_TRACE_LEVEL_ERROR,
2259 "AFSProcessReleaseFileExtents Fcb not initialied (NO EXTENTS) for FID %08lX:%08lx:%08lX:%08lX\n",
2260 pExtents->FileId.Cell,
2261 pExtents->FileId.Volume,
2262 pExtents->FileId.Vnode,
2263 pExtents->FileId.Unique);
2265 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2268 AFSLockForExtentsTrim( pFcb );
2276 // Locate an Fcb to trim down
2279 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2280 AFS_TRACE_LEVEL_VERBOSE,
2281 "AFSProcessReleaseFileExtents Searching for a Fcb to Trim Down\n");
2283 pFcb = AFSFindFcbToClean( 0, NULL, FALSE);
2288 pFcb = AFSFindFcbToClean( 0, NULL, TRUE);
2294 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2295 AFS_TRACE_LEVEL_ERROR,
2296 "AFSProcessReleaseFileExtents Failed to locate Fcb for release ...\n");
2298 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2301 pObjectInfo = pFcb->ObjectInformation;
2307 // Allocate a scratch buffer to move in the extent information
2310 ulSz = (pExtents->ExtentCount-1) * sizeof(AFSFileExtentCB);
2311 ulSz += sizeof(AFSReleaseFileExtentsResultCB);
2313 if (ulSz > pIrpSp->Parameters.DeviceIoControl.OutputBufferLength)
2315 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2316 AFS_TRACE_LEVEL_ERROR,
2317 "AFSProcessReleaseFileExtents OUTPUT Buffer too small [2]\n");
2319 try_return( ntStatus = STATUS_BUFFER_TOO_SMALL );
2322 pResult = (AFSReleaseFileExtentsResultCB*) AFSExAllocatePoolWithTag( PagedPool,
2324 AFS_EXTENTS_RESULT_TAG);
2325 if (NULL == pResult)
2328 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2329 AFS_TRACE_LEVEL_ERROR,
2330 "AFSProcessReleaseFileExtents Failed to allocate result block\n");
2332 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2336 // Set up the header (for an array of one)
2338 pResult->FileCount = 1;
2339 pResult->Flags = AFS_EXTENT_FLAG_RELEASE;
2340 ulSz -= FIELD_OFFSET(AFSReleaseFileExtentsResultCB, Files);
2343 // Setup the first (and only) file
2345 pFile = pResult->Files;
2346 pFile->FileId = pObjectInfo->FileId;
2347 pFile->Flags = AFS_EXTENT_FLAG_RELEASE;
2350 // Stash away the auth group
2353 RtlZeroMemory( &stAuthGroup,
2356 ntStatus = AFSRetrieveValidAuthGroup( pFcb,
2361 if( !NT_SUCCESS( ntStatus))
2363 try_return( ntStatus);
2366 RtlCopyMemory( &pFile->AuthGroup,
2371 // Update the metadata for this call
2374 pFile->AllocationSize = pFcb->ObjectInformation->EndOfFile;
2375 pFile->CreateTime = pFcb->ObjectInformation->CreationTime;
2376 pFile->ChangeTime = pFcb->ObjectInformation->ChangeTime;
2377 pFile->LastAccessTime = pFcb->ObjectInformation->LastAccessTime;
2378 pFile->LastWriteTime = pFcb->ObjectInformation->LastWriteTime;
2380 ulSz -= FIELD_OFFSET(AFSReleaseFileExtentsResultFileCB, FileExtents);
2382 ntStatus = AFSReleaseSpecifiedExtents( pExtents,
2386 &pFile->ExtentCount,
2389 if (!NT_SUCCESS(ntStatus))
2392 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2393 AFS_TRACE_LEVEL_ERROR,
2394 "AFSProcessReleaseFileExtents Failed to release extents Status %08lX\n",
2397 try_return( ntStatus );
2400 if( pExtents->ExtentCount == 0)
2403 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2404 AFS_TRACE_LEVEL_WARNING,
2405 "AFSProcessReleaseFileExtents Failed to release ANY extents\n");
2408 ulSz = sizeof(AFSReleaseFileExtentsResultCB);
2410 if( pExtents->ExtentCount > 0)
2412 ulSz += ((pExtents->ExtentCount-1) * sizeof(AFSFileExtentCB));
2415 RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer,
2424 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2425 AFS_TRACE_LEVEL_VERBOSE,
2426 "AFSProcessReleaseFileExtents Releasing Fcb extent lock %08lX thread %08lX\n",
2427 &pFcb->NPFcb->Specific.File.ExtentsResource,
2428 PsGetCurrentThread());
2430 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
2433 if( NULL != pResult &&
2434 Irp->AssociatedIrp.SystemBuffer != pResult)
2437 AFSExFreePool(pResult);
2440 if (NT_SUCCESS(ntStatus))
2442 Irp->IoStatus.Information = ulSz;
2446 Irp->IoStatus.Information = 0;
2449 Irp->IoStatus.Status = ntStatus;
2451 if( pObjectInfo != NULL)
2454 lCount = InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
2456 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2457 AFS_TRACE_LEVEL_VERBOSE,
2458 "AFSProcessReleaseFileExtents Decrement count on object %08lX Cnt %d\n",
2468 AFSWaitForExtentMapping( AFSFcb *Fcb,
2471 NTSTATUS ntStatus = STATUS_SUCCESS;
2472 LARGE_INTEGER liTimeOut;
2473 ULONGLONG ullProcessId = (ULONGLONG)PsGetCurrentProcessId();
2478 ASSERT( !ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
2480 if (!NT_SUCCESS( Fcb->NPFcb->Specific.File.ExtentsRequestStatus))
2484 // If this isn't the same authgroup which caused the failure
2485 // then try to request them again
2488 if( RtlCompareMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2490 sizeof( GUID)) == sizeof( GUID))
2493 ntStatus = Fcb->NPFcb->Specific.File.ExtentsRequestStatus;
2495 Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
2497 RtlZeroMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2500 try_return( ntStatus);
2504 liTimeOut.QuadPart = -(1 * AFS_ONE_SECOND);
2506 ntStatus = KeWaitForSingleObject( &Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
2512 if (!NT_SUCCESS( Fcb->NPFcb->Specific.File.ExtentsRequestStatus))
2516 // If this isn't the same authgroup which caused the failure
2517 // or the System Process,
2518 // then try to request the extents again
2521 if( RtlCompareMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2523 sizeof( GUID)) == sizeof( GUID) ||
2524 ullProcessId == (ULONGLONG)AFSSysProcess)
2527 ntStatus = Fcb->NPFcb->Specific.File.ExtentsRequestStatus;
2529 Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
2531 RtlZeroMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2534 try_return( ntStatus);
2538 if( ntStatus == STATUS_TIMEOUT)
2541 ntStatus = STATUS_SUCCESS;
2553 AFSFlushExtents( IN AFSFcb *Fcb,
2556 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
2557 AFSExtent *pExtent, *pNextExtent;
2559 AFSReleaseExtentsCB *pRelease = NULL;
2561 ULONG initialDirtyCount = 0;
2562 BOOLEAN bExtentsLocked = FALSE;
2565 NTSTATUS ntStatus = STATUS_SUCCESS;
2566 LARGE_INTEGER liLastFlush;
2567 AFSExtent *pDirtyListHead = NULL, *pDirtyListTail = NULL;
2568 AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2569 GUID *pAuthGroup = AuthGroup;
2573 ASSERT( Fcb->Header.NodeTypeCode == AFS_FILE_FCB);
2576 // Save, then reset the flush time
2579 liLastFlush = Fcb->Specific.File.LastServerFlush;
2581 KeQueryTickCount( &Fcb->Specific.File.LastServerFlush);
2586 if( pAuthGroup == NULL ||
2587 RtlCompareMemory( pAuthGroup,
2588 &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2589 sizeof( GUID)) == sizeof( GUID))
2592 RtlZeroMemory( &stAuthGroup,
2595 ntStatus = AFSRetrieveValidAuthGroup( Fcb,
2600 if( !NT_SUCCESS( ntStatus))
2602 try_return( ntStatus);
2605 pAuthGroup = &stAuthGroup;
2609 // Lock extents while we count and set up the array to send to
2613 AFSLockForExtentsTrim( Fcb);
2615 bExtentsLocked = TRUE;
2617 lCount = InterlockedIncrement( &Fcb->Specific.File.QueuedFlushCount);
2620 // Clear our queued flush event
2623 KeClearEvent( &Fcb->NPFcb->Specific.File.QueuedFlushEvent);
2626 // Look for a start in the list to flush entries
2631 sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
2633 pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
2635 AFS_EXTENT_RELEASE_TAG);
2636 if( NULL == pRelease)
2639 try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2642 initialDirtyCount = Fcb->Specific.File.ExtentsDirtyCount;
2644 while( Fcb->Specific.File.ExtentsDirtyCount > 0)
2647 pRelease->Flags = AFS_EXTENT_FLAG_DIRTY;
2649 if( BooleanFlagOn( Fcb->Flags, AFS_FCB_FILE_CLOSED))
2652 pRelease->Flags |= AFS_EXTENT_FLAG_FLUSH;
2656 // Update the metadata for this call
2659 pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
2660 pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
2661 pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
2662 pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
2663 pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
2667 AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
2670 pExtent = (AFSExtent *)pNPFcb->Specific.File.DirtyListHead;
2672 while( count < AFS_MAXIMUM_EXTENT_RELEASE_COUNT)
2675 if ( pExtent == NULL)
2681 pNextExtent = (AFSExtent *)pExtent->DirtyList.fLink;
2683 if ( pExtent->ActiveCount > 0)
2685 pExtent = pNextExtent;
2689 AFSRemoveEntryDirtyList( Fcb, pExtent);
2691 pExtent->DirtyList.fLink = NULL;
2692 pExtent->DirtyList.bLink = NULL;
2694 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
2697 // Clear the flag in advance of the write. If we do
2698 // things this was we know that the clear is
2699 // pessimistic (any write which happens from now on
2700 // will set the flag dirty again).
2703 pExtent->Flags &= ~AFS_EXTENT_DIRTY;
2705 pRelease->FileExtents[count].Flags = AFS_EXTENT_FLAG_DIRTY;
2707 pRelease->FileExtents[count].Length = pExtent->Size;
2708 pRelease->FileExtents[count].DirtyLength = pExtent->Size;
2709 pRelease->FileExtents[count].DirtyOffset = 0;
2710 pRelease->FileExtents[count].CacheOffset = pExtent->CacheOffset;
2711 pRelease->FileExtents[count].FileOffset = pExtent->FileOffset;
2714 RtlCopyMemory( pRelease->FileExtents[count].MD5,
2716 sizeof(pExtent->MD5));
2718 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_MD5_SET;
2721 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2722 AFS_TRACE_LEVEL_VERBOSE,
2723 "AFSFlushExtents Releasing DIRTY extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
2725 Fcb->ObjectInformation->FileId.Cell,
2726 Fcb->ObjectInformation->FileId.Volume,
2727 Fcb->ObjectInformation->FileId.Vnode,
2728 Fcb->ObjectInformation->FileId.Unique,
2729 pExtent->FileOffset.QuadPart,
2732 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_RELEASE;
2735 // Need to pull this extent from the main list as well
2738 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
2740 if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
2742 RemoveEntryList( &pExtent->Lists[i] );
2746 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
2748 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
2750 AFSExFreePool( pExtent);
2752 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
2754 lCount = InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount);
2759 KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
2766 pExtent = pNextExtent;
2769 AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
2772 // If we are done then get out
2778 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2779 AFS_TRACE_LEVEL_VERBOSE,
2780 "AFSFlushExtents No more dirty extents found\n");
2786 // Fire off the request synchronously
2789 sz = sizeof( AFSReleaseExtentsCB ) + (count * sizeof ( AFSFileExtentCB ));
2791 pRelease->ExtentCount = count;
2793 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2794 AFS_TRACE_LEVEL_VERBOSE,
2795 "AFSFlushExtents Releasing(1) Fcb extents lock %08lX SHARED %08lX\n",
2796 &pNPFcb->Specific.File.ExtentsResource,
2797 PsGetCurrentThread());
2799 AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource);
2800 bExtentsLocked = FALSE;
2802 KeSetEvent( &pNPFcb->Specific.File.FlushEvent,
2806 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS,
2807 AFS_REQUEST_FLAG_SYNCHRONOUS,
2810 &Fcb->ObjectInformation->FileId,
2816 if( !NT_SUCCESS(ntStatus))
2820 // Regardless of whether or not the AFSProcessRequest() succeeded, the extents
2821 // were released (if AFS_EXTENT_FLAG_RELEASE was set). Log the error so it is known.
2824 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2825 AFS_TRACE_LEVEL_ERROR,
2826 "AFSFlushExtents AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
2827 Fcb->ObjectInformation->FileId.Cell,
2828 Fcb->ObjectInformation->FileId.Volume,
2829 Fcb->ObjectInformation->FileId.Vnode,
2830 Fcb->ObjectInformation->FileId.Unique,
2834 AFSLockForExtentsTrim( Fcb);
2836 bExtentsLocked = TRUE;
2841 lCount = InterlockedDecrement( &Fcb->Specific.File.QueuedFlushCount);
2846 KeSetEvent( &pNPFcb->Specific.File.QueuedFlushEvent,
2851 KeSetEvent( &pNPFcb->Specific.File.FlushEvent,
2858 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2859 AFS_TRACE_LEVEL_VERBOSE,
2860 "AFSFlushExtents Releasing(2) Fcb extents lock %08lX SHARED %08lX\n",
2861 &pNPFcb->Specific.File.ExtentsResource,
2862 PsGetCurrentThread());
2864 AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
2869 AFSExFreePool( pRelease);
2877 AFSReleaseExtentsWithFlush( IN AFSFcb *Fcb,
2880 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
2883 AFSReleaseExtentsCB *pRelease = NULL;
2885 ULONG initialDirtyCount = 0;
2886 BOOLEAN bExtentsLocked = FALSE;
2889 NTSTATUS ntStatus = STATUS_SUCCESS;
2890 LARGE_INTEGER liLastFlush;
2891 ULONG ulRemainingExtentLength = 0;
2892 AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2893 GUID *pAuthGroup = AuthGroup;
2897 ASSERT( Fcb->Header.NodeTypeCode == AFS_FILE_FCB);
2900 // Save, then reset the flush time
2903 liLastFlush = Fcb->Specific.File.LastServerFlush;
2905 KeQueryTickCount( &Fcb->Specific.File.LastServerFlush);
2910 if( pAuthGroup == NULL ||
2911 RtlCompareMemory( pAuthGroup,
2912 &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2913 sizeof( GUID)) == sizeof( GUID))
2916 RtlZeroMemory( &stAuthGroup,
2919 ntStatus = AFSRetrieveValidAuthGroup( Fcb,
2924 if( !NT_SUCCESS( ntStatus))
2926 try_return( ntStatus);
2929 pAuthGroup = &stAuthGroup;
2933 // Look for a start in the list to flush entries
2938 sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
2940 pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
2942 AFS_EXTENT_RELEASE_TAG);
2943 if( NULL == pRelease)
2946 try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2949 if( Fcb->OpenHandleCount > 0)
2953 // Don't release everything ...
2957 // For now release everything
2960 //ulRemainingExtentLength = 1500;
2963 while( Fcb->Specific.File.ExtentLength > (LONG)ulRemainingExtentLength)
2966 AFSLockForExtentsTrim( Fcb);
2968 bExtentsLocked = TRUE;
2970 pRelease->Flags = AFS_EXTENT_FLAG_RELEASE;
2973 // Update the metadata for this call
2976 pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
2977 pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
2978 pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
2979 pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
2980 pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
2984 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
2986 while( count < AFS_MAXIMUM_EXTENT_RELEASE_COUNT &&
2987 le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
2990 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
2994 if( pExtent->ActiveCount > 0)
3000 pRelease->FileExtents[count].Flags = AFS_EXTENT_FLAG_RELEASE;
3002 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3003 AFS_TRACE_LEVEL_VERBOSE,
3004 "AFSReleaseExtentsWithFlush Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
3006 Fcb->ObjectInformation->FileId.Cell,
3007 Fcb->ObjectInformation->FileId.Volume,
3008 Fcb->ObjectInformation->FileId.Vnode,
3009 Fcb->ObjectInformation->FileId.Unique,
3010 pExtent->FileOffset.QuadPart,
3013 pRelease->FileExtents[count].Length = pExtent->Size;
3014 pRelease->FileExtents[count].DirtyLength = pExtent->Size;
3015 pRelease->FileExtents[count].DirtyOffset = 0;
3016 pRelease->FileExtents[count].CacheOffset = pExtent->CacheOffset;
3017 pRelease->FileExtents[count].FileOffset = pExtent->FileOffset;
3020 RtlCopyMemory( pRelease->FileExtents[count].MD5,
3022 sizeof(pExtent->MD5));
3024 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_MD5_SET;
3027 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3030 AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
3033 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3036 AFSRemoveEntryDirtyList( Fcb,
3039 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_DIRTY;
3041 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
3044 AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
3048 // Need to pull this extent from the main list as well
3051 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
3053 if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
3055 RemoveEntryList( &pExtent->Lists[i] );
3059 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
3061 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
3063 AFSExFreePool( pExtent);
3065 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
3067 lCount = InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount);
3072 KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
3081 // If we are done then get out
3087 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3088 AFS_TRACE_LEVEL_VERBOSE,
3089 "AFSReleaseExtentsWithFlush No more dirty extents found\n");
3095 // Fire off the request synchronously
3098 sz = sizeof( AFSReleaseExtentsCB ) + (count * sizeof ( AFSFileExtentCB ));
3100 pRelease->ExtentCount = count;
3103 // Drop the extents lock for the duration of the call to
3104 // the network. We have pinned the extents so, even
3105 // though we might get extents added during this period,
3106 // but none will be removed. Hence we can carry on from