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 *ExtentFor( PLIST_ENTRY le, ULONG SkipList );
43 static AFSExtent *NextExtent( AFSExtent *Extent, ULONG SkipList );
44 static ULONG ExtentsMasks[AFS_NUM_EXTENT_LISTS] = AFS_EXTENTS_MASKS;
45 static VOID VerifyExtentsLists(AFSFcb *Fcb);
46 static AFSExtent *DirtyExtentFor(PLIST_ENTRY le);
49 AFSEntryForOffset( IN AFSFcb *Fcb,
50 IN PLARGE_INTEGER Offset);
54 // Returns with Extents lock EX and no one using them.
58 AFSLockForExtentsTrim( IN AFSFcb *Fcb)
61 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
63 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
64 AFS_TRACE_LEVEL_VERBOSE,
65 "AFSLockForExtentsTrim Acuiring Fcb extents lock %08lX EXCL %08lX\n",
66 &pNPFcb->Specific.File.ExtentsResource,
67 PsGetCurrentThread());
69 AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, TRUE );
75 // return FALSE *or* with Extents lock EX and noone using them
78 AFSLockForExtentsTrimNoWait( IN AFSFcb *Fcb)
80 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
82 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
83 AFS_TRACE_LEVEL_VERBOSE,
84 "AFSLockForExtentsTrimNoWait Attempting to acquiring Fcb extent lock %08lX EXCL %08lX\n",
85 &pNPFcb->Specific.File.ExtentsResource,
86 PsGetCurrentThread());
88 if (!AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, FALSE ))
91 // Couldn't lock immediately
94 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
95 AFS_TRACE_LEVEL_VERBOSE,
96 "AFSLockForExtentsTrimNoWait Refused to wait for Fcb extent lock %08lX EXCL %08lX\n",
97 &pNPFcb->Specific.File.ExtentsResource,
98 PsGetCurrentThread());
106 // Pull all the extents away from the FCB.
109 AFSTearDownFcbExtents( IN AFSFcb *Fcb,
112 BOOLEAN bFoundExtents = FALSE;
113 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
116 ULONG ulCount = 0, ulReleaseCount = 0, ulProcessCount = 0;
118 AFSReleaseExtentsCB *pRelease = NULL;
119 BOOLEAN locked = FALSE;
121 AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
122 GUID *pAuthGroup = AuthGroup;
128 if( pAuthGroup == NULL)
131 RtlZeroMemory( &stAuthGroup,
134 ntStatus = AFSRetrieveValidAuthGroup( Fcb,
139 if( !NT_SUCCESS( ntStatus))
141 try_return( ntStatus);
144 pAuthGroup = &stAuthGroup;
148 // Ensure that no one is working with the extents and grab the
152 AFSLockForExtentsTrim( Fcb );
156 if (0 == Fcb->Specific.File.ExtentCount)
158 try_return ( ntStatus = STATUS_SUCCESS);
162 // Release a max of 100 extents at a time
165 sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
167 pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
169 AFS_EXTENT_RELEASE_TAG);
170 if (NULL == pRelease)
173 try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
176 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
178 ulCount = Fcb->Specific.File.ExtentCount;
180 while( ulReleaseCount < ulCount)
183 bFoundExtents = TRUE;
185 RtlZeroMemory( pRelease,
186 sizeof( AFSReleaseExtentsCB ) +
187 (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB )));
189 if( ulCount - ulReleaseCount <= AFS_MAXIMUM_EXTENT_RELEASE_COUNT)
191 ulProcessCount = ulCount - ulReleaseCount;
195 ulProcessCount = AFS_MAXIMUM_EXTENT_RELEASE_COUNT;
198 pRelease->Flags = AFS_EXTENT_FLAG_RELEASE;
199 pRelease->ExtentCount = ulProcessCount;
202 // Update the metadata for this call
205 pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
206 pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
207 pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
208 pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
209 pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
213 while (ulProcessCount < pRelease->ExtentCount)
215 pEntry = ExtentFor( le, AFS_EXTENTS_LIST );
217 pRelease->FileExtents[ulProcessCount].Flags = AFS_EXTENT_FLAG_RELEASE;
220 RtlCopyMemory( pRelease->FileExtents[ulProcessCount].MD5,
222 sizeof(pEntry->MD5));
224 pRelease->FileExtents[ulProcessCount].Flags |= AFS_EXTENT_FLAG_MD5_SET;
227 if( BooleanFlagOn( pEntry->Flags, AFS_EXTENT_DIRTY))
230 AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
233 if( BooleanFlagOn( pEntry->Flags, AFS_EXTENT_DIRTY))
238 AFSRemoveEntryDirtyList( Fcb,
241 pRelease->FileExtents[ulProcessCount].Flags |= AFS_EXTENT_FLAG_DIRTY;
243 dirtyCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
245 ASSERT( dirtyCount >= 0);
248 AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
251 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
252 AFS_TRACE_LEVEL_VERBOSE,
253 "AFSTearDownFcbExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %08lX-%08lX Len %08lX\n",
255 Fcb->ObjectInformation->FileId.Cell,
256 Fcb->ObjectInformation->FileId.Volume,
257 Fcb->ObjectInformation->FileId.Vnode,
258 Fcb->ObjectInformation->FileId.Unique,
259 pEntry->FileOffset.HighPart,
260 pEntry->FileOffset.LowPart,
263 pRelease->FileExtents[ulProcessCount].Length = pEntry->Size;
264 pRelease->FileExtents[ulProcessCount].DirtyLength = pEntry->Size;
265 pRelease->FileExtents[ulProcessCount].DirtyOffset = 0;
266 pRelease->FileExtents[ulProcessCount].CacheOffset = pEntry->CacheOffset;
267 pRelease->FileExtents[ulProcessCount].FileOffset = pEntry->FileOffset;
269 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pEntry->Size/1024)));
271 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pEntry->Size/1024)));
273 ASSERT( pEntry->ActiveCount == 0);
277 AFSExFreePool( pEntry);
279 InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
281 if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0)
284 KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
291 // Send the request down. We cannot send this down
292 // asynchronously - if we did that we could request them
293 // back before the service got this request and then this
294 // request would be a corruption.
297 sz = sizeof( AFSReleaseExtentsCB ) + (ulProcessCount * sizeof ( AFSFileExtentCB ));
299 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS,
300 AFS_REQUEST_FLAG_SYNCHRONOUS,
303 &Fcb->ObjectInformation->FileId,
309 if( !NT_SUCCESS(ntStatus))
313 // Regardless of whether or not the AFSProcessRequest() succeeded, the extents
314 // were released (if AFS_EXTENT_FLAG_RELEASE was set). Log the error so it is known.
317 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
318 AFS_TRACE_LEVEL_ERROR,
319 "AFSTearDownFcbExtents AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
320 Fcb->ObjectInformation->FileId.Cell,
321 Fcb->ObjectInformation->FileId.Volume,
322 Fcb->ObjectInformation->FileId.Vnode,
323 Fcb->ObjectInformation->FileId.Unique,
328 ulReleaseCount += ulProcessCount;
332 // Reinitialize the skip lists
335 ASSERT( Fcb->Specific.File.ExtentCount == 0);
337 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i++)
339 InitializeListHead(&Fcb->Specific.File.ExtentsLists[i]);
343 // Reinitialize the dirty list as well
346 AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
349 ASSERT( Fcb->Specific.File.ExtentsDirtyCount == 0);
351 Fcb->NPFcb->Specific.File.DirtyListHead = NULL;
352 Fcb->NPFcb->Specific.File.DirtyListTail = NULL;
354 AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
356 Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
363 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
364 AFS_TRACE_LEVEL_VERBOSE,
365 "AFSTearDownFcbExtents Releasing Fcb extent lock %08lX thread %08lX\n",
366 &Fcb->NPFcb->Specific.File.ExtentsResource,
367 PsGetCurrentThread());
369 AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource );
375 AFSExFreePool( pRelease);
379 return bFoundExtents;
383 ExtentForOffsetInList( IN AFSFcb *Fcb,
386 IN PLARGE_INTEGER Offset)
389 // Return the extent that maps the offset, that
390 // - Contains the offset
391 // - or is immediately ahead of the offset (in this list)
392 // - otherwise return NULL.
395 PLIST_ENTRY pLe = List;
396 AFSExtent *pPrevious = NULL;
398 ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
400 while (pLe != &Fcb->Specific.File.ExtentsLists[ListNumber])
404 entry = ExtentFor( pLe, ListNumber );
411 if (Offset->QuadPart < entry->FileOffset.QuadPart)
414 // Offset is ahead of entry. Return previous
419 if (Offset->QuadPart >= (entry->FileOffset.QuadPart + entry->Size))
422 // We start after this extent - carry on round
430 // Otherwise its a match
437 // Got to the end. Return Previous
443 AFSExtentContains( IN AFSExtent *Extent, IN PLARGE_INTEGER Offset)
449 return (Extent->FileOffset.QuadPart <= Offset->QuadPart &&
450 (Extent->FileOffset.QuadPart + Extent->Size) > Offset->QuadPart);
455 // Return the extent that contains the offset
458 AFSExtentForOffsetHint( IN AFSFcb *Fcb,
459 IN PLARGE_INTEGER Offset,
460 IN BOOLEAN ReturnPrevious,
463 AFSExtent *pPrevious = Hint;
467 ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
469 #if AFS_VALIDATE_EXTENTS
470 VerifyExtentsLists(Fcb);
474 // So we will go across the skip lists until we find an
475 // appropriate entry (previous or direct match). If it's a match
476 // we are done, other wise we start on the next layer down
478 for (i = AFS_NUM_EXTENT_LISTS-1; i >= AFS_EXTENTS_LIST; i--)
480 if (NULL == pPrevious)
483 // We haven't found anything in the previous layers
485 pLe = Fcb->Specific.File.ExtentsLists[i].Flink;
487 else if (NULL == pPrevious->Lists[i].Flink)
489 ASSERT(AFS_EXTENTS_LIST != i);
491 // The hint doesn't exist at this level, next one down
498 // take the previous into the next
500 pLe = &pPrevious->Lists[i];
503 pPrevious = ExtentForOffsetInList( Fcb, pLe, i, Offset);
505 if (NULL != pPrevious && AFSExtentContains(pPrevious, Offset))
508 // Found it immediately. Stop here
514 if (NULL == pPrevious || ReturnPrevious )
519 ASSERT( !AFSExtentContains(pPrevious, Offset) );
525 AFSEntryForOffset( IN AFSFcb *Fcb,
526 IN PLARGE_INTEGER Offset)
528 AFSExtent *pPrevious = NULL;
532 ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
534 #if AFS_VALIDATE_EXTENTS
535 VerifyExtentsLists(Fcb);
539 // So we will go across the skip lists until we find an
540 // appropriate entry (previous or direct match). If it's a match
541 // we are done, other wise we start on the next layer down
543 for (i = AFS_NUM_EXTENT_LISTS-1; i >= AFS_EXTENTS_LIST; i--)
545 if (NULL == pPrevious)
548 // We haven't found anything in the previous layers
550 pLe = Fcb->Specific.File.ExtentsLists[i].Flink;
552 else if (NULL == pPrevious->Lists[i].Flink)
554 ASSERT(AFS_EXTENTS_LIST != i);
556 // The hint doesn't exist at this level, next one down
563 // take the previous into the next
565 pLe = &pPrevious->Lists[i];
568 pPrevious = ExtentForOffsetInList( Fcb, pLe, i, Offset);
570 if (NULL != pPrevious && AFSExtentContains(pPrevious, Offset))
573 // Found it immediately. Stop here
583 AFSExtentForOffset( IN AFSFcb *Fcb,
584 IN PLARGE_INTEGER Offset,
585 IN BOOLEAN ReturnPrevious)
587 return AFSExtentForOffsetHint(Fcb, Offset, ReturnPrevious, NULL);
591 BOOLEAN AFSDoExtentsMapRegion(IN AFSFcb *Fcb,
592 IN PLARGE_INTEGER Offset,
594 IN OUT AFSExtent **FirstExtent,
595 OUT AFSExtent **LastExtent)
598 // Return TRUE region is completely mapped. FALSE
599 // otherwise. If the region isn't mapped then the last
600 // extent to map part of the region is returned.
602 // *LastExtent as input is where to start looking.
603 // *LastExtent as output is either the extent which
604 // contains the Offset, or the last one which doesn't
608 BOOLEAN retVal = FALSE;
613 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
614 AFS_TRACE_LEVEL_VERBOSE,
615 "AFSDoExtentsMapRegion Acquiring Fcb extent lock %08lX SHARED %08lX\n",
616 &Fcb->NPFcb->Specific.File.ExtentsResource,
617 PsGetCurrentThread());
619 AFSAcquireShared( &Fcb->NPFcb->Specific.File.ExtentsResource, TRUE );
621 entry = AFSExtentForOffsetHint(Fcb, Offset, TRUE, *FirstExtent);
622 *FirstExtent = entry;
624 if (NULL == entry || !AFSExtentContains(entry, Offset))
626 try_return (retVal = FALSE);
629 ASSERT(Offset->QuadPart >= entry->FileOffset.QuadPart);
633 if ((entry->FileOffset.QuadPart + entry->Size) >=
634 (Offset->QuadPart + Size))
637 // The end is inside the extent
639 try_return (retVal = TRUE);
642 if (entry->Lists[AFS_EXTENTS_LIST].Flink == &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
645 // Run out of extents
647 try_return (retVal = FALSE);
650 newEntry = NextExtent( entry, AFS_EXTENTS_LIST );
652 if (newEntry->FileOffset.QuadPart !=
653 (entry->FileOffset.QuadPart + entry->Size))
658 try_return (retVal = FALSE);
666 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
667 AFS_TRACE_LEVEL_VERBOSE,
668 "AFSDoExtentsMapRegion Releasing Fcb extent lock %08lX SHARED %08lX\n",
669 &Fcb->NPFcb->Specific.File.ExtentsResource,
670 PsGetCurrentThread());
672 AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource );
681 AFSRequestExtentsAsync( IN AFSFcb *Fcb,
683 IN PLARGE_INTEGER Offset,
687 AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
688 NTSTATUS ntStatus = STATUS_SUCCESS;
689 AFSExtent *pExtent = NULL;
690 AFSRequestExtentsCB request;
691 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
692 AFSExtent *pFirstExtent = NULL;
693 LARGE_INTEGER liAlignedOffset;
694 ULONG ulAlignedLength = 0;
695 BOOLEAN bRegionMapped = FALSE;
696 ULONGLONG ullProcessId = (ULONGLONG)PsGetCurrentProcessId();
701 ASSERT( !ExIsResourceAcquiredLite( &pNPFcb->Specific.File.ExtentsResource ));
704 // If the service set a failure on the file since the last
705 // CreateFile was issued, return it now.
708 if (!NT_SUCCESS( pNPFcb->Specific.File.ExtentsRequestStatus))
712 // If this isn't the same process which caused the failure then try to request them again
715 if( Fcb->Specific.File.ExtentRequestProcessId == ullProcessId)
717 try_return( ntStatus = pNPFcb->Specific.File.ExtentsRequestStatus);
720 pNPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
724 // Check if we are already mapped
727 bRegionMapped = AFSDoExtentsMapRegion( Fcb, Offset, Size, &pFirstExtent, &pExtent);
732 try_return( ntStatus = STATUS_SUCCESS);
736 // Align our request on extent size boundary
739 ulAlignedLength = Size;
741 liAlignedOffset = *Offset;
743 if( liAlignedOffset.QuadPart % pDevExt->Specific.RDR.CacheBlockSize != 0)
746 liAlignedOffset.QuadPart = (ULONGLONG)( (ULONGLONG)(liAlignedOffset.QuadPart / pDevExt->Specific.RDR.CacheBlockSize) * (ULONGLONG)pDevExt->Specific.RDR.CacheBlockSize);
748 ulAlignedLength += (ULONG)(Offset->QuadPart - liAlignedOffset.QuadPart);
751 if( ulAlignedLength % pDevExt->Specific.RDR.CacheBlockSize != 0)
754 ulAlignedLength = (ULONG)(((ulAlignedLength / pDevExt->Specific.RDR.CacheBlockSize) + 1) * pDevExt->Specific.RDR.CacheBlockSize);
757 RtlZeroMemory( &request,
758 sizeof( AFSRequestExtentsCB));
760 request.ByteOffset = liAlignedOffset;
761 request.Length = ulAlignedLength;
763 if( !AFSIsExtentRequestQueued( &Fcb->ObjectInformation->FileId,
768 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
769 AFS_TRACE_LEVEL_VERBOSE,
770 "AFSRequestExtentsAsync Request extents for fid %08lX-%08lX-%08lX-%08lX Offset %08lX Len %08lX Thread %08lX\n",
771 Fcb->ObjectInformation->FileId.Cell,
772 Fcb->ObjectInformation->FileId.Volume,
773 Fcb->ObjectInformation->FileId.Vnode,
774 Fcb->ObjectInformation->FileId.Unique,
775 request.ByteOffset.LowPart,
777 PsGetCurrentThread());
779 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_REQUEST_FILE_EXTENTS,
783 &Fcb->ObjectInformation->FileId,
785 sizeof( AFSRequestExtentsCB ),
789 if( NT_SUCCESS( ntStatus))
792 KeClearEvent( &pNPFcb->Specific.File.ExtentsRequestComplete );
798 KeClearEvent( &pNPFcb->Specific.File.ExtentsRequestComplete );
810 AFSProcessExtentsResult( IN AFSFcb *Fcb,
812 IN AFSFileExtentCB *Result)
814 NTSTATUS ntStatus = STATUS_SUCCESS;
815 AFSFileExtentCB *pFileExtents = Result;
818 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
819 ULONG fileExtentsUsed = 0;
820 BOOLEAN bFoundExtent = FALSE;
821 LIST_ENTRY *pSkipEntries[AFS_NUM_EXTENT_LISTS] = { 0 };
822 AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
825 // Grab the extents exclusive for the duration
828 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
829 AFS_TRACE_LEVEL_VERBOSE,
830 "AFSProcessExtentsResult Acquiring Fcb extent lock %08lX EXCL %08lX\n",
831 &pNPFcb->Specific.File.ExtentsResource,
832 PsGetCurrentThread());
834 AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, TRUE );
840 // Find where to put the extents
842 for (ULONG i = AFS_EXTENTS_LIST; i < AFS_NUM_EXTENT_LISTS; i++)
845 pSkipEntries[i] = Fcb->Specific.File.ExtentsLists[i].Flink;
848 le = pSkipEntries[AFS_EXTENTS_LIST];
850 if (le == &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
853 // No extents. Insert at head of list (which is where the skip lists point!)
857 else if (0 != pFileExtents->FileOffset.QuadPart)
860 // We want to find the best extents immediately *behind* this offset
862 LARGE_INTEGER offset = pFileExtents->FileOffset;
865 // Ask in the top skip list first, then work down
867 for (LONG i = AFS_NUM_EXTENT_LISTS-1; i >= AFS_EXTENTS_LIST; i--)
869 pExtent = ExtentForOffsetInList( Fcb,
877 // No dice. Header has to become the head of the list
879 pSkipEntries[i] = &Fcb->Specific.File.ExtentsLists[i];
881 // And as a loop invariant we should never have found an extent
883 ASSERT(!bFoundExtent);
888 // pExtent is where to start to insert at this level
890 pSkipEntries[i] = &pExtent->Lists[i];
893 // And also where to start to look at the next level
896 if (i > AFS_EXTENTS_LIST)
898 pSkipEntries[i-1] = &pExtent->Lists[i-1];
906 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
911 le = pExtent->Lists[AFS_EXTENTS_LIST].Blink;
917 // Looking at offset 0, so we must start at the beginning
920 pExtent = ExtentFor(le, AFS_EXTENTS_LIST);
924 // And set up the skip lists
927 for (ULONG i = AFS_EXTENTS_LIST; i < AFS_NUM_EXTENT_LISTS; i++)
929 pSkipEntries[i] = &Fcb->Specific.File.ExtentsLists[i];
933 while (fileExtentsUsed < Count)
937 // Loop invariant - le points to where to insert after and
938 // pExtent points to le->fLink
941 ASSERT (NULL == pExtent ||
942 le->Flink == &pExtent->Lists[AFS_EXTENTS_LIST]);
944 if (NULL == pExtent ||
945 pExtent->FileOffset.QuadPart > pFileExtents->FileOffset.QuadPart)
948 // We need to insert a new extent at le. Start with
949 // some sanity check on spanning
951 if (NULL != pExtent &&
952 ((pFileExtents->FileOffset.QuadPart + pFileExtents->Length) >
953 pExtent->FileOffset.QuadPart))
956 // File Extents overlaps pExtent
958 ASSERT( (pFileExtents->FileOffset.QuadPart + pFileExtents->Length) <=
959 pExtent->FileOffset.QuadPart);
961 try_return (ntStatus = STATUS_INVALID_PARAMETER);
965 // File offset is entirely in front of this extent. Create
966 // a new one (remember le is the previous list entry)
968 pExtent = (AFSExtent *) AFSExAllocatePoolWithTag( NonPagedPool,
976 try_return (ntStatus = STATUS_INSUFFICIENT_RESOURCES );
979 RtlZeroMemory( pExtent, sizeof( AFSExtent ));
981 pExtent->FileOffset = pFileExtents->FileOffset;
982 pExtent->CacheOffset = pFileExtents->CacheOffset;
983 pExtent->Size = pFileExtents->Length;
985 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
986 AFS_TRACE_LEVEL_VERBOSE,
987 "AFSProcessExtentsResult Received extent for fid %08lX-%08lX-%08lX-%08lX File Offset %I64X Cache Offset %I64X Len %08lX\n",
988 Fcb->ObjectInformation->FileId.Cell,
989 Fcb->ObjectInformation->FileId.Volume,
990 Fcb->ObjectInformation->FileId.Vnode,
991 Fcb->ObjectInformation->FileId.Unique,
992 pFileExtents->FileOffset.QuadPart,
993 pFileExtents->CacheOffset.QuadPart,
994 pFileExtents->Length);
996 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, (LONG)(pExtent->Size/1024));
998 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, (LONG)(pExtent->Size/1024));
1000 InterlockedIncrement( &Fcb->Specific.File.ExtentCount);
1002 if( InterlockedIncrement( &pControlDevExt->Specific.Control.ExtentCount) == 1)
1005 KeClearEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent);
1011 InsertHeadList(le, &pExtent->Lists[AFS_EXTENTS_LIST]);
1012 ASSERT(le->Flink == &pExtent->Lists[AFS_EXTENTS_LIST]);
1013 ASSERT(0 == (pExtent->FileOffset.LowPart & ExtentsMasks[AFS_EXTENTS_LIST]));
1016 // Do not move the cursor - we will do it next time
1020 // And into the (upper) skip lists - Again, do not move the cursor
1022 for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--)
1024 if (0 == (pExtent->FileOffset.LowPart & ExtentsMasks[i]))
1026 InsertHeadList(pSkipEntries[i], &pExtent->Lists[i]);
1027 #if AFS_VALIDATE_EXTENTS
1028 VerifyExtentsLists(Fcb);
1033 else if (pExtent->FileOffset.QuadPart == pFileExtents->FileOffset.QuadPart)
1036 if (pExtent->Size != pFileExtents->Length)
1039 ASSERT (pExtent->Size == pFileExtents->Length);
1041 try_return (ntStatus = STATUS_INVALID_PARAMETER);
1045 // Move both cursors forward.
1047 // First the extent pointer
1050 le = &pExtent->Lists[AFS_EXTENTS_LIST];
1053 // Then the skip lists cursors forward if needed
1055 for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--)
1057 if (0 == (pExtent->FileOffset.LowPart & ExtentsMasks[i]))
1060 // Check sanity before
1062 #if AFS_VALIDATE_EXTENTS
1063 VerifyExtentsLists(Fcb);
1067 // Skip list should point to us
1069 //ASSERT(pSkipEntries[i] == &pExtent->Lists[i]);
1071 // Move forward cursor
1073 pSkipEntries[i] = pSkipEntries[i]->Flink;
1075 // Check sanity before
1077 #if AFS_VALIDATE_EXTENTS
1078 VerifyExtentsLists(Fcb);
1084 // And then the cursor in the supplied array
1090 // setup pExtent if there is one
1092 if (le->Flink != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
1094 pExtent = NextExtent( pExtent, AFS_EXTENTS_LIST ) ;
1104 ASSERT( pExtent->FileOffset.QuadPart < pFileExtents->FileOffset.QuadPart );
1107 // Sanity check on spanning
1109 if ((pExtent->FileOffset.QuadPart + pExtent->Size) >
1110 pFileExtents->FileOffset.QuadPart)
1113 ASSERT( (pExtent->FileOffset.QuadPart + pExtent->Size) <=
1114 pFileExtents->FileOffset.QuadPart);
1116 try_return (ntStatus = STATUS_INVALID_PARAMETER);
1120 // Move le and pExtent forward
1122 le = &pExtent->Lists[AFS_EXTENTS_LIST];
1126 // Then the check the skip lists cursors
1128 for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--)
1130 if (0 == (pFileExtents->FileOffset.LowPart & ExtentsMasks[i]))
1134 // - empty list (pSkipEntries[i]->Flink == pSkipEntries[i]->Flink == fcb->lists[i]
1135 // - We are the last on the list (pSkipEntries[i]->Flink == fcb->lists[i])
1136 // - We are not the last on the list. In that case we have to be strictly less than
1138 if (pSkipEntries[i]->Flink != &Fcb->Specific.File.ExtentsLists[i]) {
1140 AFSExtent *otherExtent = ExtentFor(pSkipEntries[i]->Flink, i);
1141 ASSERT(pFileExtents->FileOffset.QuadPart < otherExtent->FileOffset.QuadPart);
1148 // setup pExtent if there is one
1151 if (le->Flink != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
1153 pExtent = NextExtent( pExtent, AFS_EXTENTS_LIST ) ;
1163 // All done, signal that we are done drop the lock, exit
1168 if( !NT_SUCCESS( ntStatus))
1172 // If we failed the service is going to drop all extents so trim away the
1176 AFSTrimSpecifiedExtents( Fcb,
1181 #if AFS_VALIDATE_EXTENTS
1182 VerifyExtentsLists(Fcb);
1185 KeSetEvent( &pNPFcb->Specific.File.ExtentsRequestComplete,
1189 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1190 AFS_TRACE_LEVEL_VERBOSE,
1191 "AFSProcessExtentsResult Releasing Fcb extent lock %08lX EXCL %08lX\n",
1192 &pNPFcb->Specific.File.ExtentsResource,
1193 PsGetCurrentThread());
1195 AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
1202 AFSProcessSetFileExtents( IN AFSSetFileExtentsCB *SetExtents )
1204 AFSFcb *pFcb = NULL;
1205 AFSVolumeCB *pVolumeCB = NULL;
1206 NTSTATUS ntStatus = STATUS_SUCCESS;
1207 AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1208 ULONGLONG ullIndex = 0;
1209 AFSObjectInfoCB *pObjectInfo = NULL;
1214 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1215 AFS_TRACE_LEVEL_VERBOSE,
1216 "AFSProcessSetFileExtents Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n",
1217 &pDevExt->Specific.RDR.VolumeTreeLock,
1218 PsGetCurrentThread());
1220 AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
1222 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1223 AFS_TRACE_LEVEL_VERBOSE,
1224 "AFSProcessSetFileExtents Set extents for fid %08lX-%08lX-%08lX-%08lX\n",
1225 SetExtents->FileId.Cell,
1226 SetExtents->FileId.Volume,
1227 SetExtents->FileId.Vnode,
1228 SetExtents->FileId.Unique);
1231 // Locate the volume node
1234 ullIndex = AFSCreateHighIndex( &SetExtents->FileId);
1236 ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
1238 (AFSBTreeEntry **)&pVolumeCB);
1240 if( pVolumeCB != NULL)
1243 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1244 AFS_TRACE_LEVEL_VERBOSE,
1245 "AFSProcessSetFileExtents Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n",
1246 pVolumeCB->ObjectInfoTree.TreeLock,
1247 PsGetCurrentThread());
1249 InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
1252 AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
1254 if( !NT_SUCCESS( ntStatus) ||
1258 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1259 AFS_TRACE_LEVEL_ERROR,
1260 "AFSProcessSetFileExtents Set extents for fid %08lX-%08lX-%08lX-%08lX Failed to locate volume Status %08lX\n",
1261 SetExtents->FileId.Cell,
1262 SetExtents->FileId.Volume,
1263 SetExtents->FileId.Vnode,
1264 SetExtents->FileId.Unique,
1267 try_return( ntStatus = STATUS_UNSUCCESSFUL);
1270 AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1273 InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1276 // Now locate the Object in this volume
1279 ullIndex = AFSCreateLowIndex( &SetExtents->FileId);
1281 ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
1283 (AFSBTreeEntry **)&pObjectInfo);
1285 if( pObjectInfo != NULL)
1289 // Reference the node so it won't be torn down
1292 InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
1294 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1295 AFS_TRACE_LEVEL_VERBOSE,
1296 "AFSProcessSetFileExtents Increment count on object %08lX Cnt %d\n",
1298 pObjectInfo->ObjectReferenceCount);
1301 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1303 if( !NT_SUCCESS( ntStatus) ||
1304 pObjectInfo == NULL)
1307 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1308 AFS_TRACE_LEVEL_ERROR,
1309 "AFSProcessSetFileExtents Set extents for hash %I64X fid %08lX-%08lX-%08lX-%08lX Failed to locate file in volume %08lX\n",
1311 SetExtents->FileId.Cell,
1312 SetExtents->FileId.Volume,
1313 SetExtents->FileId.Vnode,
1314 SetExtents->FileId.Unique,
1317 try_return( ntStatus = STATUS_UNSUCCESSFUL);
1320 pFcb = pObjectInfo->Fcb;
1323 // If we have a result failure then don't bother trying to set the extents
1326 if( SetExtents->ResultStatus != STATUS_SUCCESS)
1329 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1330 AFS_TRACE_LEVEL_ERROR,
1331 "AFSProcessSetFileExtents Set extents failure fid %08lX-%08lX-%08lX-%08lX ResultStatus %08lX\n",
1332 SetExtents->FileId.Cell,
1333 SetExtents->FileId.Volume,
1334 SetExtents->FileId.Vnode,
1335 SetExtents->FileId.Unique,
1336 SetExtents->ResultStatus);
1338 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1339 AFS_TRACE_LEVEL_VERBOSE,
1340 "AFSProcessSetFileExtents Acquiring Fcb extents lock %08lX EXCL %08lX\n",
1341 &pFcb->NPFcb->Specific.File.ExtentsResource,
1342 PsGetCurrentThread());
1344 AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource,
1347 pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_CANCELLED;
1349 KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete,
1353 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1354 AFS_TRACE_LEVEL_VERBOSE,
1355 "AFSProcessSetFileExtents Releasing Fcb extent lock %08lX EXCL %08lX\n",
1356 &pFcb->NPFcb->Specific.File.ExtentsResource,
1357 PsGetCurrentThread());
1359 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
1361 try_return( ntStatus);
1364 ntStatus = AFSProcessExtentsResult ( pFcb,
1365 SetExtents->ExtentCount,
1366 SetExtents->FileExtents );
1370 if( pObjectInfo != NULL)
1373 InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
1375 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1376 AFS_TRACE_LEVEL_VERBOSE,
1377 "AFSProcessSetFileExtents Decrement count on object %08lX Cnt %d\n",
1379 pObjectInfo->ObjectReferenceCount);
1387 // Helper fuctions for Usermode initiation of release of extents
1390 AFSReleaseSpecifiedExtents( IN AFSReleaseFileExtentsCB *Extents,
1392 OUT AFSFileExtentCB *FileExtents,
1393 IN ULONG BufferSize,
1394 OUT ULONG *ExtentCount,
1395 OUT BOOLEAN *DirtyExtents)
1400 ULONG ulExtentCount = 0;
1401 NTSTATUS ntStatus = STATUS_SUCCESS;
1402 BOOLEAN bReleaseAll = FALSE;
1403 AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1407 ASSERT( ExIsResourceAcquiredExclusiveLite( &Fcb->NPFcb->Specific.File.ExtentsResource));
1409 if (BufferSize < (Extents->ExtentCount * sizeof( AFSFileExtentCB)))
1412 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1413 AFS_TRACE_LEVEL_VERBOSE,
1414 "AFSReleaseSpecifiedExtents Buffer too small\n");
1416 try_return( ntStatus = STATUS_BUFFER_TOO_SMALL);
1419 RtlZeroMemory( FileExtents, BufferSize);
1422 *DirtyExtents = FALSE;
1425 // iterate until we have dealt with all we were asked for or
1426 // are at the end of the list. Note that this deals (albeit
1427 // badly) with out of order extents
1430 pExtent = AFSExtentForOffset( Fcb,
1431 &Extents->FileExtents[0].FileOffset,
1434 if (NULL == pExtent)
1436 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1440 le = &pExtent->Lists[AFS_EXTENTS_LIST];
1444 if( BooleanFlagOn( Extents->Flags, AFS_RELEASE_EXTENTS_FLAGS_RELEASE_ALL) ||
1445 ( Extents->FileId.Cell == 0 &&
1446 Extents->FileId.Volume == 0 &&
1447 Extents->FileId.Vnode == 0 &&
1448 Extents->FileId.Unique == 0))
1454 while( le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST] &&
1455 ulExtentCount < Extents->ExtentCount)
1459 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
1464 if( pExtent->FileOffset.QuadPart < Extents->FileExtents[ulExtentCount].FileOffset.QuadPart)
1467 // Skip forward through the extent list until we get
1468 // to the one we want
1474 else if (pExtent->FileOffset.QuadPart > Extents->FileExtents[ulExtentCount].FileOffset.QuadPart)
1477 // We don't have the extent asked for so return UNKNOWN
1480 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1481 AFS_TRACE_LEVEL_VERBOSE,
1482 "AFSReleaseSpecifiedExtents Located UNKNOWN extent Offset %I64X Len %08lX\n",
1483 Extents->FileExtents[ulExtentCount].FileOffset.QuadPart,
1484 Extents->FileExtents[ulExtentCount].Length);
1486 FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_UNKNOWN;
1488 FileExtents[*ExtentCount].Length = 0;
1489 FileExtents[*ExtentCount].CacheOffset.QuadPart = 0;
1490 FileExtents[*ExtentCount].FileOffset = Extents->FileExtents[ulExtentCount].FileOffset;
1492 *ExtentCount = (*ExtentCount) + 1;
1497 // Reset where we are looking
1500 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1504 else if( pExtent->ActiveCount > 0)
1507 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1508 AFS_TRACE_LEVEL_VERBOSE,
1509 "AFSReleaseSpecifiedExtents Located IN_USE extent Offset %I64X Len %08lX\n",
1510 Extents->FileExtents[ulExtentCount].FileOffset.QuadPart,
1511 Extents->FileExtents[ulExtentCount].Length);
1513 FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_IN_USE;
1515 FileExtents[*ExtentCount].Length = 0;
1516 FileExtents[*ExtentCount].CacheOffset.QuadPart = 0;
1517 FileExtents[*ExtentCount].FileOffset = Extents->FileExtents[ulExtentCount].FileOffset;
1519 *ExtentCount = (*ExtentCount) + 1;
1524 // Reset where we are looking
1527 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
1536 // If the extent is currently active then skip it
1539 if( pExtent->ActiveCount > 0)
1548 FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_RELEASE;
1550 FileExtents[*ExtentCount].Length = pExtent->Size;
1551 FileExtents[*ExtentCount].DirtyLength = pExtent->Size;
1552 FileExtents[*ExtentCount].DirtyOffset = 0;
1553 FileExtents[*ExtentCount].CacheOffset = pExtent->CacheOffset;
1554 FileExtents[*ExtentCount].FileOffset = pExtent->FileOffset;
1556 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1557 AFS_TRACE_LEVEL_VERBOSE,
1558 "AFSReleaseSpecifiedExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
1560 Fcb->ObjectInformation->FileId.Cell,
1561 Fcb->ObjectInformation->FileId.Volume,
1562 Fcb->ObjectInformation->FileId.Vnode,
1563 Fcb->ObjectInformation->FileId.Unique,
1564 FileExtents[*ExtentCount].FileOffset.QuadPart,
1565 FileExtents[*ExtentCount].Length);
1567 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
1570 AFSAcquireExcl( &Fcb->NPFcb->Specific.File.DirtyExtentsListLock,
1573 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
1576 AFSRemoveEntryDirtyList( Fcb,
1579 FileExtents[*ExtentCount].Flags |= AFS_EXTENT_FLAG_DIRTY;
1581 InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
1583 *DirtyExtents = TRUE;
1586 AFSReleaseResource( &Fcb->NPFcb->Specific.File.DirtyExtentsListLock);
1590 // move forward all three cursors
1594 *ExtentCount = (*ExtentCount) + 1;
1599 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
1601 if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
1603 RemoveEntryList( &pExtent->Lists[i] );
1607 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
1609 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
1614 AFSExFreePool( pExtent);
1616 InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
1618 if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0)
1621 KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
1636 AFSFindFcbToClean(ULONG IgnoreTime, AFSFcb *LastFcb, BOOLEAN Block)
1639 AFSFcb *pFcb = NULL;
1640 AFSVolumeCB *pVolumeCB = NULL;
1641 AFSDeviceExt *pRDRDeviceExt = NULL;
1642 AFSDeviceExt *pControlDeviceExt = NULL;
1643 BOOLEAN bLocatedEntry = FALSE;
1644 AFSObjectInfoCB *pCurrentObject = NULL;
1645 BOOLEAN bReleaseVolumeListLock = FALSE;
1647 pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
1648 pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1650 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1651 AFS_TRACE_LEVEL_VERBOSE,
1652 "AFSFindFcbToClean Acquiring RDR VolumeListLock lock %08lX SHARED %08lX\n",
1653 &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1654 PsGetCurrentThread());
1656 AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1659 bReleaseVolumeListLock = TRUE;
1661 pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead;
1663 while( pVolumeCB != NULL)
1667 // The Volume list may move under our feet. Lock it.
1670 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1671 AFS_TRACE_LEVEL_VERBOSE,
1672 "AFSFindFcbToClean Acquiring VolumeRoot ObjectInfoTree lock %08lX SHARED %08lX\n",
1673 pVolumeCB->ObjectInfoTree.TreeLock,
1674 PsGetCurrentThread());
1676 InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
1678 AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1680 bReleaseVolumeListLock = FALSE;
1682 AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1685 InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1687 if( NULL == LastFcb)
1690 pCurrentObject = pVolumeCB->ObjectInfoListHead;
1695 pCurrentObject = (AFSObjectInfoCB *)LastFcb->ObjectInformation->ListEntry.fLink;
1700 while( pCurrentObject != NULL)
1703 pFcb = (AFSFcb *)pCurrentObject->Fcb;
1706 // If the FCB is a candidate we try to lock it (but without waiting - which
1707 // means we are deadlock free
1711 pFcb->Header.NodeTypeCode == AFS_FILE_FCB)
1717 AFSLockForExtentsTrim( pFcb);
1722 if( !AFSLockForExtentsTrimNoWait( pFcb))
1725 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1734 // Need to be sure there are no current flushes in the queue
1737 if( pFcb->Specific.File.ExtentCount == 0)
1740 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1741 AFS_TRACE_LEVEL_VERBOSE,
1742 "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n",
1743 &pFcb->NPFcb->Specific.File.ExtentsResource,
1744 PsGetCurrentThread());
1746 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
1748 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1755 if( pFcb->Specific.File.QueuedFlushCount > 0)
1758 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1759 AFS_TRACE_LEVEL_VERBOSE,
1760 "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n",
1761 &pFcb->NPFcb->Specific.File.ExtentsResource,
1762 PsGetCurrentThread());
1764 AFSReleaseResource(&pFcb->NPFcb->Specific.File.ExtentsResource);
1768 AFSWaitOnQueuedFlushes( pFcb);
1773 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1781 if( pFcb->OpenHandleCount > 0)
1784 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1785 AFS_TRACE_LEVEL_VERBOSE,
1786 "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n",
1787 &pFcb->NPFcb->Specific.File.ExtentsResource,
1788 PsGetCurrentThread());
1790 AFSReleaseResource(&pFcb->NPFcb->Specific.File.ExtentsResource);
1792 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1800 // A hit a very palpable hit. Pin it
1803 InterlockedIncrement( &pCurrentObject->ObjectReferenceCount);
1805 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1806 AFS_TRACE_LEVEL_VERBOSE,
1807 "AFSFindFcbToClean Increment count on Fcb %08lX Cnt %d\n",
1809 pCurrentObject->ObjectReferenceCount);
1811 bLocatedEntry = TRUE;
1816 pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
1821 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1828 AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
1831 bReleaseVolumeListLock = TRUE;
1833 pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
1836 if( bReleaseVolumeListLock)
1839 AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
1846 AFSProcessExtentFailure( PIRP Irp)
1848 AFSExtentFailureCB *pFailureCB = NULL;
1849 NTSTATUS ntStatus = STATUS_SUCCESS;
1850 AFSDeviceExt *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension;
1851 PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1852 AFSVolumeCB *pVolumeCB = NULL;
1853 ULONGLONG ullIndex = 0;
1854 AFSObjectInfoCB *pObjectInfo = NULL;
1858 if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSExtentFailureCB))
1861 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1862 AFS_TRACE_LEVEL_ERROR,
1863 "AFSProcessExtentFailure Input buffer too small\n");
1865 try_return( ntStatus = STATUS_INVALID_PARAMETER);
1868 pFailureCB = (AFSExtentFailureCB *)Irp->AssociatedIrp.SystemBuffer;
1870 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1871 AFS_TRACE_LEVEL_ERROR,
1872 "AFSProcessExtentFailure Service Reports Failure fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
1873 pFailureCB->FileId.Cell,
1874 pFailureCB->FileId.Volume,
1875 pFailureCB->FileId.Vnode,
1876 pFailureCB->FileId.Unique,
1877 pFailureCB->FailureStatus);
1879 AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
1882 // Locate the volume node
1885 ullIndex = AFSCreateHighIndex( &pFailureCB->FileId);
1887 ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
1889 (AFSBTreeEntry **)&pVolumeCB);
1891 if( pVolumeCB != NULL)
1894 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1895 AFS_TRACE_LEVEL_VERBOSE,
1896 "AFSProcessExtentFailure Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n",
1897 pVolumeCB->ObjectInfoTree.TreeLock,
1898 PsGetCurrentThread());
1900 InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
1903 AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
1905 if( !NT_SUCCESS( ntStatus) ||
1909 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1910 AFS_TRACE_LEVEL_ERROR,
1911 "AFSProcessExtentFailure Invalid volume index %I64X status %08X\n",
1912 ullIndex, ntStatus);
1914 try_return( ntStatus = STATUS_UNSUCCESSFUL);
1917 AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
1920 InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
1923 // Now locate the Object in this volume
1926 ullIndex = AFSCreateLowIndex( &pFailureCB->FileId);
1928 ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
1930 (AFSBTreeEntry **)&pObjectInfo);
1932 if( pObjectInfo != NULL &&
1933 pObjectInfo->Fcb != NULL)
1937 // Reference the node so it won't be torn down
1940 InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
1942 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1943 AFS_TRACE_LEVEL_VERBOSE,
1944 "AFSProcessExtentFailure Increment count on object %08lX Cnt %d\n",
1946 pObjectInfo->ObjectReferenceCount);
1949 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
1951 if( !NT_SUCCESS( ntStatus) ||
1952 pObjectInfo == NULL ||
1953 pObjectInfo->Fcb == NULL)
1956 if( pObjectInfo == NULL)
1958 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1959 AFS_TRACE_LEVEL_ERROR,
1960 "AFSProcessExtentFailure Invalid file index %I64X\n",
1965 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1966 AFS_TRACE_LEVEL_ERROR,
1967 "AFSProcessExtentFailure Fcb dealocated for %I64X\n",
1971 try_return( ntStatus = STATUS_UNSUCCESSFUL);
1974 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1975 AFS_TRACE_LEVEL_VERBOSE,
1976 "AFSProcessExtentFailure Acquiring Fcb extent lock %08lX EXCL %08lX\n",
1977 &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
1978 PsGetCurrentThread());
1980 AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
1983 pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = pFailureCB->FailureStatus;
1985 KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
1989 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1990 AFS_TRACE_LEVEL_VERBOSE,
1991 "AFSProcessExtentFailure Releasing Fcb extent lock %08lX EXCL %08lX\n",
1992 &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
1993 PsGetCurrentThread());
1995 AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource);
1997 InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
1999 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2000 AFS_TRACE_LEVEL_VERBOSE,
2001 "AFSProcessExtentFailure Decrement count on object %08lX Cnt %d\n",
2003 pObjectInfo->ObjectReferenceCount);
2014 AFSProcessReleaseFileExtents( IN PIRP Irp)
2016 NTSTATUS ntStatus = STATUS_SUCCESS;
2017 PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
2018 PFILE_OBJECT pFileObject = pIrpSp->FileObject;
2019 AFSFcb *pFcb = NULL;
2020 AFSVolumeCB *pVolumeCB = NULL;
2021 AFSDeviceExt *pDevExt;
2022 AFSReleaseFileExtentsCB *pExtents;
2023 AFSReleaseFileExtentsResultCB *pResult = NULL;
2024 AFSReleaseFileExtentsResultFileCB *pFile = NULL;
2026 ULONGLONG ullIndex = 0;
2027 AFSObjectInfoCB *pObjectInfo = NULL;
2028 BOOLEAN bLocked = FALSE;
2029 BOOLEAN bDirtyExtents = FALSE;
2035 pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension;
2037 pExtents = (AFSReleaseFileExtentsCB*) Irp->AssociatedIrp.SystemBuffer;
2039 if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2040 sizeof( AFSReleaseFileExtentsCB))
2043 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2044 AFS_TRACE_LEVEL_ERROR,
2045 "AFSProcessReleaseFileExtents INPUT Buffer too small\n");
2047 try_return( ntStatus = STATUS_INVALID_PARAMETER );
2050 if ( pIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
2051 sizeof(AFSReleaseFileExtentsResultCB))
2054 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2055 AFS_TRACE_LEVEL_ERROR,
2056 "AFSProcessReleaseFileExtents OUTPUT Buffer too small [1]\n");
2059 // Must have space for one extent in one file
2062 try_return( ntStatus = STATUS_BUFFER_TOO_SMALL);
2065 if (pExtents->ExtentCount == 0)
2068 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2069 AFS_TRACE_LEVEL_ERROR,
2070 "AFSProcessReleaseFileExtents Extent count zero\n");
2072 try_return( ntStatus = STATUS_INVALID_PARAMETER);
2075 if (pExtents->FileId.Cell != 0 ||
2076 pExtents->FileId.Volume != 0 ||
2077 pExtents->FileId.Vnode != 0 ||
2078 pExtents->FileId.Unique != 0)
2081 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2082 AFS_TRACE_LEVEL_VERBOSE,
2083 "AFSProcessReleaseFileExtents Processing FID %08lX:%08lX:%08lX:%08lX\n",
2084 pExtents->FileId.Cell,
2085 pExtents->FileId.Volume,
2086 pExtents->FileId.Vnode,
2087 pExtents->FileId.Unique);
2089 if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2090 ( FIELD_OFFSET( AFSReleaseFileExtentsCB, ExtentCount) + sizeof(ULONG)) ||
2091 pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
2092 ( FIELD_OFFSET( AFSReleaseFileExtentsCB, ExtentCount) + sizeof(ULONG) +
2093 sizeof (AFSFileExtentCB) * pExtents->ExtentCount))
2096 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2097 AFS_TRACE_LEVEL_ERROR,
2098 "AFSProcessReleaseFileExtents Buffer too small for FID %08lX:%08lx:%08lX:%08lX\n",
2099 pExtents->FileId.Cell,
2100 pExtents->FileId.Volume,
2101 pExtents->FileId.Vnode,
2102 pExtents->FileId.Unique);
2104 try_return( ntStatus = STATUS_INVALID_PARAMETER );
2107 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2108 AFS_TRACE_LEVEL_VERBOSE,
2109 "AFSProcessReleaseFileExtents Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n",
2110 &pDevExt->Specific.RDR.VolumeTreeLock,
2111 PsGetCurrentThread());
2113 AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE);
2116 // Locate the volume node
2119 ullIndex = AFSCreateHighIndex( &pExtents->FileId);
2121 ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead,
2123 (AFSBTreeEntry **)&pVolumeCB);
2125 if( pVolumeCB != NULL)
2128 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2129 AFS_TRACE_LEVEL_VERBOSE,
2130 "AFSProcessReleaseFileExtents Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n",
2131 pVolumeCB->ObjectInfoTree.TreeLock,
2132 PsGetCurrentThread());
2134 InterlockedIncrement( &pVolumeCB->VolumeReferenceCount);
2137 AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock);
2139 if( !NT_SUCCESS( ntStatus) ||
2143 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2144 AFS_TRACE_LEVEL_ERROR,
2145 "AFSProcessReleaseFileExtents Invalid volume index %I64X status %08X\n",
2146 ullIndex, ntStatus);
2148 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2151 AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
2154 InterlockedDecrement( &pVolumeCB->VolumeReferenceCount);
2157 // Now locate the Object in this volume
2160 ullIndex = AFSCreateLowIndex( &pExtents->FileId);
2162 ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead,
2164 (AFSBTreeEntry **)&pObjectInfo);
2166 if( pObjectInfo != NULL)
2170 // Reference the node so it won't be torn down
2173 InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
2175 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2176 AFS_TRACE_LEVEL_VERBOSE,
2177 "AFSProcessReleaseFileExtents Increment count on object %08lX Cnt %d\n",
2179 pObjectInfo->ObjectReferenceCount);
2182 AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
2184 if( !NT_SUCCESS( ntStatus) ||
2185 pObjectInfo == NULL)
2188 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2189 AFS_TRACE_LEVEL_ERROR,
2190 "AFSProcessReleaseFileExtents Invalid file index %I64X\n",
2193 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2196 pFcb = pObjectInfo->Fcb;
2201 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2202 AFS_TRACE_LEVEL_ERROR,
2203 "AFSProcessReleaseFileExtents Fcb not initialied (NO EXTENTS) for FID %08lX:%08lx:%08lX:%08lX\n",
2204 pExtents->FileId.Cell,
2205 pExtents->FileId.Volume,
2206 pExtents->FileId.Vnode,
2207 pExtents->FileId.Unique);
2209 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2212 AFSLockForExtentsTrim( pFcb );
2220 // Locate an Fcb to trim down
2223 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2224 AFS_TRACE_LEVEL_VERBOSE,
2225 "AFSProcessReleaseFileExtents Searching for a Fcb to Trim Down\n");
2227 pFcb = AFSFindFcbToClean( 0, NULL, FALSE);
2232 pFcb = AFSFindFcbToClean( 0, NULL, TRUE);
2238 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2239 AFS_TRACE_LEVEL_ERROR,
2240 "AFSProcessReleaseFileExtents Failed to locate Fcb for release ...\n");
2242 try_return( ntStatus = STATUS_UNSUCCESSFUL);
2245 pObjectInfo = pFcb->ObjectInformation;
2251 // Allocate a scratch buffer to move in the extent information
2254 ulSz = (pExtents->ExtentCount-1) * sizeof(AFSFileExtentCB);
2255 ulSz += sizeof(AFSReleaseFileExtentsResultCB);
2257 if (ulSz > pIrpSp->Parameters.DeviceIoControl.OutputBufferLength)
2259 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2260 AFS_TRACE_LEVEL_ERROR,
2261 "AFSProcessReleaseFileExtents OUTPUT Buffer too small [2]\n");
2263 try_return( ntStatus = STATUS_BUFFER_TOO_SMALL );
2266 pResult = (AFSReleaseFileExtentsResultCB*) AFSExAllocatePoolWithTag( PagedPool,
2268 AFS_EXTENTS_RESULT_TAG);
2269 if (NULL == pResult)
2272 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
2273 AFS_TRACE_LEVEL_ERROR,
2274 "AFSProcessReleaseFileExtents Failed to allocate result block\n");
2276 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2280 // Set up the header (for an array of one)
2282 pResult->FileCount = 1;
2283 pResult->Flags = AFS_EXTENT_FLAG_RELEASE;
2284 ulSz -= FIELD_OFFSET(AFSReleaseFileExtentsResultCB, Files);
2287 // Setup the first (and only) file
2289 pFile = pResult->Files;
2290 pFile->FileId = pObjectInfo->FileId;
2291 pFile->Flags = AFS_EXTENT_FLAG_RELEASE;
2294 // Stash away the auth group
2297 RtlZeroMemory( &stAuthGroup,
2300 ntStatus = AFSRetrieveValidAuthGroup( pFcb,
2305 if( !NT_SUCCESS( ntStatus))
2307 try_return( ntStatus);
2310 RtlCopyMemory( &pFile->AuthGroup,
2315 // Update the metadata for this call
2318 pFile->AllocationSize = pFcb->ObjectInformation->EndOfFile;
2319 pFile->CreateTime = pFcb->ObjectInformation->CreationTime;
2320 pFile->ChangeTime = pFcb->ObjectInformation->ChangeTime;
2321 pFile->LastAccessTime = pFcb->ObjectInformation->LastAccessTime;
2322 pFile->LastWriteTime = pFcb->ObjectInformation->LastWriteTime;
2324 ulSz -= FIELD_OFFSET(AFSReleaseFileExtentsResultFileCB, FileExtents);
2326 ntStatus = AFSReleaseSpecifiedExtents( pExtents,
2330 &pFile->ExtentCount,
2333 if (!NT_SUCCESS(ntStatus))
2336 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2337 AFS_TRACE_LEVEL_ERROR,
2338 "AFSProcessReleaseFileExtents Failed to release extents Status %08lX\n",
2341 try_return( ntStatus );
2344 if( pExtents->ExtentCount == 0)
2347 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2348 AFS_TRACE_LEVEL_WARNING,
2349 "AFSProcessReleaseFileExtents Failed to release ANY extents\n");
2352 ulSz = sizeof(AFSReleaseFileExtentsResultCB);
2354 if( pExtents->ExtentCount > 0)
2356 ulSz += ((pExtents->ExtentCount-1) * sizeof(AFSFileExtentCB));
2359 RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer,
2368 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2369 AFS_TRACE_LEVEL_VERBOSE,
2370 "AFSProcessReleaseFileExtents Releasing Fcb extent lock %08lX thread %08lX\n",
2371 &pFcb->NPFcb->Specific.File.ExtentsResource,
2372 PsGetCurrentThread());
2374 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
2377 if( NULL != pResult &&
2378 Irp->AssociatedIrp.SystemBuffer != pResult)
2381 AFSExFreePool(pResult);
2384 if (NT_SUCCESS(ntStatus))
2386 Irp->IoStatus.Information = ulSz;
2390 Irp->IoStatus.Information = 0;
2393 Irp->IoStatus.Status = ntStatus;
2395 if( pObjectInfo != NULL)
2398 InterlockedDecrement( &pObjectInfo->ObjectReferenceCount);
2400 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
2401 AFS_TRACE_LEVEL_VERBOSE,
2402 "AFSProcessReleaseFileExtents Decrement count on object %08lX Cnt %d\n",
2404 pObjectInfo->ObjectReferenceCount);
2412 AFSWaitForExtentMapping( AFSFcb *Fcb )
2414 NTSTATUS ntStatus = STATUS_SUCCESS;
2415 LARGE_INTEGER liTimeOut;
2416 ULONGLONG ullProcessId = (ULONGLONG)PsGetCurrentProcessId();
2421 ASSERT( !ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
2423 if (!NT_SUCCESS( Fcb->NPFcb->Specific.File.ExtentsRequestStatus))
2427 // If this isn't the same process which caused the failure then try to request them again
2430 if( Fcb->Specific.File.ExtentRequestProcessId == ullProcessId)
2432 try_return( ntStatus = Fcb->NPFcb->Specific.File.ExtentsRequestStatus);
2435 Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
2438 liTimeOut.QuadPart = -(50000000);
2440 ntStatus = KeWaitForSingleObject( &Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
2446 if (!NT_SUCCESS( Fcb->NPFcb->Specific.File.ExtentsRequestStatus))
2450 // If this isn't the same process which caused the failure
2451 // and this isn't the System process, then try to request them again
2454 if( Fcb->Specific.File.ExtentRequestProcessId == ullProcessId ||
2455 ullProcessId == 0x4)
2457 try_return( ntStatus = Fcb->NPFcb->Specific.File.ExtentsRequestStatus);
2460 Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
2463 if( ntStatus == STATUS_TIMEOUT)
2466 ntStatus = STATUS_SUCCESS;
2478 AFSFlushExtents( IN AFSFcb *Fcb,
2481 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
2482 AFSExtent *pExtent, *pNextExtent;
2484 AFSReleaseExtentsCB *pRelease = NULL;
2486 ULONG initialDirtyCount = 0;
2487 BOOLEAN bExtentsLocked = FALSE;
2490 NTSTATUS ntStatus = STATUS_SUCCESS;
2491 LARGE_INTEGER liLastFlush;
2492 AFSExtent *pDirtyListHead = NULL, *pDirtyListTail = NULL;
2493 AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2494 GUID *pAuthGroup = AuthGroup;
2497 ASSERT( Fcb->Header.NodeTypeCode == AFS_FILE_FCB);
2500 // Save, then reset the flush time
2503 liLastFlush = Fcb->Specific.File.LastServerFlush;
2505 KeQueryTickCount( &Fcb->Specific.File.LastServerFlush);
2510 if( pAuthGroup == NULL)
2513 RtlZeroMemory( &stAuthGroup,
2516 ntStatus = AFSRetrieveValidAuthGroup( Fcb,
2521 if( !NT_SUCCESS( ntStatus))
2523 try_return( ntStatus);
2526 pAuthGroup = &stAuthGroup;
2530 // Lock extents while we count and set up the array to send to
2534 AFSLockForExtentsTrim( Fcb);
2536 bExtentsLocked = TRUE;
2538 InterlockedIncrement( &Fcb->Specific.File.QueuedFlushCount);
2541 // Clear our queued flush event
2544 KeClearEvent( &Fcb->NPFcb->Specific.File.QueuedFlushEvent);
2547 // Look for a start in the list to flush entries
2552 sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
2554 pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
2556 AFS_EXTENT_RELEASE_TAG);
2557 if( NULL == pRelease)
2560 try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2563 initialDirtyCount = Fcb->Specific.File.ExtentsDirtyCount;
2565 while( Fcb->Specific.File.ExtentsDirtyCount > 0)
2568 pRelease->Flags = AFS_EXTENT_FLAG_DIRTY;
2570 if( BooleanFlagOn( Fcb->Flags, AFS_FCB_FILE_CLOSED))
2573 pRelease->Flags |= AFS_EXTENT_FLAG_FLUSH;
2577 // Update the metadata for this call
2580 pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
2581 pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
2582 pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
2583 pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
2584 pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
2588 AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
2591 pExtent = (AFSExtent *)pNPFcb->Specific.File.DirtyListHead;
2593 while( count < AFS_MAXIMUM_EXTENT_RELEASE_COUNT)
2596 if ( pExtent == NULL)
2602 pNextExtent = (AFSExtent *)pExtent->DirtyList.fLink;
2604 if ( pExtent->ActiveCount > 0)
2606 pExtent = pNextExtent;
2610 AFSRemoveEntryDirtyList( Fcb, pExtent);
2612 pExtent->DirtyList.fLink = NULL;
2613 pExtent->DirtyList.bLink = NULL;
2615 InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
2618 // Clear the flag in advance of the write. If we do
2619 // things this was we know that the clear is
2620 // pessimistic (any write which happens from now on
2621 // will set the flag dirty again).
2624 pExtent->Flags &= ~AFS_EXTENT_DIRTY;
2626 pRelease->FileExtents[count].Flags = AFS_EXTENT_FLAG_DIRTY;
2628 pRelease->FileExtents[count].Length = pExtent->Size;
2629 pRelease->FileExtents[count].DirtyLength = pExtent->Size;
2630 pRelease->FileExtents[count].DirtyOffset = 0;
2631 pRelease->FileExtents[count].CacheOffset = pExtent->CacheOffset;
2632 pRelease->FileExtents[count].FileOffset = pExtent->FileOffset;
2635 RtlCopyMemory( pRelease->FileExtents[count].MD5,
2637 sizeof(pExtent->MD5));
2639 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_MD5_SET;
2642 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2643 AFS_TRACE_LEVEL_VERBOSE,
2644 "AFSFlushExtents Releasing DIRTY extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
2646 Fcb->ObjectInformation->FileId.Cell,
2647 Fcb->ObjectInformation->FileId.Volume,
2648 Fcb->ObjectInformation->FileId.Vnode,
2649 Fcb->ObjectInformation->FileId.Unique,
2650 pExtent->FileOffset.QuadPart,
2653 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_RELEASE;
2656 // Need to pull this extent from the main list as well
2659 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
2661 if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
2663 RemoveEntryList( &pExtent->Lists[i] );
2667 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
2669 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
2671 AFSExFreePool( pExtent);
2673 InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
2675 if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0)
2678 KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
2685 pExtent = pNextExtent;
2688 AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
2691 // If we are done then get out
2697 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2698 AFS_TRACE_LEVEL_VERBOSE,
2699 "AFSFlushExtents No more dirty extents found\n");
2705 // Fire off the request synchronously
2708 sz = sizeof( AFSReleaseExtentsCB ) + (count * sizeof ( AFSFileExtentCB ));
2710 pRelease->ExtentCount = count;
2712 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2713 AFS_TRACE_LEVEL_VERBOSE,
2714 "AFSFlushExtents Releasing(1) Fcb extents lock %08lX SHARED %08lX\n",
2715 &pNPFcb->Specific.File.ExtentsResource,
2716 PsGetCurrentThread());
2718 AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource);
2719 bExtentsLocked = FALSE;
2721 KeSetEvent( &pNPFcb->Specific.File.FlushEvent,
2725 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS,
2726 AFS_REQUEST_FLAG_SYNCHRONOUS,
2729 &Fcb->ObjectInformation->FileId,
2735 if( !NT_SUCCESS(ntStatus))
2739 // Regardless of whether or not the AFSProcessRequest() succeeded, the extents
2740 // were released (if AFS_EXTENT_FLAG_RELEASE was set). Log the error so it is known.
2743 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2744 AFS_TRACE_LEVEL_ERROR,
2745 "AFSFlushExtents AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
2746 Fcb->ObjectInformation->FileId.Cell,
2747 Fcb->ObjectInformation->FileId.Volume,
2748 Fcb->ObjectInformation->FileId.Vnode,
2749 Fcb->ObjectInformation->FileId.Unique,
2753 AFSLockForExtentsTrim( Fcb);
2755 bExtentsLocked = TRUE;
2760 if( InterlockedDecrement( &Fcb->Specific.File.QueuedFlushCount) == 0)
2763 KeSetEvent( &pNPFcb->Specific.File.QueuedFlushEvent,
2768 KeSetEvent( &pNPFcb->Specific.File.FlushEvent,
2775 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
2776 AFS_TRACE_LEVEL_VERBOSE,
2777 "AFSFlushExtents Releasing(2) Fcb extents lock %08lX SHARED %08lX\n",
2778 &pNPFcb->Specific.File.ExtentsResource,
2779 PsGetCurrentThread());
2781 AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
2786 AFSExFreePool( pRelease);
2794 AFSReleaseExtentsWithFlush( IN AFSFcb *Fcb,
2797 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
2800 AFSReleaseExtentsCB *pRelease = NULL;
2802 ULONG initialDirtyCount = 0;
2803 BOOLEAN bExtentsLocked = FALSE;
2806 NTSTATUS ntStatus = STATUS_SUCCESS;
2807 LARGE_INTEGER liLastFlush;
2808 ULONG ulRemainingExtentLength = 0;
2809 AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
2810 GUID *pAuthGroup = AuthGroup;
2813 ASSERT( Fcb->Header.NodeTypeCode == AFS_FILE_FCB);
2816 // Save, then reset the flush time
2819 liLastFlush = Fcb->Specific.File.LastServerFlush;
2821 KeQueryTickCount( &Fcb->Specific.File.LastServerFlush);
2826 if( pAuthGroup == NULL)
2829 RtlZeroMemory( &stAuthGroup,
2832 ntStatus = AFSRetrieveValidAuthGroup( Fcb,
2837 if( !NT_SUCCESS( ntStatus))
2839 try_return( ntStatus);
2842 pAuthGroup = &stAuthGroup;
2846 // Look for a start in the list to flush entries
2851 sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ));
2853 pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool,
2855 AFS_EXTENT_RELEASE_TAG);
2856 if( NULL == pRelease)
2859 try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
2862 if( Fcb->OpenHandleCount > 0)
2866 // Don't release everything ...
2870 // For now release everything
2873 //ulRemainingExtentLength = 1500;
2876 while( Fcb->Specific.File.ExtentLength > (LONG)ulRemainingExtentLength)
2879 AFSLockForExtentsTrim( Fcb);
2881 bExtentsLocked = TRUE;
2883 pRelease->Flags = AFS_EXTENT_FLAG_RELEASE;
2886 // Update the metadata for this call
2889 pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile;
2890 pRelease->CreateTime = Fcb->ObjectInformation->CreationTime;
2891 pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime;
2892 pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime;
2893 pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime;
2897 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
2899 while( count < AFS_MAXIMUM_EXTENT_RELEASE_COUNT &&
2900 le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
2903 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
2907 if( pExtent->ActiveCount > 0)
2913 pRelease->FileExtents[count].Flags = AFS_EXTENT_FLAG_RELEASE;
2915 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2916 AFS_TRACE_LEVEL_VERBOSE,
2917 "AFSReleaseExtentsWithFlush Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
2919 Fcb->ObjectInformation->FileId.Cell,
2920 Fcb->ObjectInformation->FileId.Volume,
2921 Fcb->ObjectInformation->FileId.Vnode,
2922 Fcb->ObjectInformation->FileId.Unique,
2923 pExtent->FileOffset.QuadPart,
2926 pRelease->FileExtents[count].Length = pExtent->Size;
2927 pRelease->FileExtents[count].DirtyLength = pExtent->Size;
2928 pRelease->FileExtents[count].DirtyOffset = 0;
2929 pRelease->FileExtents[count].CacheOffset = pExtent->CacheOffset;
2930 pRelease->FileExtents[count].FileOffset = pExtent->FileOffset;
2933 RtlCopyMemory( pRelease->FileExtents[count].MD5,
2935 sizeof(pExtent->MD5));
2937 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_MD5_SET;
2940 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
2943 AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
2946 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
2949 AFSRemoveEntryDirtyList( Fcb,
2952 pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_DIRTY;
2954 InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
2957 AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
2961 // Need to pull this extent from the main list as well
2964 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
2966 if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
2968 RemoveEntryList( &pExtent->Lists[i] );
2972 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
2974 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
2976 AFSExFreePool( pExtent);
2978 InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
2980 if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0)
2983 KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
2992 // If we are done then get out
2998 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
2999 AFS_TRACE_LEVEL_VERBOSE,
3000 "AFSReleaseExtentsWithFlush No more dirty extents found\n");
3006 // Fire off the request synchronously
3009 sz = sizeof( AFSReleaseExtentsCB ) + (count * sizeof ( AFSFileExtentCB ));
3011 pRelease->ExtentCount = count;
3014 // Drop the extents lock for the duration of the call to
3015 // the network. We have pinned the extents so, even
3016 // though we might get extents added during this period,
3017 // but none will be removed. Hence we can carry on from
3021 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3022 AFS_TRACE_LEVEL_VERBOSE,
3023 "AFSReleaseExtentsWithFlush Releasing Fcb extents lock %08lX thread %08lX\n",
3024 &pNPFcb->Specific.File.ExtentsResource,
3025 PsGetCurrentThread());
3027 AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource);
3028 bExtentsLocked = FALSE;
3030 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS,
3031 AFS_REQUEST_FLAG_SYNCHRONOUS,
3034 &Fcb->ObjectInformation->FileId,
3040 if( !NT_SUCCESS(ntStatus))
3044 // Regardless of whether or not the AFSProcessRequest() succeeded, the extents
3045 // were released (if AFS_EXTENT_FLAG_RELEASE was set). Log the error so it is known.
3048 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3049 AFS_TRACE_LEVEL_ERROR,
3050 "AFSReleaseExtentsWithFlush AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n",
3051 Fcb->ObjectInformation->FileId.Cell,
3052 Fcb->ObjectInformation->FileId.Volume,
3053 Fcb->ObjectInformation->FileId.Vnode,
3054 Fcb->ObjectInformation->FileId.Unique,
3064 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3065 AFS_TRACE_LEVEL_VERBOSE,
3066 "AFSReleaseExtentsWithFlush Releasing Fcb extents lock %08lX thread %08lX\n",
3067 &pNPFcb->Specific.File.ExtentsResource,
3068 PsGetCurrentThread());
3070 AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource );
3075 AFSExFreePool( pRelease);
3083 AFSMarkDirty( IN AFSFcb *Fcb,
3084 IN AFSExtent *StartExtent,
3085 IN ULONG ExtentsCount,
3086 IN LARGE_INTEGER *StartingByte)
3089 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
3090 AFSExtent *pExtent = StartExtent;
3091 AFSExtent *pNextExtent, *pCurrentExtent = NULL;
3093 BOOLEAN bInsertTail = FALSE, bInsertHead = FALSE;
3095 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3096 AFS_TRACE_LEVEL_VERBOSE,
3097 "AFSMarkDirty Acquiring Fcb extents lock %08lX SHARED %08lX\n",
3098 &Fcb->NPFcb->Specific.File.ExtentsResource,
3099 PsGetCurrentThread());
3101 AFSAcquireShared( &Fcb->NPFcb->Specific.File.ExtentsResource, TRUE);
3103 AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
3107 // Find the insertion point
3110 if( pNPFcb->Specific.File.DirtyListHead == NULL)
3115 else if( StartingByte->QuadPart == 0)
3123 pCurrentExtent = pNPFcb->Specific.File.DirtyListHead;
3125 while( pCurrentExtent != NULL)
3128 if( pCurrentExtent->FileOffset.QuadPart + pCurrentExtent->Size >= StartingByte->QuadPart ||
3129 pCurrentExtent->DirtyList.fLink == NULL)
3135 pCurrentExtent = (AFSExtent *)pCurrentExtent->DirtyList.fLink;
3139 while( ulCount < ExtentsCount)
3142 pNextExtent = NextExtent( pExtent, AFS_EXTENTS_LIST);
3144 if( !BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3147 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3148 AFS_TRACE_LEVEL_VERBOSE,
3149 "AFSMarkDirty Marking extent offset %I64X Length %08lX DIRTY\n",
3150 pExtent->FileOffset.QuadPart,
3153 pExtent->DirtyList.fLink = NULL;
3154 pExtent->DirtyList.bLink = NULL;
3159 pExtent->DirtyList.fLink = (void *)pNPFcb->Specific.File.DirtyListHead;
3161 pExtent->DirtyList.bLink = NULL;
3163 pNPFcb->Specific.File.DirtyListHead->DirtyList.bLink = (void *)pExtent;
3165 pNPFcb->Specific.File.DirtyListHead = pExtent;
3167 pCurrentExtent = pExtent;
3169 bInsertHead = FALSE;
3171 else if( bInsertTail)
3174 if( pNPFcb->Specific.File.DirtyListHead == NULL)
3177 pNPFcb->Specific.File.DirtyListHead = pExtent;
3182 pNPFcb->Specific.File.DirtyListTail->DirtyList.fLink = (void *)pExtent;
3184 pExtent->DirtyList.bLink = (void *)pNPFcb->Specific.File.DirtyListTail;
3187 pNPFcb->Specific.File.DirtyListTail = pExtent;
3192 pExtent->DirtyList.fLink = pCurrentExtent->DirtyList.fLink;
3193 pExtent->DirtyList.bLink = (void *)pCurrentExtent;
3195 if( pExtent->DirtyList.fLink == NULL)
3198 pNPFcb->Specific.File.DirtyListTail = pExtent;
3203 ((AFSExtent *)pExtent->DirtyList.fLink)->DirtyList.bLink = (void *)pExtent;
3206 pCurrentExtent->DirtyList.fLink = (void *)pExtent;
3208 pCurrentExtent = pExtent;
3211 pExtent->Flags |= AFS_EXTENT_DIRTY;
3214 // Up the dirty count
3217 InterlockedIncrement( &Fcb->Specific.File.ExtentsDirtyCount);
3222 pCurrentExtent = pExtent;
3225 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_ACTIVE_COUNTING,
3226 AFS_TRACE_LEVEL_VERBOSE,
3227 "AFSMarkDirty Decrement count on extent %08lX Cnt %d\n",
3229 pExtent->ActiveCount);
3231 ASSERT( pExtent->ActiveCount > 0);
3233 InterlockedDecrement( &pExtent->ActiveCount);
3235 pExtent = pNextExtent;
3240 AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
3242 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3243 AFS_TRACE_LEVEL_VERBOSE,
3244 "AFSMarkDirty Releasing Fcb extents lock %08lX SHARED %08lX\n",
3245 &Fcb->NPFcb->Specific.File.ExtentsResource,
3246 PsGetCurrentThread());
3248 AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource );
3257 static AFSExtent *ExtentFor(PLIST_ENTRY le, ULONG SkipList)
3259 return CONTAINING_RECORD( le, AFSExtent, Lists[SkipList] );
3262 static AFSExtent *NextExtent(AFSExtent *Extent, ULONG SkipList)
3264 return ExtentFor(Extent->Lists[SkipList].Flink, SkipList);
3267 static AFSExtent *DirtyExtentFor(PLIST_ENTRY le)
3269 return CONTAINING_RECORD( le, AFSExtent, DirtyList );
3272 static VOID VerifyExtentsLists(AFSFcb *Fcb)
3276 // Check the ordering of the extents lists
3278 ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource ));
3280 ASSERT(Fcb->Specific.File.ExtentsLists[0].Flink != &Fcb->Specific.File.ExtentsLists[1]);
3282 for (ULONG listNo = 0; listNo < AFS_NUM_EXTENT_LISTS; listNo ++)
3284 LARGE_INTEGER lastOffset;
3286 lastOffset.QuadPart = 0;
3288 for (PLIST_ENTRY pLe = Fcb->Specific.File.ExtentsLists[listNo].Flink;
3289 pLe != &Fcb->Specific.File.ExtentsLists[listNo];
3294 pExtent = ExtentFor(pLe, listNo);
3297 ASSERT(pLe != &Fcb->Specific.File.ExtentsLists[1] &&
3298 pLe->Flink !=&Fcb->Specific.File.ExtentsLists[1] &&
3299 pLe->Blink !=&Fcb->Specific.File.ExtentsLists[1]);
3302 ASSERT(pLe->Flink->Blink == pLe);
3303 ASSERT(pLe->Blink->Flink == pLe);
3306 // Should follow on from previous
3308 ASSERT(pExtent->FileOffset.QuadPart >= lastOffset.QuadPart);
3309 lastOffset.QuadPart = pExtent->FileOffset.QuadPart + pExtent->Size;
3312 // Should match alignment criteria
3314 ASSERT( 0 == (pExtent->FileOffset.LowPart & ExtentsMasks[listNo]) );
3317 // "lower" lists should be populated
3319 for (LONG subListNo = listNo-1; subListNo > 0; subListNo --)
3321 ASSERT( !IsListEmpty(&pExtent->Lists[subListNo]));
3329 AFSTrimExtents( IN AFSFcb *Fcb,
3330 IN PLARGE_INTEGER FileSize)
3333 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
3336 BOOLEAN locked = FALSE;
3337 NTSTATUS ntStatus = STATUS_SUCCESS;
3338 LARGE_INTEGER liAlignedOffset = {0,0};
3339 AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
3340 AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
3346 // Get an aligned offset
3349 if( FileSize != NULL)
3352 liAlignedOffset = *FileSize;
3355 if( liAlignedOffset.QuadPart > 0 &&
3356 liAlignedOffset.QuadPart % pDevExt->Specific.RDR.CacheBlockSize != 0)
3360 // Align UP to the next cache block size
3363 liAlignedOffset.QuadPart = (ULONGLONG)( (ULONGLONG)((liAlignedOffset.QuadPart / pDevExt->Specific.RDR.CacheBlockSize) + 1) * (ULONGLONG)pDevExt->Specific.RDR.CacheBlockSize);
3367 // Ensure that no one is working with the extents and grab the
3371 AFSLockForExtentsTrim( Fcb);
3375 if( 0 == Fcb->Specific.File.ExtentCount)
3379 // Update the request extent status
3382 Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
3384 try_return( ntStatus = STATUS_SUCCESS);
3388 // We are truncating from a specific length in the file. If the offset
3389 // is non-zero then go find the first extent to remove
3392 if( 0 == FileSize->QuadPart)
3395 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
3400 pExtent = AFSExtentForOffset( Fcb,
3404 if( NULL == pExtent)
3407 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
3411 le = &pExtent->Lists[AFS_EXTENTS_LIST];
3415 while( le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST])
3418 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
3421 // Only trim down extents beyond the aligned offset
3426 if( pExtent->FileOffset.QuadPart >= liAlignedOffset.QuadPart)
3429 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3432 AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
3435 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3439 AFSRemoveEntryDirtyList( Fcb,
3442 dirtyCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
3444 ASSERT(dirtyCount >= 0);
3447 AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
3450 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
3452 if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
3454 RemoveEntryList( &pExtent->Lists[i] );
3458 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3459 AFS_TRACE_LEVEL_VERBOSE,
3460 "AFSTrimExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
3462 Fcb->ObjectInformation->FileId.Cell,
3463 Fcb->ObjectInformation->FileId.Volume,
3464 Fcb->ObjectInformation->FileId.Vnode,
3465 Fcb->ObjectInformation->FileId.Unique,
3466 pExtent->FileOffset.QuadPart,
3469 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
3471 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
3473 ASSERT( pExtent->ActiveCount == 0);
3478 AFSExFreePool( pExtent);
3480 InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
3482 if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0)
3485 KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
3493 // Update the request extent status
3496 Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
3503 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3504 AFS_TRACE_LEVEL_VERBOSE,
3505 "AFSTrimExtents Releasing Fcb extents lock %08lX thread %08lX\n",
3506 &Fcb->NPFcb->Specific.File.ExtentsResource,
3507 PsGetCurrentThread());
3509 AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource );
3517 AFSTrimSpecifiedExtents( IN AFSFcb *Fcb,
3519 IN AFSFileExtentCB *Result)
3522 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
3525 AFSFileExtentCB *pFileExtents = Result;
3526 NTSTATUS ntStatus = STATUS_SUCCESS;
3527 AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
3528 AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
3533 le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink;
3535 while( le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST] &&
3539 pExtent = ExtentFor( le, AFS_EXTENTS_LIST);
3542 // Only trim down extents beyond the aligned offset
3547 if( pExtent->FileOffset.QuadPart == pFileExtents->FileOffset.QuadPart)
3550 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3553 AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock,
3556 if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY))
3561 AFSRemoveEntryDirtyList( Fcb,
3564 dirtyCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount);
3566 ASSERT( dirtyCount >= 0);
3570 AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock);
3574 for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++)
3576 if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i]))
3578 RemoveEntryList( &pExtent->Lists[i] );
3582 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
3583 AFS_TRACE_LEVEL_VERBOSE,
3584 "AFSTrimSpecifiedExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n",
3586 Fcb->ObjectInformation->FileId.Cell,
3587 Fcb->ObjectInformation->FileId.Volume,
3588 Fcb->ObjectInformation->FileId.Vnode,
3589 Fcb->ObjectInformation->FileId.Unique,
3590 pExtent->FileOffset.QuadPart,
3593 InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024)));
3595 InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024)));
3597 ASSERT( pExtent->ActiveCount == 0);
3602 AFSExFreePool( pExtent);
3604 InterlockedDecrement( &Fcb->Specific.File.ExtentCount);
3606 if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0)
3609 KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent,
3615 // Next extent we are looking for
3625 // Update the request extent status
3628 Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
3635 AFSReferenceActiveExtents( IN AFSExtent *StartExtent,
3636 IN ULONG ExtentsCount)
3639 AFSExtent *pExtent = StartExtent;
3640 AFSExtent *pNextExtent;
3643 while( ulCount < ExtentsCount)
3646 pNextExtent = NextExtent( pExtent, AFS_EXTENTS_LIST);
3648 InterlockedIncrement( &pExtent->ActiveCount);
3650 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_ACTIVE_COUNTING,
3651 AFS_TRACE_LEVEL_VERBOSE,
3652 "AFSReferenceActiveExtents Increment count on extent %08lX Cnt %d\n",
3654 pExtent->ActiveCount);
3656 pExtent = pNextExtent;
3665 AFSDereferenceActiveExtents( IN AFSExtent *StartExtent,
3666 IN ULONG ExtentsCount)
3669 AFSExtent *pExtent = StartExtent;
3670 AFSExtent *pNextExtent;
3673 while( ulCount < ExtentsCount)
3676 pNextExtent = NextExtent( pExtent, AFS_EXTENTS_LIST);
3678 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_ACTIVE_COUNTING,
3679 AFS_TRACE_LEVEL_VERBOSE,
3680 "AFSDereferenceActiveExtents Decrement count on extent %08lX Cnt %d\n",
3682 pExtent->ActiveCount);
3684 ASSERT( pExtent->ActiveCount > 0);
3686 InterlockedDecrement( &pExtent->ActiveCount);
3688 pExtent = pNextExtent;
3697 AFSRemoveEntryDirtyList( IN AFSFcb *Fcb,
3698 IN AFSExtent *Extent)
3701 if( Extent->DirtyList.fLink == NULL)
3704 Fcb->NPFcb->Specific.File.DirtyListTail = (AFSExtent *)Extent->DirtyList.bLink;
3706 if( Fcb->NPFcb->Specific.File.DirtyListTail != NULL)
3709 Fcb->NPFcb->Specific.File.DirtyListTail->DirtyList.fLink = NULL;
3715 ((AFSExtent *)Extent->DirtyList.fLink)->DirtyList.bLink = Extent->DirtyList.bLink;
3718 if( Extent->DirtyList.bLink == NULL)
3721 Fcb->NPFcb->Specific.File.DirtyListHead = (AFSExtent *)Extent->DirtyList.fLink;
3723 if( Fcb->NPFcb->Specific.File.DirtyListHead != NULL)
3726 Fcb->NPFcb->Specific.File.DirtyListHead->DirtyList.bLink = NULL;
3732 ((AFSExtent *)Extent->DirtyList.bLink)->DirtyList.fLink = Extent->DirtyList.fLink;
3741 AFSSetupMD5Hash( IN AFSFcb *Fcb,
3742 IN AFSExtent *StartExtent,
3743 IN ULONG ExtentsCount,
3744 IN void *SystemBuffer,
3745 IN LARGE_INTEGER *ByteOffset,
3749 NTSTATUS ntStatus = STATUS_SUCCESS;
3750 AFSNonPagedFcb *pNPFcb = Fcb->NPFcb;
3751 AFSExtent *pExtent = StartExtent;
3752 AFSExtent *pNextExtent, *pCurrentExtent = NULL;
3754 char *pCurrentBuffer = (char *)SystemBuffer;
3755 char *pMD5Buffer = NULL;
3756 ULONG ulCurrentLen = 0;
3757 void *pExtentBuffer = NULL;
3758 LARGE_INTEGER liByteOffset;
3759 ULONG ulBytesRead = 0;
3764 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3765 AFS_TRACE_LEVEL_VERBOSE,
3766 "AFSSetupMD5Hash Acquiring Fcb extents lock %08lX SHARED %08lX\n",
3767 &Fcb->NPFcb->Specific.File.ExtentsResource,
3768 PsGetCurrentThread());
3770 AFSAcquireShared( &Fcb->NPFcb->Specific.File.ExtentsResource, TRUE);
3772 liByteOffset.QuadPart = ByteOffset->QuadPart;
3774 while( ulCount < ExtentsCount)
3777 RtlZeroMemory( pExtent->MD5,
3778 sizeof( pExtent->MD5));
3780 pNextExtent = NextExtent( pExtent, AFS_EXTENTS_LIST);
3782 if( liByteOffset.QuadPart == pExtent->FileOffset.QuadPart &&
3783 ByteCount < pExtent->Size)
3786 if( pExtentBuffer == NULL)
3789 pExtentBuffer = AFSExAllocatePoolWithTag( PagedPool,
3791 AFS_GENERIC_MEMORY_9_TAG);
3793 if( pExtentBuffer == NULL)
3800 RtlZeroMemory( pExtentBuffer,
3803 RtlCopyMemory( pExtentBuffer,
3807 pMD5Buffer = (char *)pExtentBuffer;
3809 ulCurrentLen = ByteCount;
3811 else if( liByteOffset.QuadPart != pExtent->FileOffset.QuadPart)
3814 pExtentBuffer = AFSExAllocatePoolWithTag( PagedPool,
3816 AFS_GENERIC_MEMORY_10_TAG);
3818 if( pExtentBuffer == NULL)
3824 RtlZeroMemory( pExtentBuffer,
3827 if( BooleanFlagOn( AFSLibControlFlags, AFS_REDIR_LIB_FLAGS_NONPERSISTENT_CACHE))
3831 RtlCopyMemory( pExtentBuffer,
3832 ((char *)AFSLibCacheBaseAddress + pExtent->CacheOffset.QuadPart),
3835 ASSERT( pExtent->CacheOffset.HighPart == 0);
3836 RtlCopyMemory( pExtentBuffer,
3837 ((char *)AFSLibCacheBaseAddress + pExtent->CacheOffset.LowPart),
3841 ulBytesRead = pExtent->Size;
3846 ntStatus = AFSReadCacheFile( pExtentBuffer,
3847 &pExtent->CacheOffset,
3851 if( !NT_SUCCESS( ntStatus))
3857 pMD5Buffer = (char *)pExtentBuffer;
3859 ulCurrentLen = min( ByteCount, pExtent->Size - (ULONG)(liByteOffset.QuadPart - pExtent->FileOffset.QuadPart));
3861 RtlCopyMemory( (void *)((char *)pExtentBuffer + (ULONG)(liByteOffset.QuadPart - pExtent->FileOffset.QuadPart)),
3868 ulCurrentLen = pExtent->Size;
3870 pMD5Buffer = pCurrentBuffer;
3873 AFSGenerateMD5( pMD5Buffer,
3877 pExtent = pNextExtent;
3881 ByteCount -= ulCurrentLen;
3883 pCurrentBuffer += ulCurrentLen;
3885 liByteOffset.QuadPart += ulCurrentLen;
3888 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
3889 AFS_TRACE_LEVEL_VERBOSE,
3890 "AFSSetupMD5Hash Releasing Fcb extents lock %08lX SHARED %08lX\n",
3891 &Fcb->NPFcb->Specific.File.ExtentsResource,
3892 PsGetCurrentThread());
3894 AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource );
3896 if( pExtentBuffer != NULL)
3899 AFSExFreePool( pExtentBuffer);