- Define RxShouldPostCompletion() and use it
- Define RxIsResourceOwnershipStateExclusive() and use it
- Define some magic values

[RDBSS]
- Implement CheckForLoudOperations(), RxAdjustFileTimesAndSize(), RxIsOkToPurgeFcb()
- Continue implementation of RxCommonCleanup()
- Fix bugs in the RxCommonCleanup() implementation and make it more explicit when in the delete on close path
- Stub RxCleanupPipeQueues(), RxLowIoLockControlShell()
- Silent a few DPRINTs

CORE-8204
CORE-11327

svn path=/trunk/; revision=75307
This commit is contained in:
Pierre Schweitzer 2017-07-08 17:12:33 +00:00
parent f45220c16f
commit ae1901b2c3
6 changed files with 292 additions and 31 deletions

View file

@ -200,6 +200,7 @@ typedef struct _FCB
} FCB, *PFCB;
#define FCB_STATE_DELETE_ON_CLOSE 0x00000001
#define FCB_STATE_TRUNCATE_ON_CLOSE 0x00000002
#define FCB_STATE_PAGING_FILE 0x00000004
#define FCB_STATE_DISABLE_LOCAL_BUFFERING 0x00000010
#define FCB_STATE_TEMPORARY 0x00000020
@ -287,6 +288,9 @@ typedef struct _SRV_OPEN
#define FOBX_FLAG_MATCH_ALL 0x10000
#define FOBX_FLAG_FREE_UNICODE 0x20000
#define FOBX_FLAG_USER_SET_LAST_WRITE 0x40000
#define FOBX_FLAG_USER_SET_LAST_ACCESS 0x80000
#define FOBX_FLAG_USER_SET_LAST_CHANGE 0x200000
#define FOBX_FLAG_DELETE_ON_CLOSE 0x800000
#define FOBX_FLAG_SRVOPEN_CLOSED 0x1000000
#define FOBX_FLAG_UNC_NAME 0x2000000

View file

@ -1,6 +1,8 @@
#ifndef _RXMINIRDR_
#define _RXMINIRDR_
#define RxShouldPostCompletion() ((KeGetCurrentIrql() >= DISPATCH_LEVEL))
#define RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS 0x00000001
#define RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS 0x00000002
#define RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH 0x00000004
@ -313,6 +315,7 @@ typedef struct _LOWIO_CONTEXT
} LOWIO_CONTEXT;
#define LOWIO_CONTEXT_FLAG_SYNCCALL 0x01
#define LOWIO_CONTEXT_FLAG_SAVEUNLOCKS 0x2
#define LOWIO_CONTEXT_FLAG_LOUDOPS 0x04
#define LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL 0x08

View file

