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)
1017 try_return (ntStatus = STATUS_INSUFFICIENT_RESOURCES );
1020 RtlZeroMemory( pExtent, sizeof( AFSExtent ));
1022 pExtent->FileOffset = pFileExtents->FileOffset;
1023 pExtent->CacheOffset = pFileExtents->CacheOffset;
1024 pExtent->Size = pFileExtents->Length;
1026 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1027 AFS_TRACE_LEVEL_VERBOSE,
1028 "AFSProcessExtentsResult Received extent for fid %08lX-%08lX-%08lX-%08lX File Offset %I64X Cache Offset %I64X Len %08lX\n",
1029 Fcb->ObjectInformation->FileId.Cell,
1030 Fcb->ObjectInformation->FileId.Volume,
1031 Fcb->ObjectInformation->FileId.Vnode,
1032 Fcb->ObjectInformation->FileId.Unique,
1033 pFileExtents->FileOffset.QuadPart,
1034 pFileExtents->CacheOffset.QuadPart,
1035 pFileExtents->Length);
1037 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, (LONG)(pExtent->Size/1024));
1039 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, (LONG)(pExtent->Size/1024));
1041 lCount = InterlockedIncrement( &Fcb->Specific.File.ExtentCount);
1043 lCount = InterlockedIncrement( &pControlDevExt->Specific.Control.ExtentCount);
1048 KeClearEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent);
1054 InsertHeadList(le, &pExtent->Lists[AFS_EXTENTS_LIST]);
1055 ASSERT(le->Flink == &pExtent->Lists[AFS_EXTENTS_LIST]);
1056 ASSERT(0 == (pExtent->FileOffset.LowPart & ExtentsMasks[AFS_EXTENTS_LIST]));
1059 // Do not move the cursor - we will do it next time
1063 // And into the (upper) skip lists - Again, do not move the cursor
1065 for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--)
1067 if (0 == (pExtent->FileOffset.LowPart & ExtentsMasks[i]))
1069 InsertHeadList(pSkipEntries[i], &pExtent->Lists[i]);
1070 #if AFS_VALIDATE_EXTENTS
1071 VerifyExtentsLists(Fcb);
1076 else if (pExtent->FileOffset.QuadPart == pFileExtents->FileOffset.QuadPart)
1079 if (pExtent->Size != pFileExtents->Length)
1082 ASSERT (pExtent->Size == pFileExtents->Length);
1084 try_return (ntStatus = STATUS_INVALID_PARAMETER);
1088 // Move both cursors forward.
1090 // First the extent pointer
1093 le = &pExtent->Lists[AFS_EXTENTS_LIST];
1096 // Then the skip lists cursors forward if needed
1098 for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--)
1100 if (0 == (pExtent->FileOffset.LowPart & ExtentsMasks[i]))
1103 // Check sanity before
1105 #if AFS_VALIDATE_EXTENTS
1106 VerifyExtentsLists(Fcb);
1110 // Skip list should point to us
1112 //ASSERT(pSkipEntries[i] == &pExtent->Lists[i]);
1114 // Move forward cursor
1116 pSkipEntries[i] = pSkipEntries[i]->Flink;
1118 // Check sanity before
1120 #if AFS_VALIDATE_EXTENTS
1121 VerifyExtentsLists(Fcb);
1127 // And then the cursor in the supplied array
1133 // setup pExtent if there is one
1135 if (le->Flink != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
1137 pExtent = NextExtent( pExtent, AFS_EXTENTS_LIST ) ;
1147 ASSERT( pExtent->FileOffset.QuadPart < pFileExtents->FileOffset.QuadPart );
1150 // Sanity check on spanning
1152 if ((pExtent->FileOffset.QuadPart + pExtent->Size) >
1153 pFileExtents->FileOffset.QuadPart)
1156 ASSERT( (pExtent->FileOffset.QuadPart + pExtent->Size) <=
1157 pFileExtents->FileOffset.QuadPart);
1159 try_return (ntStatus = STATUS_INVALID_PARAMETER);
1163 // Move le and pExtent forward
1165 le = &pExtent->Lists[AFS_EXTENTS_LIST];
1169 // Then the check the skip lists cursors
1171 for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--)
1173 if (0 == (pFileExtents->FileOffset.LowPart & ExtentsMasks[i]))
1177 // - empty list (pSkipEntries[i]->Flink == pSkipEntries[i]->Flink == fcb->lists[i]
1178 // - We are the last on the list (pSkipEntries[i]->Flink == fcb->lists[i])
1179 // - We are not the last on the list. In that case we have to be strictly less than
1181 if (pSkipEntries[i]->Flink != &Fcb->Specific.File.ExtentsLists[i]) {
1183 AFSExtent *otherExtent = ExtentFor(pSkipEntries[i]->Flink, i);
1184 ASSERT(pFileExtents->FileOffset.QuadPart < otherExtent->FileOffset.QuadPart);
1191 // setup pExtent if there is one
1194 if (le->Flink != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
1196 pExtent = NextExtent( pExtent, AFS_EXTENTS_LIST ) ;
1206 // All done, signal that we are done drop the lock, exit
1211 if( !NT_SUCCESS( ntStatus))
1215 // If we failed the service is going to drop all extents so trim away the
1219 AFSTrimSpecifiedExtents( Fcb,
1224 #if AFS_VALIDATE_EXTENTS
1225 VerifyExtentsLists(Fcb);
1228 KeSetEvent( &pNPFcb->Specific.File.ExtentsRequestComplete,
1232 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1233 AFS_TRACE_LEVEL_VERBOSE,
1234 "AFSProcessExtentsResult Releasing Fcb extent lock %08lX EXCL %08lX\n",
1235 &pNPFcb->Specific.File.ExtentsResource,
1236 PsGetCurrentThread());
1238 AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
1245 AFSProcessSetFileExtents( IN AFSSetFileExtentsCB *SetExtents )
1247 AFSFcb *pFcb = NULL;
1248 AFSVolumeCB *pVolumeCB = NULL;
1249 NTSTATUS ntStatus = STATUS_SUCCESS;
1250 AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1251 ULONGLONG ullIndex = 0;
1252 AFSObjectInfoCB *pObjectInfo = NULL;
1258 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1259 AFS_TRACE_LEVEL_VERBOSE,
1260 "AFSProcessSetFileExtents Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n",
1261 &pDevExt->Specific.RDR.VolumeTreeLock,
1262 PsGetCurrentThread());
1264 AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
1266 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1267 AFS_TRACE_LEVEL_VERBOSE,
1268 "AFSProcessSetFileExtents Set extents for fid %08lX-%08lX-%08lX-%08lX\n",
1269 SetExtents->FileId.Cell,
1270 SetExtents->FileId.Volume,
1271 SetExtents->FileId.Vnode,
1272 SetExtents->FileId.Unique);
1275 // Locate the volume node
1278 ullIndex = AFSCreateHighIndex( &SetExtents->FileId);
1280 ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
1282 (AFSBTreeEntry **)&pVolumeCB);
1284 if( pVolumeCB != NULL)
1287 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1288 AFS_TRACE_LEVEL_VERBOSE,
1289 "AFSProcessSetFileExtents Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n",
1290 pVolumeCB->ObjectInfoTree.TreeLock,
1291 PsGetCurrentThread());
1293 lCount = InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
1296 AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
1298 if( !NT_SUCCESS( ntStatus) ||
1302 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1303 AFS_TRACE_LEVEL_ERROR,
1304 "AFSProcessSetFileExtents Set extents for fid %08lX-%08lX-%08lX-%08lX Failed to locate volume Status %08lX\n",
1305 SetExtents->FileId.Cell,
1306 SetExtents->FileId.Volume,
1307 SetExtents->FileId.Vnode,
1308 SetExtents->FileId.Unique,
1311 try_return( ntStatus = STATUS_UNSUCCESSFUL);
1314 AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1317 lCount = InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1320 // Now locate the Object in this volume
1323 ullIndex = AFSCreateLowIndex( &SetExtents->FileId);
1325 ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
1327 (AFSBTreeEntry **)&pObjectInfo);
1329 if( pObjectInfo != NULL)
1333 // Reference the node so it won't be torn down
1336 lCount = InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
1338 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1339 AFS_TRACE_LEVEL_VERBOSE,
1340 "AFSProcessSetFileExtents Increment count on object %08lX Cnt %d\n",
1345 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1347 if( !NT_SUCCESS( ntStatus) ||
1348 pObjectInfo == NULL)
1351 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1352 AFS_TRACE_LEVEL_ERROR,
1353 "AFSProcessSetFileExtents Set extents for hash %I64X fid %08lX-%08lX-%08lX-%08lX Failed to locate file in volume %08lX\n",
1355 SetExtents->FileId.Cell,
1356 SetExtents->FileId.Volume,
1357 SetExtents->FileId.Vnode,
1358 SetExtents->FileId.Unique,
1361 try_return( ntStatus = STATUS_UNSUCCESSFUL);
1364 pFcb = pObjectInfo->Fcb;
1367 // If we have a result failure then don't bother trying to set the extents
1370 if( SetExtents->ResultStatus != STATUS_SUCCESS)
1373 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1374 AFS_TRACE_LEVEL_ERROR,
1375 "AFSProcessSetFileExtents Set extents failure fid %08lX-%08lX-%08lX-%08lX ResultStatus %08lX\n",
1376 SetExtents->FileId.Cell,
1377 SetExtents->FileId.Volume,
1378 SetExtents->FileId.Vnode,
1379 SetExtents->FileId.Unique,
1380 SetExtents->ResultStatus);
1382 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1383 AFS_TRACE_LEVEL_VERBOSE,
1384 "AFSProcessSetFileExtents Acquiring Fcb extents lock %08lX EXCL %08lX\n",
1385 &pFcb->NPFcb->Specific.File.ExtentsResource,
1386 PsGetCurrentThread());
1388 AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource,
1391 pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_CANCELLED;
1393 KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete,
1397 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1398 AFS_TRACE_LEVEL_VERBOSE,
1399 "AFSProcessSetFileExtents Releasing Fcb extent lock %08lX EXCL %08lX\n",
1400 &pFcb->NPFcb->Specific.File.ExtentsResource,
1401 PsGetCurrentThread());
1403 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
1405 try_return( ntStatus);
1408 ntStatus = AFSProcessExtentsResult ( pFcb,
1409 SetExtents->ExtentCount,
1410 SetExtents->FileExtents );
1414 if( pObjectInfo != NULL)
1417 lCount = InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
1419 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1420 AFS_TRACE_LEVEL_VERBOSE,
1421 "AFSProcessSetFileExtents Decrement count on object %08lX Cnt %d\n",
1431 // Helper fuctions for Usermode initiation of release of extents
1434 AFSReleaseSpecifiedExtents( IN AFSReleaseFileExtentsCB *Extents,
1436 OUT AFSFileExtentCB *FileExtents,
1437 IN ULONG BufferSize,
1438 OUT ULONG *ExtentCount,
1439 OUT BOOLEAN *DirtyExtents)
1444 ULONG ulExtentCount = 0;
1445 NTSTATUS ntStatus = STATUS_SUCCESS;
1446 BOOLEAN bReleaseAll = FALSE;
1447 AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1452 ASSERT( ExIsResourceAcquiredExclusiveLite( &Fcb->NPFcb->Specific.File.ExtentsResource));
1454 if (BufferSize < (Extents->ExtentCount * sizeof( AFSFileExtentCB)))
1457 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1458 AFS_TRACE_LEVEL_VERBOSE,
1459 "AFSReleaseSpecifiedExtents Buffer too small\n");
1461 try_return( ntStatus = STATUS_BUFFER_TOO_SMALL);
1464 RtlZeroMemory( FileExtents, BufferSize);
1467 *DirtyExtents = FALSE;
1470 // iterate until we have dealt with all we were asked for or
1471 // are at the end of the list. Note that this deals (albeit
1472 // badly) with out of order extents
1475 pExtent = AFSExtentForOffset( Fcb,
1476 &Extents->FileExtents[0].FileOffset,
1479 if (NULL == pExtent)
1481 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1485 le = &pExtent->Lists[AFS_EXTENTS_LIST];
1489 if( BooleanFlagOn( Extents->Flags, AFS_RELEASE_EXTENTS_FLAGS_RELEASE_ALL) ||
1490 ( Extents->FileId.Cell == 0 &&
1491 Extents->FileId.Volume == 0 &&
1492 Extents->FileId.Vnode == 0 &&
1493 Extents->FileId.Unique == 0))
1499 while( le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST] &&
1500 ulExtentCount < Extents->ExtentCount)
1504 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
1509 if( pExtent->FileOffset.QuadPart < Extents->FileExtents[ulExtentCount].FileOffset.QuadPart)
1512 // Skip forward through the extent list until we get
1513 // to the one we want
1519 else if (pExtent->FileOffset.QuadPart > Extents->FileExtents[ulExtentCount].FileOffset.QuadPart)
1522 // We don't have the extent asked for so return UNKNOWN
1525 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1526 AFS_TRACE_LEVEL_VERBOSE,
1527 "AFSReleaseSpecifiedExtents Located UNKNOWN extent Offset %I64X Len %08lX\n",
1528 Extents->FileExtents[ulExtentCount].FileOffset.QuadPart,
1529 Extents->FileExtents[ulExtentCount].Length);
1531 FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_UNKNOWN;
1533 FileExtents[*ExtentCount].Length = 0;
1534 FileExtents[*ExtentCount].CacheOffset.QuadPart = 0;
1535 FileExtents[*ExtentCount].FileOffset = Extents->FileExtents[ulExtentCount].FileOffset;
1537 *ExtentCount = (*ExtentCount) + 1;
1542 // Reset where we are looking
1545 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1549 else if( pExtent->ActiveCount > 0)
1552 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1553 AFS_TRACE_LEVEL_VERBOSE,
1554 "AFSReleaseSpecifiedExtents Located IN_USE extent Offset %I64X Len %08lX\n",
1555 Extents->FileExtents[ulExtentCount].FileOffset.QuadPart,
1556 Extents->FileExtents[ulExtentCount].Length);
1558 FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_IN_USE;
1560 FileExtents[*ExtentCount].Length = 0;
1561 FileExtents[*ExtentCount].CacheOffset.QuadPart = 0;
1562 FileExtents[*ExtentCount].FileOffset = Extents->FileExtents[ulExtentCount].FileOffset;
1564 *ExtentCount = (*ExtentCount) + 1;
1569 // Reset where we are looking
1572 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1581 // If the extent is currently active then skip it
1584 if( pExtent->ActiveCount > 0)
1593 FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_RELEASE;
1595 FileExtents[*ExtentCount].Length = pExtent->Size;
1596 FileExtents[*ExtentCount].DirtyLength = pExtent->Size;
1597 FileExtents[*ExtentCount].DirtyOffset = 0;
1598 FileExtents[*ExtentCount].CacheOffset = pExtent->CacheOffset;
1599 FileExtents[*ExtentCount].FileOffset = pExtent->FileOffset;
1601 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1602 AFS_TRACE_LEVEL_VERBOSE,
1603 "AFSReleaseSpecifiedExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
1605 Fcb->ObjectInformation->FileId.Cell,
1606 Fcb->ObjectInformation->FileId.Volume,
1607 Fcb->ObjectInformation->FileId.Vnode,
1608 Fcb->ObjectInformation->FileId.Unique,
1609 FileExtents[*ExtentCount].FileOffset.QuadPart,
1610 FileExtents[*ExtentCount].Length);
1612 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
1615 AFSAcquireExcl( &Fcb->NPFcb->Specific.File.DirtyExtentsListLock,
1618 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
1621 AFSRemoveEntryDirtyList( Fcb,
1624 FileExtents[*ExtentCount].Flags |= AFS_EXTENT_FLAG_DIRTY;
1626 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
1628 *DirtyExtents = TRUE;
1631 AFSReleaseResource( &Fcb->NPFcb->Specific.File.DirtyExtentsListLock);
1635 // move forward all three cursors
1639 *ExtentCount = (*ExtentCount) + 1;
1644 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
1646 if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
1648 RemoveEntryList( &pExtent->Lists[i] );
1652 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
1654 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
1659 AFSExFreePool( pExtent);
1661 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
1663 lCount = InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount);
1668 KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
1683 AFSFindFcbToClean(ULONG IgnoreTime, AFSFcb *LastFcb, BOOLEAN Block)
1686 AFSFcb *pFcb = NULL;
1687 AFSVolumeCB *pVolumeCB = NULL;
1688 AFSDeviceExt *pRDRDeviceExt = NULL;
1689 AFSDeviceExt *pControlDeviceExt = NULL;
1690 BOOLEAN bLocatedEntry = FALSE;
1691 AFSObjectInfoCB *pCurrentObject = NULL;
1692 BOOLEAN bReleaseVolumeListLock = FALSE;
1695 pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1696 pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1698 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1699 AFS_TRACE_LEVEL_VERBOSE,
1700 "AFSFindFcbToClean Acquiring RDR VolumeListLock lock %08lX SHARED %08lX\n",
1701 &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1702 PsGetCurrentThread());
1704 AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1707 bReleaseVolumeListLock = TRUE;
1709 pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead;
1711 while( pVolumeCB != NULL)
1715 // The Volume list may move under our feet. Lock it.
1718 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1719 AFS_TRACE_LEVEL_VERBOSE,
1720 "AFSFindFcbToClean Acquiring VolumeRoot ObjectInfoTree lock %08lX SHARED %08lX\n",
1721 pVolumeCB->ObjectInfoTree.TreeLock,
1722 PsGetCurrentThread());
1724 lCount = InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
1726 AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1728 bReleaseVolumeListLock = FALSE;
1730 AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1733 lCount = InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1735 if( NULL == LastFcb)
1738 pCurrentObject = pVolumeCB->ObjectInfoListHead;
1743 pCurrentObject = (AFSObjectInfoCB *)LastFcb->ObjectInformation->ListEntry.fLink;
1748 while( pCurrentObject != NULL)
1751 pFcb = (AFSFcb *)pCurrentObject->Fcb;
1754 // If the FCB is a candidate we try to lock it (but without waiting - which
1755 // means we are deadlock free
1759 pFcb->Header.NodeTypeCode == AFS_FILE_FCB)
1765 AFSLockForExtentsTrim( pFcb);
1770 if( !AFSLockForExtentsTrimNoWait( pFcb))
1773 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1782 // Need to be sure there are no current flushes in the queue
1785 if( pFcb->Specific.File.ExtentCount == 0)
1788 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1789 AFS_TRACE_LEVEL_VERBOSE,
1790 "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n",
1791 &pFcb->NPFcb->Specific.File.ExtentsResource,
1792 PsGetCurrentThread());
1794 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
1796 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1803 if( pFcb->Specific.File.QueuedFlushCount > 0)
1806 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1807 AFS_TRACE_LEVEL_VERBOSE,
1808 "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n",
1809 &pFcb->NPFcb->Specific.File.ExtentsResource,
1810 PsGetCurrentThread());
1812 AFSReleaseResource(&pFcb->NPFcb->Specific.File.ExtentsResource);
1816 AFSWaitOnQueuedFlushes( pFcb);
1821 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1829 if( pFcb->OpenHandleCount > 0)
1832 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1833 AFS_TRACE_LEVEL_VERBOSE,
1834 "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n",
1835 &pFcb->NPFcb->Specific.File.ExtentsResource,
1836 PsGetCurrentThread());
1838 AFSReleaseResource(&pFcb->NPFcb->Specific.File.ExtentsResource);
1840 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1848 // A hit a very palpable hit. Pin it
1851 lCount = InterlockedIncrement( &pCurrentObject->ObjectReferenceCount);
1853 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1854 AFS_TRACE_LEVEL_VERBOSE,
1855 "AFSFindFcbToClean Increment count on Fcb %08lX Cnt %d\n",
1859 bLocatedEntry = TRUE;
1864 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1869 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1876 AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1879 bReleaseVolumeListLock = TRUE;
1881 pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1884 if( bReleaseVolumeListLock)
1887 AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1894 AFSProcessExtentFailure( PIRP Irp)
1896 AFSExtentFailureCB *pFailureCB = NULL;
1897 NTSTATUS ntStatus = STATUS_SUCCESS;
1898 AFSDeviceExt *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension;
1899 PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1900 AFSVolumeCB *pVolumeCB = NULL;
1901 ULONGLONG ullIndex = 0;
1902 AFSObjectInfoCB *pObjectInfo = NULL;
1907 if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSExtentFailureCB))
1910 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1911 AFS_TRACE_LEVEL_ERROR,
1912 "AFSProcessExtentFailure Input buffer too small\n");
1914 try_return( ntStatus = STATUS_INVALID_PARAMETER);
1917 pFailureCB = (AFSExtentFailureCB *)Irp->AssociatedIrp.SystemBuffer;
1919 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1920 AFS_TRACE_LEVEL_ERROR,
1921 "AFSProcessExtentFailure Service Reports Failure fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
1922 pFailureCB->FileId.Cell,
1923 pFailureCB->FileId.Volume,
1924 pFailureCB->FileId.Vnode,
1925 pFailureCB->FileId.Unique,
1926 pFailureCB->FailureStatus);
1928 AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
1931 // Locate the volume node
1934 ullIndex = AFSCreateHighIndex( &pFailureCB->FileId);
1936 ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
1938 (AFSBTreeEntry **)&pVolumeCB);
1940 if( pVolumeCB != NULL)
1943 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1944 AFS_TRACE_LEVEL_VERBOSE,
1945 "AFSProcessExtentFailure Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n",
1946 pVolumeCB->ObjectInfoTree.TreeLock,
1947 PsGetCurrentThread());
1949 lCount = InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
1952 AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
1954 if( !NT_SUCCESS( ntStatus) ||
1958 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1959 AFS_TRACE_LEVEL_ERROR,
1960 "AFSProcessExtentFailure Invalid volume index %I64X status %08X\n",
1961 ullIndex, ntStatus);
1963 try_return( ntStatus = STATUS_UNSUCCESSFUL);
1966 AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1969 lCount = InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1972 // Now locate the Object in this volume
1975 ullIndex = AFSCreateLowIndex( &pFailureCB->FileId);
1977 ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
1979 (AFSBTreeEntry **)&pObjectInfo);
1981 if( pObjectInfo != NULL &&
1982 pObjectInfo->Fcb != NULL)
1986 // Reference the node so it won't be torn down
1989 lCount = InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
1991 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1992 AFS_TRACE_LEVEL_VERBOSE,
1993 "AFSProcessExtentFailure Increment count on object %08lX Cnt %d\n",
1998 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
2000 if( !NT_SUCCESS( ntStatus) ||
2001 pObjectInfo == NULL ||
2002 pObjectInfo->Fcb == NULL)
2005 if( pObjectInfo == NULL)
2007 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2008 AFS_TRACE_LEVEL_ERROR,
2009 "AFSProcessExtentFailure Invalid file index %I64X\n",
2014 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2015 AFS_TRACE_LEVEL_ERROR,
2016 "AFSProcessExtentFailure Fcb dealocated for %I64X\n",
2020 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2023 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2024 AFS_TRACE_LEVEL_VERBOSE,
2025 "AFSProcessExtentFailure Acquiring Fcb extent lock %08lX EXCL %08lX\n",
2026 &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
2027 PsGetCurrentThread());
2029 AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
2032 pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = pFailureCB->FailureStatus;
2034 RtlCopyMemory( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2035 &pFailureCB->AuthGroup,
2038 KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
2042 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2043 AFS_TRACE_LEVEL_VERBOSE,
2044 "AFSProcessExtentFailure Releasing Fcb extent lock %08lX EXCL %08lX\n",
2045 &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
2046 PsGetCurrentThread());
2048 AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource);
2050 lCount = InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
2052 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2053 AFS_TRACE_LEVEL_VERBOSE,
2054 "AFSProcessExtentFailure Decrement count on object %08lX Cnt %d\n",
2067 AFSProcessReleaseFileExtents( IN PIRP Irp)
2069 NTSTATUS ntStatus = STATUS_SUCCESS;
2070 PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
2071 PFILE_OBJECT pFileObject = pIrpSp->FileObject;
2072 AFSFcb *pFcb = NULL;
2073 AFSVolumeCB *pVolumeCB = NULL;
2074 AFSDeviceExt *pDevExt;
2075 AFSReleaseFileExtentsCB *pExtents;
2076 AFSReleaseFileExtentsResultCB *pResult = NULL;
2077 AFSReleaseFileExtentsResultFileCB *pFile = NULL;
2079 ULONGLONG ullIndex = 0;
2080 AFSObjectInfoCB *pObjectInfo = NULL;
2081 BOOLEAN bLocked = FALSE;
2082 BOOLEAN bDirtyExtents = FALSE;
2089 pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension;
2091 pExtents = (AFSReleaseFileExtentsCB*) Irp->AssociatedIrp.SystemBuffer;
2093 if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2094 sizeof( AFSReleaseFileExtentsCB))
2097 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2098 AFS_TRACE_LEVEL_ERROR,
2099 "AFSProcessReleaseFileExtents INPUT Buffer too small\n");
2101 try_return( ntStatus = STATUS_INVALID_PARAMETER );
2104 if ( pIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
2105 sizeof(AFSReleaseFileExtentsResultCB))
2108 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2109 AFS_TRACE_LEVEL_ERROR,
2110 "AFSProcessReleaseFileExtents OUTPUT Buffer too small [1]\n");
2113 // Must have space for one extent in one file
2116 try_return( ntStatus = STATUS_BUFFER_TOO_SMALL);
2119 if (pExtents->ExtentCount == 0)
2122 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2123 AFS_TRACE_LEVEL_ERROR,
2124 "AFSProcessReleaseFileExtents Extent count zero\n");
2126 try_return( ntStatus = STATUS_INVALID_PARAMETER);
2129 if (pExtents->FileId.Cell != 0 ||
2130 pExtents->FileId.Volume != 0 ||
2131 pExtents->FileId.Vnode != 0 ||
2132 pExtents->FileId.Unique != 0)
2135 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2136 AFS_TRACE_LEVEL_VERBOSE,
2137 "AFSProcessReleaseFileExtents Processing FID %08lX:%08lX:%08lX:%08lX\n",
2138 pExtents->FileId.Cell,
2139 pExtents->FileId.Volume,
2140 pExtents->FileId.Vnode,
2141 pExtents->FileId.Unique);
2143 if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2144 ( FIELD_OFFSET( AFSReleaseFileExtentsCB, ExtentCount) + sizeof(ULONG)) ||
2145 pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2146 ( FIELD_OFFSET( AFSReleaseFileExtentsCB, ExtentCount) + sizeof(ULONG) +
2147 sizeof (AFSFileExtentCB) * pExtents->ExtentCount))
2150 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2151 AFS_TRACE_LEVEL_ERROR,
2152 "AFSProcessReleaseFileExtents Buffer too small for FID %08lX:%08lx:%08lX:%08lX\n",
2153 pExtents->FileId.Cell,
2154 pExtents->FileId.Volume,
2155 pExtents->FileId.Vnode,
2156 pExtents->FileId.Unique);
2158 try_return( ntStatus = STATUS_INVALID_PARAMETER );
2161 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2162 AFS_TRACE_LEVEL_VERBOSE,
2163 "AFSProcessReleaseFileExtents Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n",
2164 &pDevExt->Specific.RDR.VolumeTreeLock,
2165 PsGetCurrentThread());
2167 AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
2170 // Locate the volume node
2173 ullIndex = AFSCreateHighIndex( &pExtents->FileId);
2175 ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
2177 (AFSBTreeEntry **)&pVolumeCB);
2179 if( pVolumeCB != NULL)
2182 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2183 AFS_TRACE_LEVEL_VERBOSE,
2184 "AFSProcessReleaseFileExtents Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n",
2185 pVolumeCB->ObjectInfoTree.TreeLock,
2186 PsGetCurrentThread());
2188 lCount = InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
2191 AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
2193 if( !NT_SUCCESS( ntStatus) ||
2197 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2198 AFS_TRACE_LEVEL_ERROR,
2199 "AFSProcessReleaseFileExtents Invalid volume index %I64X status %08X\n",
2200 ullIndex, ntStatus);
2202 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2205 AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
2208 lCount = InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
2211 // Now locate the Object in this volume
2214 ullIndex = AFSCreateLowIndex( &pExtents->FileId);
2216 ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
2218 (AFSBTreeEntry **)&pObjectInfo);
2220 if( pObjectInfo != NULL)
2224 // Reference the node so it won't be torn down
2227 lCount = InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
2229 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2230 AFS_TRACE_LEVEL_VERBOSE,
2231 "AFSProcessReleaseFileExtents Increment count on object %08lX Cnt %d\n",
2236 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
2238 if( !NT_SUCCESS( ntStatus) ||
2239 pObjectInfo == NULL)
2242 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2243 AFS_TRACE_LEVEL_ERROR,
2244 "AFSProcessReleaseFileExtents Invalid file index %I64X\n",
2247 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2250 pFcb = pObjectInfo->Fcb;
2255 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2256 AFS_TRACE_LEVEL_ERROR,
2257 "AFSProcessReleaseFileExtents Fcb not initialied (NO EXTENTS) for FID %08lX:%08lx:%08lX:%08lX\n",
2258 pExtents->FileId.Cell,
2259 pExtents->FileId.Volume,
2260 pExtents->FileId.Vnode,
2261 pExtents->FileId.Unique);
2263 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2266 AFSLockForExtentsTrim( pFcb );
2274 // Locate an Fcb to trim down
2277 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2278 AFS_TRACE_LEVEL_VERBOSE,
2279 "AFSProcessReleaseFileExtents Searching for a Fcb to Trim Down\n");
2281 pFcb = AFSFindFcbToClean( 0, NULL, FALSE);
2286 pFcb = AFSFindFcbToClean( 0, NULL, TRUE);
2292 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2293 AFS_TRACE_LEVEL_ERROR,
2294 "AFSProcessReleaseFileExtents Failed to locate Fcb for release ...\n");
2296 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2299 pObjectInfo = pFcb->ObjectInformation;
2305 // Allocate a scratch buffer to move in the extent information
2308 ulSz = (pExtents->ExtentCount-1) * sizeof(AFSFileExtentCB);
2309 ulSz += sizeof(AFSReleaseFileExtentsResultCB);
2311 if (ulSz > pIrpSp->Parameters.DeviceIoControl.OutputBufferLength)
2313 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2314 AFS_TRACE_LEVEL_ERROR,
2315 "AFSProcessReleaseFileExtents OUTPUT Buffer too small [2]\n");
2317 try_return( ntStatus = STATUS_BUFFER_TOO_SMALL );
2320 pResult = (AFSReleaseFileExtentsResultCB*) AFSExAllocatePoolWithTag( PagedPool,
2322 AFS_EXTENTS_RESULT_TAG);
2323 if (NULL == pResult)
2326 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2327 AFS_TRACE_LEVEL_ERROR,
2328 "AFSProcessReleaseFileExtents Failed to allocate result block\n");
2330 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2334 // Set up the header (for an array of one)
2336 pResult->FileCount = 1;
2337 pResult->Flags = AFS_EXTENT_FLAG_RELEASE;
2338 ulSz -= FIELD_OFFSET(AFSReleaseFileExtentsResultCB, Files);
2341 // Setup the first (and only) file
2343 pFile = pResult->Files;
2344 pFile->FileId = pObjectInfo->FileId;
2345 pFile->Flags = AFS_EXTENT_FLAG_RELEASE;
2348 // Stash away the auth group
2351 RtlZeroMemory( &stAuthGroup,
2354 ntStatus = AFSRetrieveValidAuthGroup( pFcb,
2359 if( !NT_SUCCESS( ntStatus))
2361 try_return( ntStatus);
2364 RtlCopyMemory( &pFile->AuthGroup,
2369 // Update the metadata for this call
2372 pFile->AllocationSize = pFcb->ObjectInformation->EndOfFile;
2373 pFile->CreateTime = pFcb->ObjectInformation->CreationTime;
2374 pFile->ChangeTime = pFcb->ObjectInformation->ChangeTime;
2375 pFile->LastAccessTime = pFcb->ObjectInformation->LastAccessTime;
2376 pFile->LastWriteTime = pFcb->ObjectInformation->LastWriteTime;
2378 ulSz -= FIELD_OFFSET(AFSReleaseFileExtentsResultFileCB, FileExtents);
2380 ntStatus = AFSReleaseSpecifiedExtents( pExtents,
2384 &pFile->ExtentCount,
2387 if (!NT_SUCCESS(ntStatus))
2390 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2391 AFS_TRACE_LEVEL_ERROR,
2392 "AFSProcessReleaseFileExtents Failed to release extents Status %08lX\n",
2395 try_return( ntStatus );
2398 if( pExtents->ExtentCount == 0)
2401 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2402 AFS_TRACE_LEVEL_WARNING,
2403 "AFSProcessReleaseFileExtents Failed to release ANY extents\n");
2406 ulSz = sizeof(AFSReleaseFileExtentsResultCB);
2408 if( pExtents->ExtentCount > 0)
2410 ulSz += ((pExtents->ExtentCount-1) * sizeof(AFSFileExtentCB));
2413 RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer,
2422 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2423 AFS_TRACE_LEVEL_VERBOSE,
2424 "AFSProcessReleaseFileExtents Releasing Fcb extent lock %08lX thread %08lX\n",
2425 &pFcb->NPFcb->Specific.File.ExtentsResource,
2426 PsGetCurrentThread());
2428 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
2431 if( NULL != pResult &&
2432 Irp->AssociatedIrp.SystemBuffer != pResult)
2435 AFSExFreePool(pResult);
2438 if (NT_SUCCESS(ntStatus))
2440 Irp->IoStatus.Information = ulSz;
2444 Irp->IoStatus.Information = 0;
2447 Irp->IoStatus.Status = ntStatus;
2449 if( pObjectInfo != NULL)
2452 lCount = InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
2454 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2455 AFS_TRACE_LEVEL_VERBOSE,
2456 "AFSProcessReleaseFileExtents Decrement count on object %08lX Cnt %d\n",
2466 AFSWaitForExtentMapping( AFSFcb *Fcb,
2469 NTSTATUS ntStatus = STATUS_SUCCESS;
2470 LARGE_INTEGER liTimeOut;
2471 ULONGLONG ullProcessId = (ULONGLONG)PsGetCurrentProcessId();
2476 ASSERT( !ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
2478 if (!NT_SUCCESS( Fcb->NPFcb->Specific.File.ExtentsRequestStatus))
2482 // If this isn't the same authgroup which caused the failure
2483 // then try to request them again
2486 if( RtlCompareMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2488 sizeof( GUID)) == sizeof( GUID))
2491 ntStatus = Fcb->NPFcb->Specific.File.ExtentsRequestStatus;
2493 Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
2495 RtlZeroMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2498 try_return( ntStatus);
2502 liTimeOut.QuadPart = -(1 * AFS_ONE_SECOND);
2504 ntStatus = KeWaitForSingleObject( &Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
2510 if (!NT_SUCCESS( Fcb->NPFcb->Specific.File.ExtentsRequestStatus))
2514 // If this isn't the same authgroup which caused the failure
2515 // or the System Process,
2516 // then try to request the extents again
2519 if( RtlCompareMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2521 sizeof( GUID)) == sizeof( GUID) ||
2522 ullProcessId == (ULONGLONG)AFSSysProcess)
2525 ntStatus = Fcb->NPFcb->Specific.File.ExtentsRequestStatus;
2527 Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
2529 RtlZeroMemory( &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2532 try_return( ntStatus);
2536 if( ntStatus == STATUS_TIMEOUT)
2539 ntStatus = STATUS_SUCCESS;
2551 AFSFlushExtents( IN AFSFcb *Fcb,
2554 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
2555 AFSExtent *pExtent, *pNextExtent;
2557 AFSReleaseExtentsCB *pRelease = NULL;
2559 ULONG initialDirtyCount = 0;
2560 BOOLEAN bExtentsLocked = FALSE;
2563 NTSTATUS ntStatus = STATUS_SUCCESS;
2564 LARGE_INTEGER liLastFlush;
2565 AFSExtent *pDirtyListHead = NULL, *pDirtyListTail = NULL;
2566 AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2567 GUID *pAuthGroup = AuthGroup;
2571 ASSERT( Fcb->Header.NodeTypeCode == AFS_FILE_FCB);
2574 // Save, then reset the flush time
2577 liLastFlush = Fcb->Specific.File.LastServerFlush;
2579 KeQueryTickCount( &Fcb->Specific.File.LastServerFlush);
2584 if( pAuthGroup == NULL ||
2585 RtlCompareMemory( pAuthGroup,
2586 &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2587 sizeof( GUID)) == sizeof( GUID))
2590 RtlZeroMemory( &stAuthGroup,
2593 ntStatus = AFSRetrieveValidAuthGroup( Fcb,
2598 if( !NT_SUCCESS( ntStatus))
2600 try_return( ntStatus);
2603 pAuthGroup = &stAuthGroup;
2607 // Lock extents while we count and set up the array to send to
2611 AFSLockForExtentsTrim( Fcb);
2613 bExtentsLocked = TRUE;
2615 lCount = InterlockedIncrement( &Fcb->Specific.File.QueuedFlushCount);
2618 // Clear our queued flush event
2621 KeClearEvent( &Fcb->NPFcb->Specific.File.QueuedFlushEvent);
2624 // Look for a start in the list to flush entries
2629 sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
2631 pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
2633 AFS_EXTENT_RELEASE_TAG);
2634 if( NULL == pRelease)
2637 try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2640 initialDirtyCount = Fcb->Specific.File.ExtentsDirtyCount;
2642 while( Fcb->Specific.File.ExtentsDirtyCount > 0)
2645 pRelease->Flags = AFS_EXTENT_FLAG_DIRTY;
2647 if( BooleanFlagOn( Fcb->Flags, AFS_FCB_FILE_CLOSED))
2650 pRelease->Flags |= AFS_EXTENT_FLAG_FLUSH;
2654 // Update the metadata for this call
2657 pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
2658 pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
2659 pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
2660 pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
2661 pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
2665 AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
2668 pExtent = (AFSExtent *)pNPFcb->Specific.File.DirtyListHead;
2670 while( count < AFS_MAXIMUM_EXTENT_RELEASE_COUNT)
2673 if ( pExtent == NULL)
2679 pNextExtent = (AFSExtent *)pExtent->DirtyList.fLink;
2681 if ( pExtent->ActiveCount > 0)
2683 pExtent = pNextExtent;
2687 AFSRemoveEntryDirtyList( Fcb, pExtent);
2689 pExtent->DirtyList.fLink = NULL;
2690 pExtent->DirtyList.bLink = NULL;
2692 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
2695 // Clear the flag in advance of the write. If we do
2696 // things this was we know that the clear is
2697 // pessimistic (any write which happens from now on
2698 // will set the flag dirty again).
2701 pExtent->Flags &= ~AFS_EXTENT_DIRTY;
2703 pRelease->FileExtents[count].Flags = AFS_EXTENT_FLAG_DIRTY;
2705 pRelease->FileExtents[count].Length = pExtent->Size;
2706 pRelease->FileExtents[count].DirtyLength = pExtent->Size;
2707 pRelease->FileExtents[count].DirtyOffset = 0;
2708 pRelease->FileExtents[count].CacheOffset = pExtent->CacheOffset;
2709 pRelease->FileExtents[count].FileOffset = pExtent->FileOffset;
2712 RtlCopyMemory( pRelease->FileExtents[count].MD5,
2714 sizeof(pExtent->MD5));
2716 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_MD5_SET;
2719 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2720 AFS_TRACE_LEVEL_VERBOSE,
2721 "AFSFlushExtents Releasing DIRTY extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
2723 Fcb->ObjectInformation->FileId.Cell,
2724 Fcb->ObjectInformation->FileId.Volume,
2725 Fcb->ObjectInformation->FileId.Vnode,
2726 Fcb->ObjectInformation->FileId.Unique,
2727 pExtent->FileOffset.QuadPart,
2730 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_RELEASE;
2733 // Need to pull this extent from the main list as well
2736 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
2738 if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
2740 RemoveEntryList( &pExtent->Lists[i] );
2744 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
2746 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
2748 AFSExFreePool( pExtent);
2750 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
2752 lCount = InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount);
2757 KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
2764 pExtent = pNextExtent;
2767 AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
2770 // If we are done then get out
2776 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2777 AFS_TRACE_LEVEL_VERBOSE,
2778 "AFSFlushExtents No more dirty extents found\n");
2784 // Fire off the request synchronously
2787 sz = sizeof( AFSReleaseExtentsCB ) + (count * sizeof ( AFSFileExtentCB ));
2789 pRelease->ExtentCount = count;
2791 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2792 AFS_TRACE_LEVEL_VERBOSE,
2793 "AFSFlushExtents Releasing(1) Fcb extents lock %08lX SHARED %08lX\n",
2794 &pNPFcb->Specific.File.ExtentsResource,
2795 PsGetCurrentThread());
2797 AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource);
2798 bExtentsLocked = FALSE;
2800 KeSetEvent( &pNPFcb->Specific.File.FlushEvent,
2804 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS,
2805 AFS_REQUEST_FLAG_SYNCHRONOUS,
2808 &Fcb->ObjectInformation->FileId,
2814 if( !NT_SUCCESS(ntStatus))
2818 // Regardless of whether or not the AFSProcessRequest() succeeded, the extents
2819 // were released (if AFS_EXTENT_FLAG_RELEASE was set). Log the error so it is known.
2822 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2823 AFS_TRACE_LEVEL_ERROR,
2824 "AFSFlushExtents AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
2825 Fcb->ObjectInformation->FileId.Cell,
2826 Fcb->ObjectInformation->FileId.Volume,
2827 Fcb->ObjectInformation->FileId.Vnode,
2828 Fcb->ObjectInformation->FileId.Unique,
2832 AFSLockForExtentsTrim( Fcb);
2834 bExtentsLocked = TRUE;
2839 lCount = InterlockedDecrement( &Fcb->Specific.File.QueuedFlushCount);
2844 KeSetEvent( &pNPFcb->Specific.File.QueuedFlushEvent,
2849 KeSetEvent( &pNPFcb->Specific.File.FlushEvent,
2856 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2857 AFS_TRACE_LEVEL_VERBOSE,
2858 "AFSFlushExtents Releasing(2) Fcb extents lock %08lX SHARED %08lX\n",
2859 &pNPFcb->Specific.File.ExtentsResource,
2860 PsGetCurrentThread());
2862 AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
2867 AFSExFreePool( pRelease);
2875 AFSReleaseExtentsWithFlush( IN AFSFcb *Fcb,
2878 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
2881 AFSReleaseExtentsCB *pRelease = NULL;
2883 ULONG initialDirtyCount = 0;
2884 BOOLEAN bExtentsLocked = FALSE;
2887 NTSTATUS ntStatus = STATUS_SUCCESS;
2888 LARGE_INTEGER liLastFlush;
2889 ULONG ulRemainingExtentLength = 0;
2890 AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2891 GUID *pAuthGroup = AuthGroup;
2895 ASSERT( Fcb->Header.NodeTypeCode == AFS_FILE_FCB);
2898 // Save, then reset the flush time
2901 liLastFlush = Fcb->Specific.File.LastServerFlush;
2903 KeQueryTickCount( &Fcb->Specific.File.LastServerFlush);
2908 if( pAuthGroup == NULL ||
2909 RtlCompareMemory( pAuthGroup,
2910 &Fcb->NPFcb->Specific.File.ExtentsRequestAuthGroup,
2911 sizeof( GUID)) == sizeof( GUID))
2914 RtlZeroMemory( &stAuthGroup,
2917 ntStatus = AFSRetrieveValidAuthGroup( Fcb,
2922 if( !NT_SUCCESS( ntStatus))
2924 try_return( ntStatus);
2927 pAuthGroup = &stAuthGroup;
2931 // Look for a start in the list to flush entries
2936 sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
2938 pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
2940 AFS_EXTENT_RELEASE_TAG);
2941 if( NULL == pRelease)
2944 try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2947 if( Fcb->OpenHandleCount > 0)
2951 // Don't release everything ...
2955 // For now release everything
2958 //ulRemainingExtentLength = 1500;
2961 while( Fcb->Specific.File.ExtentLength > (LONG)ulRemainingExtentLength)
2964 AFSLockForExtentsTrim( Fcb);
2966 bExtentsLocked = TRUE;
2968 pRelease->Flags = AFS_EXTENT_FLAG_RELEASE;
2971 // Update the metadata for this call
2974 pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
2975 pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
2976 pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
2977 pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
2978 pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
2982 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
2984 while( count < AFS_MAXIMUM_EXTENT_RELEASE_COUNT &&
2985 le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
2988 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
2992 if( pExtent->ActiveCount > 0)
2998 pRelease->FileExtents[count].Flags = AFS_EXTENT_FLAG_RELEASE;
3000 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3001 AFS_TRACE_LEVEL_VERBOSE,
3002 "AFSReleaseExtentsWithFlush Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
3004 Fcb->ObjectInformation->FileId.Cell,
3005 Fcb->ObjectInformation->FileId.Volume,
3006 Fcb->ObjectInformation->FileId.Vnode,
3007 Fcb->ObjectInformation->FileId.Unique,
3008 pExtent->FileOffset.QuadPart,
3011 pRelease->FileExtents[count].Length = pExtent->Size;
3012 pRelease->FileExtents[count].DirtyLength = pExtent->Size;
3013 pRelease->FileExtents[count].DirtyOffset = 0;
3014 pRelease->FileExtents[count].CacheOffset = pExtent->CacheOffset;
3015 pRelease->FileExtents[count].FileOffset = pExtent->FileOffset;
3018 RtlCopyMemory( pRelease->FileExtents[count].MD5,
3020 sizeof(pExtent->MD5));
3022 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_MD5_SET;
3025 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3028 AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
3031 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3034 AFSRemoveEntryDirtyList( Fcb,
3037 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_DIRTY;
3039 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
3042 AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
3046 // Need to pull this extent from the main list as well
3049 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
3051 if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
3053 RemoveEntryList( &pExtent->Lists[i] );
3057 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
3059 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
3061 AFSExFreePool( pExtent);
3063 lCount = InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
3065 lCount = InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount);
3070 KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
3079 // If we are done then get out
3085 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3086 AFS_TRACE_LEVEL_VERBOSE,
3087 "AFSReleaseExtentsWithFlush No more dirty extents found\n");
3093 // Fire off the request synchronously
3096 sz = sizeof( AFSReleaseExtentsCB ) + (count * sizeof ( AFSFileExtentCB ));
3098 pRelease->ExtentCount = count;
3101 // Drop the extents lock for the duration of the call to
3102 // the network. We have pinned the extents so, even
3103 // though we might get extents added during this period,