@ -9,9 +9,13 @@
#define RxAllocatePoolWithTag ExAllocatePoolWithTag
#define RxFreePool ExFreePool
#define RxIsResourceOwnershipStateExclusive(Resource) (FlagOn((Resource)->Flag, ResourceOwnedExclusive))
#define RxMdlIsLocked(Mdl) ((Mdl)->MdlFlags & MDL_PAGES_LOCKED)
#define RxMdlSourceIsNonPaged(Mdl) ((Mdl)->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL)
#define RxGetRequestorProcess(RxContext) IoGetRequestorProcess(RxContext->CurrentIrp)
#define RxAdjustAllocationSizeforCC(Fcb) \
{ \
if ((Fcb)->Header.FileSize.QuadPart > (Fcb)->Header.AllocationSize.QuadPart) \

View file

@ -116,6 +116,9 @@ RxMapSystemBuffer(
#define FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE 3
#define FCB_MODE_SHARED_STARVE_EXCLUSIVE 4
#define CHANGE_BUFFERING_STATE_CONTEXT ((PRX_CONTEXT)IntToPtr(0xffffffff))
#define CHANGE_BUFFERING_STATE_CONTEXT_WAIT ((PRX_CONTEXT)IntToPtr(0xfffffffe))
NTSTATUS
__RxAcquireFcb(
_Inout_ PFCB Fcb,
@ -374,6 +377,18 @@ RxFindOrConstructVirtualNetRoot(
_In_ PUNICODE_STRING RemainingName);
#endif
#if (_WIN32_WINNT >= 0x0600)
NTSTATUS
RxLowIoLockControlShell(
_In_ PRX_CONTEXT RxContext,
_In_ PIRP Irp,
_In_ PFCB Fcb);
#else
NTSTATUS
RxLowIoLockControlShell(
_In_ PRX_CONTEXT RxContext);
#endif
NTSTATUS
NTAPI
RxChangeBufferingState(

View file

@ -491,6 +491,7 @@ NPAGED_LOOKASIDE_LIST RxContextLookasideList;
FAST_MUTEX RxContextPerFileSerializationMutex;
RDBSS_DATA RxData;
FCB RxDeviceFCB;
BOOLEAN RxLoudLowIoOpsEnabled = FALSE;
RX_FSD_DISPATCH_VECTOR RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION + 1] =
{
{ RxCommonDispatchProblem },
@ -593,11 +594,31 @@ DECLARE_CONST_UNICODE_STRING(unknownId, L"???");
/* FUNCTIONS ****************************************************************/
/*
* @implemented
*/
VOID
CheckForLoudOperations(
PRX_CONTEXT RxContext)
{
UNIMPLEMENTED;
PAGED_CODE();
#define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL))
/* Are loud operations enabled? */
if (RxLoudLowIoOpsEnabled)
{
PFCB Fcb;
/* If so, the operation will be loud only if filename ends with all.scr */
Fcb = (PFCB)RxContext->pFcb;
if (RtlCompareMemory(Add2Ptr(Fcb->PrivateAlreadyPrefixedName.Buffer, (Fcb->PrivateAlreadyPrefixedName.Length - ALLSCR_LENGTH)),
L"all.scr", ALLSCR_LENGTH) == ALLSCR_LENGTH)
{
SetFlag(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_LOUDOPS);
}
}
#undef ALLSCR_LENGTH
}
/*
@ -746,6 +767,106 @@ RxAddToWorkque(
ExQueueWorkItem((PWORK_QUEUE_ITEM)&RxContext->WorkQueueItem, Queue);
}
/*
* @implemented
*/
VOID
RxAdjustFileTimesAndSize(
PRX_CONTEXT Context)
{
PFCB Fcb;
PFOBX Fobx;
NTSTATUS Status;
PFILE_OBJECT FileObject;
LARGE_INTEGER CurrentTime;
FILE_BASIC_INFORMATION FileBasicInfo;
FILE_END_OF_FILE_INFORMATION FileEOFInfo;
BOOLEAN FileModified, SetLastChange, SetLastAccess, SetLastWrite, NeedUpdate;
PAGED_CODE();
FileObject = Context->CurrentIrpSp->FileObject;
/* If Cc isn't initialized, the file was not read nor written, nothing to do */
if (FileObject->PrivateCacheMap == NULL)
{
return;
}
/* Get now */
KeQuerySystemTime(&CurrentTime);
Fobx = (PFOBX)Context->pFobx;
/* Was the file modified? */
FileModified = BooleanFlagOn(FileObject->Flags, FO_FILE_MODIFIED);
/* We'll set last write if it was modified and user didn't update yet */
SetLastWrite = FileModified && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
/* File was accessed if: written or read (fastio), we'll update last access if user didn't */
SetLastAccess = SetLastWrite ||
(BooleanFlagOn(FileObject->Flags, FO_FILE_FAST_IO_READ) &&
!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS));
/* We'll set last change if it was modified and user didn't update yet */
SetLastChange = FileModified && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
/* Nothing to update? Job done */
if (!FileModified && !SetLastWrite && !SetLastAccess && !SetLastChange)
{
return;
}
Fcb = (PFCB)Context->pFcb;
/* By default, we won't issue any MRxSetFileInfoAtCleanup call */
NeedUpdate = FALSE;
RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
/* Update lastwrite time if required */
if (SetLastWrite)
{
NeedUpdate = TRUE;
Fcb->LastWriteTime.QuadPart = CurrentTime.QuadPart;
FileBasicInfo.LastWriteTime.QuadPart = CurrentTime.QuadPart;
}
/* Update lastaccess time if required */
if (SetLastAccess)
{
NeedUpdate = TRUE;
Fcb->LastAccessTime.QuadPart = CurrentTime.QuadPart;
FileBasicInfo.LastAccessTime.QuadPart = CurrentTime.QuadPart;
}
/* Update lastchange time if required */
if (SetLastChange)
{
NeedUpdate = TRUE;
Fcb->LastChangeTime.QuadPart = CurrentTime.QuadPart;
FileBasicInfo.ChangeTime.QuadPart = CurrentTime.QuadPart;
}
/* If one of the date was modified, issue a call to mini-rdr */
if (NeedUpdate)
{
Context->Info.FileInformationClass = FileBasicInformation;
Context->Info.Buffer = &FileBasicInfo;
Context->Info.Length = sizeof(FileBasicInfo);
MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxSetFileInfoAtCleanup, (Context));
(void)Status;
}
/* If the file was modified, update its EOF */
if (FileModified)
{
FileEOFInfo.EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
Context->Info.FileInformationClass = FileEndOfFileInformation;
Context->Info.Buffer = &FileEOFInfo;
Context->Info.Length = sizeof(FileEOFInfo);
MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxSetFileInfoAtCleanup, (Context));
(void)Status;
}
}
/*
* @implemented
*/
@ -1069,6 +1190,13 @@ RxCheckShareAccessPerSrvOpens(
return STATUS_SUCCESS;
}
VOID
RxCleanupPipeQueues(
PRX_CONTEXT Context)
{
UNIMPLEMENTED;
}
/*
* @implemented
*/
@ -1462,8 +1590,9 @@ RxCommonCleanup(
NTSTATUS Status;
PNET_ROOT NetRoot;
PFILE_OBJECT FileObject;
PLARGE_INTEGER TruncateSize;
BOOLEAN NeedPurge, FcbTableAcquired, OneLeft, IsFile, FcbAcquired;
LARGE_INTEGER TruncateSize;
PLARGE_INTEGER TruncateSizePtr;
BOOLEAN NeedPurge, FcbTableAcquired, OneLeft, IsFile, FcbAcquired, LeftForDelete;
PAGED_CODE();
@ -1545,12 +1674,13 @@ RxCommonCleanup(
NetRoot = (PNET_ROOT)Fcb->pNetRoot;
FcbTableAcquired = FALSE;
OneLeft = FALSE;
LeftForDelete = FALSE;
OneLeft = (Fcb->UncleanCount == 1);
_SEH2_TRY
{
/* Unclean count and delete on close? Verify whether we're the one */
if (Fcb->UncleanCount == 1 && BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE))
if (OneLeft && BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE))
{
if (RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
{
@ -1572,9 +1702,10 @@ RxCommonCleanup(
FcbTableAcquired = TRUE;
}
/* That means we'll perform the delete on close! */
if (Fcb->UncleanCount == 1)
{
OneLeft = TRUE;
LeftForDelete = TRUE;
}
else
{
@ -1584,18 +1715,82 @@ RxCommonCleanup(
}
IsFile = FALSE;
TruncateSize = NULL;
TruncateSizePtr = NULL;
/* Handle cleanup for pipes and printers */
if (NetRoot->Type == NET_ROOT_PIPE || NetRoot->Type == NET_ROOT_PRINT)
{
UNIMPLEMENTED;
RxCleanupPipeQueues(Context);
}
/* Handle cleanup for files */
else if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD)
{
Context->LowIoContext.Flags |= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS;
if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
{
UNIMPLEMENTED;
/* First, unlock */
FsRtlFastUnlockAll(&Fcb->Specific.Fcb.FileLock, FileObject, RxGetRequestorProcess(Context), Context);
/* If there are still locks to release, proceed */
if (Context->LowIoContext.ParamsFor.Locks.LockList != NULL)
{
RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_UNLOCK_MULTIPLE);
Context->LowIoContext.ParamsFor.Locks.Flags = 0;
Status = RxLowIoLockControlShell(Context);
}
/* Fix times and size */
RxAdjustFileTimesAndSize(Context);
/* If we're the only one left... */
if (OneLeft)
{
/* And if we're supposed to delete on close */
if (LeftForDelete)
{
/* Update the sizes */
RxAcquirePagingIoResource(Context, Fcb);
Fcb->Header.FileSize.QuadPart = 0;
Fcb->Header.ValidDataLength.QuadPart = 0;
RxReleasePagingIoResource(Context, Fcb);
}
/* Otherwise, call the mini-rdr to adjust sizes */
else
{
/* File got grown up, fill with zeroes */
if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
(Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart))
{
MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxZeroExtend, (Context));
Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
}
/* File was truncated, let mini-rdr proceed */
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE))
{
MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxTruncate, (Context));
ClearFlag(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE);
/* Keep track of file change for Cc uninit */
TruncateSize.QuadPart = Fcb->Header.FileSize.QuadPart;
TruncateSizePtr = &TruncateSize;
}
}
}
/* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
if (NeedPurge)
{
if (!OneLeft)
{
NeedPurge = FALSE;
}
}
/* Otherwise, try to see whether we can purge */
else
{
NeedPurge = (OneLeft && (LeftForDelete || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED)));
}
IsFile = TRUE;
}
}
@ -1622,7 +1817,7 @@ RxCommonCleanup(
if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL &&
Fcb->UncleanCount == Fcb->UncachedUncleanCount)
{
DPRINT1("Flushing %p due to last cached handle cleanup\n", Context);
DPRINT("Flushing %p due to last cached handle cleanup\n", Context);
RxFlushFcbInSystemCache(Fcb, TRUE);
}
}
@ -1631,7 +1826,7 @@ RxCommonCleanup(
/* Always */
if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
{
DPRINT1("Flushing %p on cleanup\n", Context);
DPRINT("Flushing %p on cleanup\n", Context);
RxFlushFcbInSystemCache(Fcb, TRUE);
}
}
@ -1644,32 +1839,32 @@ RxCommonCleanup(
if (Fcb->UncachedUncleanCount == Fcb->UncleanCount &&
Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
{
DPRINT1("Flushing FCB in system cache for %p\n", Context);
DPRINT("Flushing FCB in system cache for %p\n", Context);
RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
}
}
}
/* If purge required, flush */
if (!OneLeft && NeedPurge)
/* If purge required, and not about to delete, flush */
if (!LeftForDelete && NeedPurge)
{
DPRINT1("Flushing FCB in system cache for %p\n", Context);
DPRINT("Flushing FCB in system cache for %p\n", Context);
RxFlushFcbInSystemCache(Fcb, TRUE);
}
/* If it was a file, drop cache */
if (IsFile)
{
DPRINT1("Uninit cache map for file\n");
RxUninitializeCacheMap(Context, FileObject, TruncateSize);
DPRINT("Uninit cache map for file\n");
RxUninitializeCacheMap(Context, FileObject, TruncateSizePtr);
}
/* If that's the one left, or if it needs purge, flush */
if (OneLeft || NeedPurge)
/* If that's the one left for deletion, or if it needs purge, flush */
if (LeftForDelete || NeedPurge)
{
RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, !OneLeft);
/* Also remove from FCB table */
if (OneLeft)
RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, !LeftForDelete);
/* If that's for deletion, also remove from FCB table */
if (LeftForDelete)
{
RxRemoveNameNetFcb(Fcb);
RxReleaseFcbTableLock(&NetRoot->FcbTable);
@ -4943,12 +5138,43 @@ RxIsMemberOfTopLevelIrpAllocatedContextsList(
return Found;
}
/*
* @implemented
*/
BOOLEAN
RxIsOkToPurgeFcb(
PFCB Fcb)
{
UNIMPLEMENTED;
return FALSE;
PLIST_ENTRY Entry;
/* No associated SRV_OPEN, it's OK to purge */
if (IsListEmpty(&Fcb->SrvOpenList))
{
return TRUE;
}
/* Only allow to purge if all the associated SRV_OPEN
* - have no outstanding opens ongoing
* - have only read attribute set
*/
for (Entry = Fcb->SrvOpenList.Flink;
Entry != &Fcb->SrvOpenList;
Entry = Entry->Flink)
{
PSRV_OPEN SrvOpen;
SrvOpen = CONTAINING_RECORD(Entry, SRV_OPEN, SrvOpenQLinks);
/* Failing previous needs, don't allow purge */
if (SrvOpen->UncleanFobxCount != 0 ||
(SrvOpen->DesiredAccess & 0xFFEFFFFF) != FILE_READ_ATTRIBUTES)
{
return FALSE;
}
}
/* All correct, allow purge */
return TRUE;
}
/*
@ -5091,6 +5317,14 @@ RxLowIoIoCtlShellCompletion(
return Status;
}
NTSTATUS
RxLowIoLockControlShell(
IN PRX_CONTEXT RxContext)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/

View file

@ -5116,7 +5116,7 @@ RxLowIoCompletionTail(
DPRINT("RxLowIoCompletionTail(%p)\n", RxContext);
/* Only continue if we're at APC_LEVEL or lower */
if (KeGetCurrentIrql() >= DISPATCH_LEVEL &&
if (RxShouldPostCompletion() &&
!BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL))
{
return STATUS_MORE_PROCESSING_REQUIRED;
@ -5755,7 +5755,8 @@ RxpDereferenceAndFinalizeNetFcb(
if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
{
if (RxContext != NULL && RxContext != (PVOID)-1 && RxContext != (PVOID)-2)
if (RxContext != NULL && RxContext != CHANGE_BUFFERING_STATE_CONTEXT &&
RxContext != CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
{
RxContext->Flags |= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK;
}
@ -7807,11 +7808,11 @@ RxTrackerUpdateHistory(
{
Case = RX_FCBTRACKER_CASE_NULLCONTEXT;
}
else if ((ULONG_PTR)RxContext == -1)
else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT)
{
Case = RX_FCBTRACKER_CASE_CBS_CONTEXT;
}
else if ((ULONG_PTR)RxContext == -2)
else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
{
Case = RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT;
}
@ -8211,7 +8212,7 @@ __RxAcquireFcb(
SpecialContext = FALSE;
ContextIsPresent = FALSE;
/* Check for special context */
if ((ULONG_PTR)RxContext == -1 || (ULONG_PTR)RxContext == -2)
if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT || RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
{
SpecialContext = TRUE;
}
@ -8374,7 +8375,7 @@ __RxReleaseFcb(
RxAcquireSerializationMutex();
BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
IsExclusive = BooleanFlagOn(MrxFcb->Header.Resource->Flag, ResourceOwnedExclusive);
IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource);
/* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
* then just release the FCB
@ -8421,7 +8422,7 @@ __RxReleaseFcbForThread(
RxAcquireSerializationMutex();
BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
IsExclusive = BooleanFlagOn(MrxFcb->Header.Resource->Flag, ResourceOwnedExclusive);
IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource);
/* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
* then just release the FCB