#include <pseh/pseh2.h>
#include <limits.h>
#include <dfs.h>
+#include <copysup.h>
#define NDEBUG
#include <debug.h>
FILE_INFORMATION_CLASS FileInfoClass,
PVOID Buffer);
+VOID
+RxPurgeNetFcb(
+ PFCB Fcb,
+ PRX_CONTEXT LocalContext);
+
NTSTATUS
RxQueryAlternateNameInfo(
PRX_CONTEXT RxContext,
return STATUS_SUCCESS;
}
+VOID
+RxCancelNotifyChangeDirectoryRequestsForFobx(
+ PFOBX Fobx)
+{
+ UNIMPLEMENTED;
+}
+
VOID
NTAPI
RxCancelRoutine(
return Status;
}
-NTSTATUS
-NTAPI
-RxChangeBufferingState(
- PSRV_OPEN SrvOpen,
- PVOID Context,
- BOOLEAN ComputeNewState)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
VOID
NTAPI
RxCheckFcbStructuresForAlignment(
return STATUS_SUCCESS;
}
+/*
+ * @implemented
+ */
NTSTATUS
RxCloseAssociatedSrvOpen(
IN PFOBX Fobx,
IN PRX_CONTEXT RxContext OPTIONAL)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ PFCB Fcb;
+ NTSTATUS Status;
+ PSRV_OPEN SrvOpen;
+ BOOLEAN CloseSrvOpen;
+ PRX_CONTEXT LocalContext;
+
+ PAGED_CODE();
+
+ /* Assume SRV_OPEN is already closed */
+ CloseSrvOpen = FALSE;
+ /* If we have a FOBX, we'll have to close it */
+ if (Fobx != NULL)
+ {
+ /* If the FOBX isn't closed yet */
+ if (!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
+ {
+ SrvOpen = Fobx->SrvOpen;
+ Fcb = (PFCB)SrvOpen->pFcb;
+ /* Check whether we've to close SRV_OPEN first */
+ if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
+ {
+ CloseSrvOpen = TRUE;
+ }
+ else
+ {
+ ASSERT(RxIsFcbAcquiredExclusive(Fcb));
+
+ /* Not much to do */
+ SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
+
+ if (SrvOpen->OpenCount > 0)
+ {
+ --SrvOpen->OpenCount;
+ }
+ }
+ }
+
+ /* No need to close SRV_OPEN, so close FOBX */
+ if (!CloseSrvOpen)
+ {
+ RxMarkFobxOnClose(Fobx);
+
+ return STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ /* No FOBX? No RX_CONTEXT, ok, job done! */
+ if (RxContext == NULL)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ /* Get the FCB from RX_CONTEXT */
+ Fcb = (PFCB)RxContext->pFcb;
+ SrvOpen == NULL;
+ }
+
+ /* If we don't have RX_CONTEXT, allocte one, we'll need it */
+ if (RxContext == NULL)
+ {
+ ASSERT(Fobx != NULL);
+
+ LocalContext = RxCreateRxContext(NULL, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING | RX_CONTEXT_FLAG_WAIT);
+ if (LocalContext == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ LocalContext->MajorFunction = 2;
+ LocalContext->pFcb = RX_GET_MRX_FCB(Fcb);
+ LocalContext->pFobx = (PMRX_FOBX)Fobx;
+ LocalContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)Fobx->SrvOpen;
+ }
+ else
+ {
+ LocalContext = RxContext;
+ }
+
+ ASSERT(RxIsFcbAcquiredExclusive(Fcb));
+
+ /* Now, close the FOBX */
+ if (Fobx != NULL)
+ {
+ RxMarkFobxOnClose(Fobx);
+ }
+ else
+ {
+ InterlockedDecrement((volatile long *)&Fcb->OpenCount);
+ }
+
+ /* If not a "standard" file, SRV_OPEN can be null */
+ if (SrvOpen == NULL)
+ {
+ ASSERT((NodeType(Fcb) == RDBSS_NTC_OPENTARGETDIR_FCB) || (NodeType(Fcb) == RDBSS_NTC_IPC_SHARE) || (NodeType(Fcb) == RDBSS_NTC_MAILSLOT));
+ RxDereferenceNetFcb(Fcb);
+
+ if (LocalContext != RxContext)
+ {
+ RxDereferenceAndDeleteRxContext(LocalContext);
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ /* If SRV_OPEN isn't in a good condition, nothing to close */
+ if (SrvOpen->Condition != Condition_Good)
+ {
+ if (LocalContext != RxContext)
+ {
+ RxDereferenceAndDeleteRxContext(LocalContext);
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ /* Decrease open count */
+ if (SrvOpen->OpenCount > 0)
+ {
+ --SrvOpen->OpenCount;
+ }
+
+ /* If we're the only one left, is there a FOBX handled by Scavenger? */
+ if (SrvOpen->OpenCount == 1)
+ {
+ if (!IsListEmpty(&SrvOpen->FobxList))
+ {
+ if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks)->ScavengerFinalizationList))
+ {
+ SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
+ }
+ }
+ }
+
+ /* Nothing left, purge FCB */
+ if (SrvOpen->OpenCount == 0 && RxContext == NULL)
+ {
+ RxPurgeNetFcb(Fcb, LocalContext);
+ }
+
+ /* Already closed? Job done! */
+ SrvOpen = Fobx->SrvOpen;
+ if (SrvOpen == NULL ||
+ (SrvOpen->OpenCount != 0 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING)) ||
+ BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
+ {
+ SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
+ if (LocalContext != RxContext)
+ {
+ RxDereferenceAndDeleteRxContext(LocalContext);
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ ASSERT(RxIsFcbAcquiredExclusive(Fcb));
+
+ /* Inform mini-rdr about closing */
+ MINIRDR_CALL(Status, LocalContext, Fcb->MRxDispatch, MRxCloseSrvOpen, (LocalContext));
+ DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
+ Status, RxContext, Fobx, Fcb, SrvOpen);
+
+ /* And mark as such */
+ SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED);
+ SrvOpen->Key = (PVOID)-1;
+
+ /* If we were delayed, we're not! */
+ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
+ {
+ InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles);
+ }
+
+ /* Clear access */
+ RxRemoveShareAccessPerSrvOpens(SrvOpen);
+ RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen);
+
+ /* Dereference */
+ RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
+
+ /* Mark the FOBX closed as well */
+ SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
+
+ if (LocalContext != RxContext)
+ {
+ RxDereferenceAndDeleteRxContext(LocalContext);
+ }
+
+ return Status;
}
/*
#define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
PFCB Fcb;
PFOBX Fobx;
+ ULONG OpenCount;
NTSTATUS Status;
- BOOLEAN NeedPurge;
+ PNET_ROOT NetRoot;
PFILE_OBJECT FileObject;
+ PLARGE_INTEGER TruncateSize;
+ BOOLEAN NeedPurge, FcbTableAcquired, OneLeft, IsFile, FcbAcquired;
PAGED_CODE();
return Status;
}
+ FcbAcquired = TRUE;
+
Fobx->AssociatedFileObject = NULL;
/* In case SRV_OPEN used is part of FCB */
return STATUS_SUCCESS;
}
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ /* Report the fact that file could be set as delete on close */
+ if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
+ {
+ SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
+ }
+
+ /* Cancel any pending notification */
+ RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx);
+
+ /* Backup open count before we start playing with it */
+ OpenCount = Fcb->ShareAccess.OpenCount;
+
+ NetRoot = (PNET_ROOT)Fcb->pNetRoot;
+ FcbTableAcquired = FALSE;
+ OneLeft = FALSE;
+
+ _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 (RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
+ {
+ FcbTableAcquired = TRUE;
+ }
+ else
+ {
+ RxReleaseFcb(Context, Fcb);
+
+ RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
+
+ Status = RxAcquireExclusiveFcb(Context, Fcb);
+ if (Status != STATUS_SUCCESS)
+ {
+ RxReleaseFcbTableLock(&NetRoot->FcbTable);
+ return Status;
+ }
+
+ FcbTableAcquired = TRUE;
+ }
+
+ if (Fcb->UncleanCount == 1)
+ {
+ OneLeft = TRUE;
+ }
+ else
+ {
+ RxReleaseFcbTableLock(&NetRoot->FcbTable);
+ FcbTableAcquired = FALSE;
+ }
+ }
+
+ IsFile = FALSE;
+ TruncateSize = NULL;
+ /* Handle cleanup for pipes and printers */
+ if (NetRoot->Type == NET_ROOT_PIPE || NetRoot->Type == NET_ROOT_PRINT)
+ {
+ UNIMPLEMENTED;
+ }
+ /* Handle cleanup for files */
+ else if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD)
+ {
+ if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
+ {
+ UNIMPLEMENTED;
+ IsFile = TRUE;
+ }
+ }
+
+ /* We have to still be there! */
+ ASSERT(Fcb->UncleanCount != 0);
+ InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
+
+ if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
+ {
+ --Fcb->UncachedUncleanCount;
+ }
+
+ /* Inform mini-rdr about ongoing cleanup */
+ MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
+
+ ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
+ --Fobx->SrvOpen->UncleanFobxCount;
+
+ /* Flush cache */
+ if (DisableFlushOnCleanup)
+ {
+ /* Only if we're the last standing */
+ if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL &&
+ Fcb->UncleanCount == Fcb->UncachedUncleanCount)
+ {
+ DPRINT1("Flushing %p due to last cached handle cleanup\n", Context);
+ RxFlushFcbInSystemCache(Fcb, TRUE);
+ }
+ }
+ else
+ {
+ /* Always */
+ if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
+ {
+ DPRINT1("Flushing %p on cleanup\n", Context);
+ RxFlushFcbInSystemCache(Fcb, TRUE);
+ }
+ }
+
+ /* If only remaining uncached & unclean, then flush and purge */
+ if (!BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
+ {
+ if (Fcb->UncachedUncleanCount != 0)
+ {
+ if (Fcb->UncachedUncleanCount == Fcb->UncleanCount &&
+ Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
+ {
+ DPRINT1("Flushing FCB in system cache for %p\n", Context);
+ RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
+ }
+ }
+ }
+
+ /* If purge required, flush */
+ if (!OneLeft && NeedPurge)
+ {
+ DPRINT1("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);
+ }
+
+ /* If that's the one left, or if it needs purge, flush */
+ if (OneLeft || NeedPurge)
+ {
+ RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, !OneLeft);
+ /* Also remove from FCB table */
+ if (OneLeft)
+ {
+ RxRemoveNameNetFcb(Fcb);
+ RxReleaseFcbTableLock(&NetRoot->FcbTable);
+ FcbTableAcquired = FALSE;
+ }
+ }
+
+ /* Remove any share access */
+ if (OpenCount != 0 && NetRoot->Type == NET_ROOT_DISK)
+ {
+ RxRemoveShareAccess(FileObject, &Fcb->ShareAccess, "Cleanup the share access", "ClnUpShr");
+ }
+
+ /* In case there's caching, on a file, update file metadata */
+ if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE && BooleanFlagOn(Fobx->Flags, 0x20000000) &&
+ BooleanFlagOn(Fcb->FcbState, FCB_STATE_WRITECACHING_ENABLED) && !BooleanFlagOn(Fobx->pSrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_WRITE_CACHING))
+ {
+ UNIMPLEMENTED;
+ }
+
+ /* We're clean! */
+ SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
+
+ FcbAcquired = FALSE;
+ RxReleaseFcb(Context, Fcb);
+ }
+ _SEH2_FINALLY
+ {
+ if (FcbAcquired)
+ {
+ RxReleaseFcb(Context, Fcb);
+ }
+
+ if (FcbTableAcquired)
+ {
+ RxReleaseFcbTableLock(&NetRoot->FcbTable);
+ }
+ }
+ _SEH2_END;
+
+ return Status;
#undef BugCheckFileId
}
PIO_STATUS_BLOCK IoStatus,
PDEVICE_OBJECT DeviceObject)
{
+ PFCB Fcb;
+ PSRV_OPEN SrvOpen;
+
+ PAGED_CODE();
+
+ /* Get the FCB to validate it */
+ Fcb = FileObject->FsContext;
+ if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE)
+ {
+ DPRINT1("Not a file, FastIO not possible!\n");
+ return FALSE;
+ }
+
+ if (FileObject->DeletePending)
+ {
+ DPRINT1("File delete pending\n");
+ return FALSE;
+ }
+
+ /* If there's a pending write operation, deny fast operation */
+ if (Fcb->NonPaged->OutstandingAsyncWrites != 0)
+ {
+ DPRINT1("Write operations to be completed\n");
+ return FALSE;
+ }
+
+ /* Deny read on orphaned node */
+ SrvOpen = (PSRV_OPEN)((PFOBX)FileObject->FsContext2)->pSrvOpen;
+ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_ORPHANED))
+ {
+ DPRINT1("SRV_OPEN orphaned\n");
+ return FALSE;
+ }
+
+ if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
+ {
+ DPRINT1("FCB orphaned\n");
+ return FALSE;
+ }
+
+ /* If there's a buffering state change pending, deny fast operation (it might change
+ * cache status)
+ */
+ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
+ {
+ DPRINT1("Buffering change pending\n");
+ return FALSE;
+ }
+
+ /* File got renamed/deleted, deny operation */
+ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED) ||
+ BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED))
+ {
+ DPRINT1("File renamed/deleted\n");
+ return FALSE;
+ }
+
+ /* Process pending change buffering state operations */
+ FsRtlEnterFileSystem();
+ RxProcessChangeBufferingStateRequestsForSrvOpen(SrvOpen);
+ FsRtlExitFileSystem();
+
+ /* If operation to come is a read operation */
+ if (CheckForReadOperation)
+ {
+ LARGE_INTEGER LargeLength;
+
+ /* Check that read cache is enabled */
+ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED))
+ {
+ DPRINT1("Read caching disabled\n");
+ return FALSE;
+ }
+
+ /* Check whether there's a lock conflict */
+ LargeLength.QuadPart = Length;
+ if (!FsRtlFastCheckLockForRead(&Fcb->Specific.Fcb.FileLock,
+ FileOffset,
+ &LargeLength,
+ LockKey,
+ FileObject,
+ PsGetCurrentProcess()))
+ {
+ DPRINT1("FsRtlFastCheckLockForRead failed\n");
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
UNIMPLEMENTED;
return FALSE;
}
}
}
+/*
+ * @implemented
+ */
BOOLEAN
NTAPI
RxFastIoRead(
PIO_STATUS_BLOCK IoStatus,
PDEVICE_OBJECT DeviceObject)
{
- UNIMPLEMENTED;
- return FALSE;
+ BOOLEAN Ret;
+ RX_TOPLEVELIRP_CONTEXT TopLevelContext;
+
+ PAGED_CODE();
+
+ DPRINT("RxFastIoRead: %p (%p, %p)\n", FileObject, FileObject->FsContext,
+ FileObject->FsContext2);
+ DPRINT("Reading %ld at %I64x\n", Length, FileOffset->QuadPart);
+
+ /* Prepare a TLI context */
+ ASSERT(RxIsThisTheTopLevelIrp(NULL));
+ RxInitializeTopLevelIrpContext(&TopLevelContext, (PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP,
+ (PRDBSS_DEVICE_OBJECT)DeviceObject);
+
+ Ret = FsRtlCopyRead2(FileObject, FileOffset, Length, Wait, LockKey, Buffer,
+ IoStatus, DeviceObject, &TopLevelContext);
+ if (Ret)
+ {
+ DPRINT("Read OK\n");
+ }
+ else
+ {
+ DPRINT1("Read failed!\n");
+ }
+
+ return Ret;
}
BOOLEAN
return STATUS_SUCCESS;
}
-NTSTATUS
-NTAPI
-RxInitializeRxTimer(
- VOID)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
/*
* @implemented
*/
UNIMPLEMENTED;
}
+/*
+ * @implemented
+ */
+VOID
+RxPurgeNetFcb(
+ PFCB Fcb,
+ PRX_CONTEXT LocalContext)
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ /* First, flush */
+ MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite);
+
+ /* And force close */
+ RxReleaseFcb(NULL, Fcb);
+ MmForceSectionClosed(&Fcb->NonPaged->SectionObjectPointers, TRUE);
+ Status = RxAcquireExclusiveFcb(NULL, Fcb);
+ ASSERT(Status == STATUS_SUCCESS);
+}
+
NTSTATUS
RxQueryAlternateNameInfo(
PRX_CONTEXT RxContext,
return Context;
}
+/*
+ * @implemented
+ */
VOID
RxRemoveShareAccess(
_Inout_ PFILE_OBJECT FileObject,
_In_ PSZ where,
_In_ PSZ wherelogtag)
{
- UNIMPLEMENTED;
+ PAGED_CODE();
+
+ RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
+ IoRemoveShareAccess(FileObject, ShareAccess);
+ RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxRemoveShareAccessPerSrvOpens(
+ IN OUT PSRV_OPEN SrvOpen)
+{
+ ACCESS_MASK DesiredAccess;
+ BOOLEAN ReadAccess;
+ BOOLEAN WriteAccess;
+ BOOLEAN DeleteAccess;
+
+ PAGED_CODE();
+
+ /* Get access that were granted to SRV_OPEN */
+ DesiredAccess = SrvOpen->DesiredAccess;
+ ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
+ WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
+ DeleteAccess = (DesiredAccess & DELETE) != 0;
+
+ /* If any, drop them */
+ if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
+ {
+ BOOLEAN SharedRead;
+ BOOLEAN SharedWrite;
+ BOOLEAN SharedDelete;
+ ULONG DesiredShareAccess;
+ PSHARE_ACCESS ShareAccess;
+
+ ShareAccess = &((PFCB)SrvOpen->pFcb)->ShareAccessPerSrvOpens;
+ DesiredShareAccess = SrvOpen->ShareAccess;
+
+ ShareAccess->Readers -= ReadAccess;
+ ShareAccess->Writers -= WriteAccess;
+ ShareAccess->Deleters -= DeleteAccess;
+
+ ShareAccess->OpenCount--;
+
+ SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
+ SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
+ SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
+ ShareAccess->SharedRead -= SharedRead;
+ ShareAccess->SharedWrite -= SharedWrite;
+ ShareAccess->SharedDelete -= SharedDelete;
+ }
}
NTSTATUS
PSRV_OPEN SrvOpen,
PLIST_ENTRY DiscardedRequests);
+VOID
+NTAPI
+RxScavengerTimerRoutine(
+ PVOID Context);
+
+VOID
+NTAPI
+RxTimerDispatch(
+ _In_ struct _KDPC *Dpc,
+ _In_opt_ PVOID DeferredContext,
+ _In_opt_ PVOID SystemArgument1,
+ _In_opt_ PVOID SystemArgument2);
+
VOID
NTAPI
RxWorkItemDispatcher(
FAST_MUTEX RxLowIoPagingIoSyncMutex;
BOOLEAN RxContinueFromAssert = TRUE;
ULONG RxExplodePoolTags = 1;
+LARGE_INTEGER RxTimerInterval;
+RX_SPIN_LOCK RxTimerLock;
+LIST_ENTRY RxTimerQueueHead;
+LIST_ENTRY RxRecurrentWorkItemsList;
+KDPC RxTimerDpc;
+KTIMER RxTimer;
+ULONG RxTimerTickCount;
#if DBG
BOOLEAN DumpDispatchRoutine = TRUE;
#else
RxpWorkerThreadDispatcher(RxWorkQueue, NULL);
}
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+RxChangeBufferingState(
+ PSRV_OPEN SrvOpen,
+ PVOID Context,
+ BOOLEAN ComputeNewState)
+{
+ PFCB Fcb;
+ NTSTATUS Status, MiniStatus;
+ ULONG NewBufferingState, OldBufferingState;
+
+ PAGED_CODE();
+
+ DPRINT("RxChangeBufferingState(%p, %p, %d)\n", SrvOpen, Context, ComputeNewState);
+
+ Fcb = (PFCB)SrvOpen->pFcb;
+ ASSERT(NodeTypeIsFcb(Fcb));
+ /* First of all, mark that buffering state is changing */
+ SetFlag(Fcb->FcbState, FCB_STATE_BUFFERSTATE_CHANGING);
+
+ /* Assume success */
+ Status = STATUS_SUCCESS;
+ _SEH2_TRY
+ {
+ /* If we're asked to compute a new state, ask the mini-rdr for it */
+ if (ComputeNewState)
+ {
+ MINIRDR_CALL_THROUGH(MiniStatus, Fcb->MRxDispatch, MRxComputeNewBufferingState,
+ ((PMRX_SRV_OPEN)SrvOpen, Context, &NewBufferingState));
+ if (MiniStatus != STATUS_SUCCESS)
+ {
+ NewBufferingState = 0;
+ }
+ }
+ else
+ {
+ /* If not, use SRV_OPEN state */
+ NewBufferingState = SrvOpen->BufferingFlags;
+ }
+
+ /* If no shared access, and if we're not asked to compute a new state, use maximum flags set */
+ if ((Fcb->ShareAccess.SharedRead + Fcb->ShareAccess.SharedWrite + Fcb->ShareAccess.SharedDelete) == 0 && !ComputeNewState)
+ {
+ SetFlag(NewBufferingState, FCB_STATE_BUFFERING_STATE_WITH_NO_SHARES);
+ }
+
+ /* If there's a lock operation to complete, clear that flag */
+ if (Fcb->OutstandingLockOperationsCount != 0)
+ {
+ ClearFlag(NewBufferingState, FCB_STATE_LOCK_BUFFERING_ENABLED);
+ }
+
+ /* Get the old state */
+ OldBufferingState = Fcb->FcbState & FCB_STATE_BUFFERING_STATE_MASK;
+ DPRINT("ChangeBufferingState %x -> %x (%x)\n", OldBufferingState, NewBufferingState, SrvOpen->BufferingFlags);
+
+ /* If we're dropping write cache, then flush the FCB */
+ if (BooleanFlagOn(OldBufferingState, FCB_STATE_WRITECACHING_ENABLED) &&
+ !BooleanFlagOn(NewBufferingState, FCB_STATE_WRITECACHING_ENABLED))
+ {
+ DPRINT("Flushing\n");
+
+ Status = RxFlushFcbInSystemCache(Fcb, TRUE);
+ }
+
+ /* If we're dropping read cache, then purge */
+ if (Fcb->UncleanCount == 0 ||
+ (BooleanFlagOn(OldBufferingState, FCB_STATE_READCACHING_ENABLED) &&
+ !BooleanFlagOn(NewBufferingState, FCB_STATE_READCACHING_ENABLED)) ||
+ BooleanFlagOn(NewBufferingState, FCB_STATE_DELETE_ON_CLOSE))
+ {
+ DPRINT("Purging\n");
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Previous flush failed with status: %lx\n", Status);
+ }
+
+ CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers, NULL, 0, TRUE);
+ }
+
+ /* If there's already a change pending in SRV_OPEN */
+ if (ComputeNewState && BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
+ {
+ /* If there's a FOBX at least */
+ if (!IsListEmpty(&SrvOpen->FobxList))
+ {
+ PRX_CONTEXT RxContext;
+
+ /* Create a fake context to pass to the mini-rdr */
+ RxContext = RxCreateRxContext(NULL, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING | RX_CONTEXT_FLAG_WAIT);
+ if (RxContext != NULL)
+ {
+ PFOBX Fobx;
+
+ RxContext->pFcb = RX_GET_MRX_FCB(Fcb);
+
+ /* Give the first FOBX */
+ Fobx = CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks);
+ RxContext->pFobx = (PMRX_FOBX)Fobx;
+ RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
+
+ /* If there was a delayed close, perform it */
+ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
+ {
+ DPRINT("Oplock break close for %p\n", SrvOpen);
+
+ RxCloseAssociatedSrvOpen(Fobx, RxContext);
+ }
+ /* Otherwise, inform the mini-rdr about completion */
+ else
+ {
+ MINIRDR_CALL_THROUGH(MiniStatus, Fcb->MRxDispatch, MRxCompleteBufferingStateChangeRequest,
+ (RxContext, (PMRX_SRV_OPEN)SrvOpen, Context));
+ (void)MiniStatus;
+ }
+
+ RxDereferenceAndDeleteRxContext(RxContext);
+ }
+ }
+ }
+
+ /* Set the new state */
+ Fcb->FcbState ^= (NewBufferingState ^ Fcb->FcbState) & FCB_STATE_BUFFERING_STATE_MASK;
+ }
+ _SEH2_FINALLY
+ {
+ /* Job done, clear the flag */
+ ClearFlag(Fcb->FcbState, FCB_STATE_BUFFERSTATE_CHANGING);
+
+ if (!BooleanFlagOn(NewBufferingState, FCB_STATE_FILETIMECACHEING_ENABLED))
+ {
+ ClearFlag(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET);
+ }
+ }
+ _SEH2_END;
+
+ return Status;
+}
+
NTSTATUS
RxCheckVNetRootCredentials(
PRX_CONTEXT RxContext,
return VNetRoot;
}
+/*
+ * @implemented
+ */
VOID
RxDereference(
IN OUT PVOID Instance,
/* We have to be locked exclusively */
if (LockHoldingState != LHS_ExclusiveLockHeld)
{
- UNIMPLEMENTED;
+ if ((NodeType == RDBSS_NTC_FOBX && RefCount == 0) ||
+ (NodeType >= RDBSS_NTC_SRVCALL && NodeType <= RDBSS_NTC_V_NETROOT))
+ {
+ RxpMarkInstanceForScavengedFinalization(Instance);
+ }
+
RxReleaseScavengerMutex();
return;
}
+ else
+ {
+ if (BooleanFlagOn(NodeType, RX_SCAVENGER_MASK))
+ {
+ RxpUndoScavengerFinalizationMarking(Instance);
+ }
+ }
RxReleaseScavengerMutex();
}
}
+VOID
+NTAPI
+RxDispatchChangeBufferingStateRequests(
+ PVOID Context)
+{
+ UNIMPLEMENTED;
+}
+
/*
* @implemented
*/
ASSERT(ForceFinalize || ((ThisFcb->OpenCount == 0) && (ThisFcb->UncleanCount == 0)));
- DPRINT("Finalizing FCB open: %d (%d)", ThisFcb->OpenCount, ForceFinalize);
+ DPRINT("Finalizing FCB open: %d (%d)\n", ThisFcb->OpenCount, ForceFinalize);
/* If finalization was not already initiated, go ahead */
if (!ThisFcb->UpperFinalizationDone)
ExDeleteResourceLite(ThisFcb->Header.PagingIoResource);
InterlockedDecrement((volatile long *)&ThisFcb->pNetRoot->NumberOfFcbs);
- RxDereferenceNetRoot(ThisFcb->pNetRoot, LHS_LockNotHeld);
+ RxDereferenceVNetRoot(ThisFcb->VNetRoot, LHS_LockNotHeld);
ASSERT(IsListEmpty(&ThisFcb->FcbTableEntry.HashLinks));
ASSERT(!ThisFcb->fMiniInited);
return TRUE;
}
+/*
+ * @implemented
+ */
BOOLEAN
RxFinalizeSrvOpen(
OUT PSRV_OPEN ThisSrvOpen,
IN BOOLEAN RecursiveFinalize,
IN BOOLEAN ForceFinalize)
{
- UNIMPLEMENTED;
- return FALSE;
+ PFCB Fcb;
+
+ PAGED_CODE();
+
+ /* We have to have a SRV_OPEN */
+ ASSERT(NodeType(ThisSrvOpen) == RDBSS_NTC_SRVOPEN);
+
+ /* If that's a recursive finalization, finalize any related FOBX */
+ if (RecursiveFinalize)
+ {
+ PLIST_ENTRY ListEntry;
+
+ for (ListEntry = ThisSrvOpen->FobxList.Flink;
+ ListEntry != &ThisSrvOpen->FobxList;
+ ListEntry = ListEntry->Flink)
+ {
+ PFOBX Fobx;
+
+ Fobx = CONTAINING_RECORD(ListEntry, FOBX, FobxQLinks);
+ RxFinalizeNetFobx(Fobx, TRUE, ForceFinalize);
+ }
+ }
+
+ /* If we have still references, don't finalize unless forced */
+ if (ThisSrvOpen->NodeReferenceCount != 0 &&
+ !ForceFinalize)
+ {
+ return FALSE;
+ }
+
+ DPRINT("Finalize SRV_OPEN: %p (with %d ref), forced: %d\n", ThisSrvOpen, ThisSrvOpen->NodeReferenceCount, ForceFinalize);
+
+ /* Only finalize if closed, or if it wasn't already done and SRV_OPEN is in a bad shape */
+ Fcb = (PFCB)ThisSrvOpen->pFcb;
+ if ((!ThisSrvOpen->UpperFinalizationDone && ThisSrvOpen->Condition != Condition_Good) ||
+ BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
+ {
+ PV_NET_ROOT VNetRoot;
+
+ /* Associated FCB can't be fake one */
+ ASSERT(NodeType(Fcb) != RDBSS_NTC_OPENTARGETDIR_FCB);
+ ASSERT(RxIsFcbAcquiredExclusive (Fcb));
+
+ /* Purge any pending operation */
+ RxPurgeChangeBufferingStateRequestsForSrvOpen(ThisSrvOpen);
+
+ /* If the FCB wasn't orphaned, inform the mini-rdr about close */
+ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
+ {
+ NTSTATUS Status;
+
+ MINIRDR_CALL_THROUGH(Status, Fcb->MRxDispatch, MRxForceClosed, ((PMRX_SRV_OPEN)ThisSrvOpen));
+ (void)Status;
+ }
+
+ /* Remove ourselves from the FCB */
+ RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
+ InitializeListHead(&ThisSrvOpen->SrvOpenQLinks);
+ ++Fcb->SrvOpenListVersion;
+
+ /* If we have a V_NET_ROOT, dereference it */
+ VNetRoot = (PV_NET_ROOT)ThisSrvOpen->pVNetRoot;
+ if (VNetRoot != NULL)
+ {
+ InterlockedDecrement((volatile long *)&VNetRoot->pNetRoot->NumberOfSrvOpens);
+ RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
+ ThisSrvOpen->pVNetRoot = NULL;
+ }
+
+ /* Finalization done */
+ ThisSrvOpen->UpperFinalizationDone = TRUE;
+ }
+
+ /* Don't free memory if still referenced */
+ if (ThisSrvOpen->NodeReferenceCount != 0)
+ {
+ return FALSE;
+ }
+
+ /* No key association left */
+ ASSERT(IsListEmpty(&ThisSrvOpen->SrvOpenKeyList));
+
+ /* If we're still in some FCB, remove us */
+ if (!IsListEmpty(&ThisSrvOpen->SrvOpenQLinks))
+ {
+ RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
+ }
+
+ /* If enclosed allocation, mark the memory zone free and dereference FCB */
+ if (BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED))
+ {
+ ClearFlag(Fcb->FcbState, FCB_STATE_SRVOPEN_USED);
+ RxDereferenceNetFcb(Fcb);
+ }
+ /* Otherwise, free the memory */
+ else
+ {
+ RxFreeFcbObject(ThisSrvOpen);
+ }
+
+ return TRUE;
}
/*
return IoStatus.Status;
}
+/*
+ * @implemented
+ */
VOID
RxFreeFcbObject(
PVOID Object)
{
- UNIMPLEMENTED;
+ PAGED_CODE();
+
+ /* If that's a FOBX/SRV_OPEN, nothing to do, just free it */
+ if (NodeType(Object) == RDBSS_NTC_FOBX || NodeType(Object) == RDBSS_NTC_SRVOPEN)
+ {
+ RxFreePoolWithTag(Object, RX_FCB_POOLTAG);
+ }
+ /* If that's a FCB... */
+ else if (NodeTypeIsFcb(Object))
+ {
+ PFCB Fcb;
+ PRDBSS_DEVICE_OBJECT DeviceObject;
+
+ Fcb = (PFCB)Object;
+ DeviceObject = Fcb->RxDeviceObject;
+
+ /* Delete per stream contexts */
+ FsRtlTeardownPerStreamContexts(&Fcb->Header);
+
+ SetFlag(Fcb->Header.Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH);
+
+ /* If there was a non-paged FCB allocated, free it */
+ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE))
+ {
+ RxFreePoolWithTag(Fcb->NonPaged, RX_NONPAGEDFCB_POOLTAG);
+ }
+
+ /* Free the FCB */
+ RxFreePool(Fcb);
+
+ /* Update statistics */
+ InterlockedDecrement(&RxNumberOfActiveFcbs);
+ InterlockedDecrement((volatile long *)&DeviceObject->NumberOfActiveFcbs);
+ }
}
/*
* @implemented
*/
VOID
-RxGetFileSizeWithLock(
- IN PFCB Fcb,
- OUT PLONGLONG FileSize)
+RxGatherRequestsForSrvOpen(
+ IN OUT PSRV_CALL SrvCall,
+ IN PSRV_OPEN SrvOpen,
+ IN OUT PLIST_ENTRY RequestsListHead)
{
- PAGED_CODE();
+ KIRQL OldIrql;
+ LIST_ENTRY Discarded, *Entry;
+ PCHANGE_BUFFERING_STATE_REQUEST Request;
- *FileSize = Fcb->Header.FileSize.QuadPart;
-}
+ /* Dispatch any pending operation first */
+ RxpDispatchChangeBufferingStateRequests(SrvCall, SrvOpen, &Discarded);
-/*
- * @implemented
- */
-PEPROCESS
-NTAPI
-RxGetRDBSSProcess(
- VOID)
-{
- return RxData.OurProcess;
-}
+ /* Then, get any entry related to our key and SRV_OPEN */
+ KeAcquireSpinLock(&SrvCall->BufferingManager.SpinLock, &OldIrql);
+ Entry = SrvCall->BufferingManager.HandlerList.Flink;
+ while (Entry != &SrvCall->BufferingManager.HandlerList)
+ {
+ Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
+ Entry = Entry->Flink;
+ if (Request->SrvOpenKey == SrvOpen->Key && Request->SrvOpen == SrvOpen)
+ {
+ RemoveEntryList(&Request->ListEntry);
+ InsertTailList(RequestsListHead, &Request->ListEntry);
+ }
+ }
+ KeReleaseSpinLock(&SrvCall->BufferingManager.SpinLock, OldIrql);
-/*
- * @implemented
- */
-NTSTATUS
-RxInitializeBufferingManager(
- PSRV_CALL SrvCall)
-{
- KeInitializeSpinLock(&SrvCall->BufferingManager.SpinLock);
- InitializeListHead(&SrvCall->BufferingManager.DispatcherList);
- InitializeListHead(&SrvCall->BufferingManager.HandlerList);
- InitializeListHead(&SrvCall->BufferingManager.LastChanceHandlerList);
- SrvCall->BufferingManager.DispatcherActive = FALSE;
- SrvCall->BufferingManager.HandlerInactive = FALSE;
- SrvCall->BufferingManager.LastChanceHandlerActive = FALSE;
- SrvCall->BufferingManager.NumberOfOutstandingOpens = 0;
- InitializeListHead(&SrvCall->BufferingManager.SrvOpenLists[0]);
- ExInitializeFastMutex(&SrvCall->BufferingManager.Mutex);
+ /* Perform the same search in the last change list */
+ Entry = SrvCall->BufferingManager.LastChanceHandlerList.Flink;
+ while (Entry != &SrvCall->BufferingManager.LastChanceHandlerList)
+ {
+ Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
+ Entry = Entry->Flink;
+ if (Request->SrvOpenKey == SrvOpen->Key && Request->SrvOpen == SrvOpen)
+ {
+ RemoveEntryList(&Request->ListEntry);
+ InsertTailList(RequestsListHead, &Request->ListEntry);
+ }
+ }
- return STATUS_SUCCESS;
+ /* Discard the discarded requests */
+ RxpDiscardChangeBufferingStateRequests(&Discarded);
}
/*
* @implemented
*/
-VOID
-NTAPI
-RxInitializeContext(
- IN PIRP Irp,
- IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
- IN ULONG InitialContextFlags,
- IN OUT PRX_CONTEXT RxContext)
+PRDBSS_DEVICE_OBJECT
+RxGetDeviceObjectOfInstance(
+ PVOID Instance)
{
- PIO_STACK_LOCATION Stack;
+ NODE_TYPE_CODE NodeType;
+ PRDBSS_DEVICE_OBJECT DeviceObject;
- /* Initialize our various fields */
- RxContext->NodeTypeCode = RDBSS_NTC_RX_CONTEXT;
- RxContext->NodeByteSize = sizeof(RX_CONTEXT);
- RxContext->ReferenceCount = 1;
- RxContext->SerialNumber = InterlockedExchangeAdd((volatile LONG *)&RxContextSerialNumberCounter, 1);
- RxContext->RxDeviceObject = RxDeviceObject;
- KeInitializeEvent(&RxContext->SyncEvent, SynchronizationEvent, FALSE);
- RxInitializeScavengerEntry(&RxContext->ScavengerEntry);
- InitializeListHead(&RxContext->BlockedOperations);
- RxContext->MRxCancelRoutine = NULL;
- RxContext->ResumeRoutine = NULL;
- RxContext->Flags |= InitialContextFlags;
- RxContext->CurrentIrp = Irp;
- RxContext->LastExecutionThread = PsGetCurrentThread();
- RxContext->OriginalThread = RxContext->LastExecutionThread;
+ PAGED_CODE();
- /* If've got no IRP, mark RX_CONTEXT */
- if (Irp == NULL)
+ /* We only handle a few object types */
+ NodeType = NodeType(Instance);
+ ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
+ (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) || (NodeType == RDBSS_NTC_FOBX));
+
+ /* Get the device object depending on the object */
+ switch (NodeType)
{
- RxContext->CurrentIrpSp = NULL;
- RxContext->MajorFunction = IRP_MJ_MAXIMUM_FUNCTION + 1;
- RxContext->MinorFunction = 0;
+ case RDBSS_NTC_FOBX:
+ {
+ PFOBX Fobx;
+
+ Fobx = (PFOBX)Instance;
+ DeviceObject = Fobx->RxDeviceObject;
+ break;
+ }
+
+ case RDBSS_NTC_SRVCALL:
+ {
+ PSRV_CALL SrvCall;
+
+ SrvCall = (PSRV_CALL)Instance;
+ DeviceObject = SrvCall->RxDeviceObject;
+ break;
+ }
+
+ case RDBSS_NTC_NETROOT:
+ {
+ PNET_ROOT NetRoot;
+
+ NetRoot = (PNET_ROOT)Instance;
+ DeviceObject = NetRoot->pSrvCall->RxDeviceObject;
+ break;
+ }
+
+ case RDBSS_NTC_V_NETROOT:
+ {
+ PV_NET_ROOT VNetRoot;
+
+ VNetRoot = (PV_NET_ROOT)Instance;
+ DeviceObject = VNetRoot->pNetRoot->pSrvCall->RxDeviceObject;
+ break;
+ }
+
+ case RDBSS_NTC_SRVOPEN:
+ {
+ PSRV_OPEN SrvOpen;
+
+ SrvOpen = (PSRV_OPEN)Instance;
+ DeviceObject = ((PFCB)SrvOpen->pFcb)->RxDeviceObject;
+ break;
+ }
+
+ default:
+ DeviceObject = NULL;
+ break;
+ }
+
+ /* Job done */
+ return DeviceObject;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxGetFileSizeWithLock(
+ IN PFCB Fcb,
+ OUT PLONGLONG FileSize)
+{
+ PAGED_CODE();
+
+ *FileSize = Fcb->Header.FileSize.QuadPart;
+}
+
+/*
+ * @implemented
+ */
+PEPROCESS
+NTAPI
+RxGetRDBSSProcess(
+ VOID)
+{
+ return RxData.OurProcess;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxInitializeBufferingManager(
+ PSRV_CALL SrvCall)
+{
+ KeInitializeSpinLock(&SrvCall->BufferingManager.SpinLock);
+ InitializeListHead(&SrvCall->BufferingManager.DispatcherList);
+ InitializeListHead(&SrvCall->BufferingManager.HandlerList);
+ InitializeListHead(&SrvCall->BufferingManager.LastChanceHandlerList);
+ SrvCall->BufferingManager.DispatcherActive = FALSE;
+ SrvCall->BufferingManager.HandlerInactive = FALSE;
+ SrvCall->BufferingManager.LastChanceHandlerActive = FALSE;
+ SrvCall->BufferingManager.NumberOfOutstandingOpens = 0;
+ InitializeListHead(&SrvCall->BufferingManager.SrvOpenLists[0]);
+ ExInitializeFastMutex(&SrvCall->BufferingManager.Mutex);
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxInitializeContext(
+ IN PIRP Irp,
+ IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
+ IN ULONG InitialContextFlags,
+ IN OUT PRX_CONTEXT RxContext)
+{
+ PIO_STACK_LOCATION Stack;
+
+ /* Initialize our various fields */
+ RxContext->NodeTypeCode = RDBSS_NTC_RX_CONTEXT;
+ RxContext->NodeByteSize = sizeof(RX_CONTEXT);
+ RxContext->ReferenceCount = 1;
+ RxContext->SerialNumber = InterlockedExchangeAdd((volatile LONG *)&RxContextSerialNumberCounter, 1);
+ RxContext->RxDeviceObject = RxDeviceObject;
+ KeInitializeEvent(&RxContext->SyncEvent, SynchronizationEvent, FALSE);
+ RxInitializeScavengerEntry(&RxContext->ScavengerEntry);
+ InitializeListHead(&RxContext->BlockedOperations);
+ RxContext->MRxCancelRoutine = NULL;
+ RxContext->ResumeRoutine = NULL;
+ RxContext->Flags |= InitialContextFlags;
+ RxContext->CurrentIrp = Irp;
+ RxContext->LastExecutionThread = PsGetCurrentThread();
+ RxContext->OriginalThread = RxContext->LastExecutionThread;
+
+ /* If've got no IRP, mark RX_CONTEXT */
+ if (Irp == NULL)
+ {
+ RxContext->CurrentIrpSp = NULL;
+ RxContext->MajorFunction = IRP_MJ_MAXIMUM_FUNCTION + 1;
+ RxContext->MinorFunction = 0;
}
else
{
return STATUS_NOT_IMPLEMENTED;
}
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+RxInitializeRxTimer(
+ VOID)
+{
+ PAGED_CODE();
+
+ RxTimerInterval.HighPart = -1;
+ RxTimerInterval.LowPart = -550000;
+ KeInitializeSpinLock(&RxTimerLock);
+ InitializeListHead(&RxTimerQueueHead);
+ InitializeListHead(&RxRecurrentWorkItemsList);
+ KeInitializeDpc(&RxTimerDpc, RxTimerDispatch, NULL);
+ KeInitializeTimer(&RxTimer);
+ RxTimerTickCount = 0;
+
+ return STATUS_SUCCESS;
+}
+
NTSTATUS
RxInitializeVNetRootParameters(
PRX_CONTEXT RxContext,
_SEH2_END;
}
+/*
+ * @implemented
+ */
NTSTATUS
RxLowIoCompletionTail(
IN PRX_CONTEXT RxContext)
Operation = RxContext->LowIoContext.Operation;
if (Operation == LOWIO_OP_READ || Operation == LOWIO_OP_WRITE)
{
+ /* Remove ourselves from the list and resume operations */
if (BooleanFlagOn(RxContext->LowIoContext.ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
{
- UNIMPLEMENTED;
- Status = STATUS_NOT_IMPLEMENTED;
+ ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
+ RemoveEntryList(&RxContext->RxContextSerializationQLinks);
+ RxContext->RxContextSerializationQLinks.Flink = NULL;
+ RxContext->RxContextSerializationQLinks.Blink = NULL;
+ ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
+ RxResumeBlockedOperations_ALL(RxContext);
}
}
else
return Irp->AssociatedIrp.SystemBuffer;
}
+/*
+ * @implemented
+ */
VOID
RxMarkFobxOnCleanup(
PFOBX pFobx,
PBOOLEAN NeedPurge)
{
- UNIMPLEMENTED;
+ PFCB Fcb;
+ PFOBX ScavengerFobx;
+ LARGE_INTEGER TickCount;
+ PRDBSS_SCAVENGER Scavenger;
+
+ PAGED_CODE();
+
+ /* No FOBX, nothing to mark */
+ if (pFobx == NULL)
+ {
+ return;
+ }
+
+ /* Query time for close */
+ KeQueryTickCount(&TickCount);
+
+ Fcb = (PFCB)pFobx->pSrvOpen->pFcb;
+ ASSERT(NodeTypeIsFcb(Fcb));
+
+ Scavenger = Fcb->RxDeviceObject->pRdbssScavenger;
+ RxAcquireScavengerMutex();
+
+ ScavengerFobx = NULL;
+ /* If that's not a file, or even not a disk resource, just mark as dormant */
+ if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE || Fcb->VNetRoot->pNetRoot->DeviceType != FILE_DEVICE_DISK)
+ {
+ SetFlag(pFobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
+ InitializeListHead(&pFobx->ClosePendingList);
+ ++Scavenger->NumberOfDormantFiles;
+ }
+ else
+ {
+ ASSERT(Scavenger->NumberOfDormantFiles >= 0);
+ /* If we're about to reach the maximum dormant of FOBX */
+ if (Scavenger->NumberOfDormantFiles >= Scavenger->MaximumNumberOfDormantFiles)
+ {
+ /* This should never be wrong... */
+ if (!IsListEmpty(&Scavenger->ClosePendingFobxsList))
+ {
+ /* Then, take the first from the list (oldest) and save it for later purge */
+ ScavengerFobx = CONTAINING_RECORD(Scavenger->ClosePendingFobxsList.Flink, FOBX, ClosePendingList);
+ if (ScavengerFobx->pSrvOpen != NULL && ScavengerFobx->pSrvOpen->pFcb == RX_GET_MRX_FCB(Fcb))
+ {
+ *NeedPurge = TRUE;
+ ScavengerFobx = NULL;
+ }
+ else
+ {
+ RxReferenceNetFobx(ScavengerFobx);
+ }
+ }
+ }
+
+ /* Mark ourselves as dormant */
+ SetFlag(pFobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
+ pFobx->CloseTime.QuadPart = TickCount.QuadPart;
+
+ /* And insert us in the list of dormant files */
+ InsertTailList(&Scavenger->ClosePendingFobxsList, &pFobx->ClosePendingList);
+ /* If scavenger was inactive, start it */
+ if (Scavenger->NumberOfDormantFiles++ == 0 && Scavenger->State == RDBSS_SCAVENGER_INACTIVE)
+ {
+ Scavenger->State = RDBSS_SCAVENGER_DORMANT;
+ RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem, RxScavengerTimerRoutine,
+ Fcb->RxDeviceObject, Scavenger->TimeLimit);
+ }
+ }
+
+ RxReleaseScavengerMutex();
+
+ /* If we had reached max */
+ if (ScavengerFobx != NULL)
+ {
+ NTSTATUS Status;
+
+ /* Purge the oldest FOBX */
+ Status = RxPurgeFobxFromCache(ScavengerFobx);
+ if (Status != STATUS_SUCCESS)
+ {
+ *NeedPurge = TRUE;
+ }
+ }
}
+/*
+ * @implemented
+ */
VOID
RxMarkFobxOnClose(
PFOBX Fobx)
{
- UNIMPLEMENTED;
+ PFCB Fcb;
+ PRDBSS_SCAVENGER Scavenger;
+
+ PAGED_CODE();
+
+ /* No FOBX, nothing to mark */
+ if (Fobx == NULL)
+ {
+ return;
+ }
+
+ Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
+ ASSERT(NodeTypeIsFcb(Fcb));
+
+ Scavenger = Fcb->RxDeviceObject->pRdbssScavenger;
+
+ RxAcquireScavengerMutex();
+ /* Only mark it if it was already marked as dormant */
+ if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT))
+ {
+ /* If FCB wasn't already decrement, do it now */
+ if (!Fobx->fOpenCountDecremented)
+ {
+ Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
+ ASSERT(NodeTypeIsFcb(Fcb));
+ InterlockedDecrement((volatile long *)&Fcb->OpenCount);
+
+ Fobx->fOpenCountDecremented = TRUE;
+ }
+
+ /* We're no longer dormant */
+ InterlockedDecrement(&Scavenger->NumberOfDormantFiles);
+ ClearFlag(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
+ }
+
+ /* If we were inserted in the scavenger, drop ourselves out */
+ if (!IsListEmpty(&Fobx->ClosePendingList))
+ {
+ RemoveEntryList(&Fobx->ClosePendingList);
+ InitializeListHead(&Fobx->ClosePendingList);
+ }
+
+ RxReleaseScavengerMutex();
}
/*
}
/* If locking was OK (or not needed!), attempt finalization */
- if (NT_SUCCESS(Status))
+ if (Status == STATUS_SUCCESS)
{
Freed = RxFinalizeNetFcb(ThisFcb, RecursiveFinalize, ForceFinalize, References);
}
RxReleasePrefixTableLock(PrefixTable);
}
-VOID
-RxpDiscardChangeBufferingStateRequests(
- _Inout_ PLIST_ENTRY DiscardedRequests)
+/*
+ * @implemented
+ */
+VOID
+RxpDiscardChangeBufferingStateRequests(
+ _Inout_ PLIST_ENTRY DiscardedRequests)
+{
+ PLIST_ENTRY Entry;
+
+ PAGED_CODE();
+
+ /* No requests to discard */
+ if (IsListEmpty(DiscardedRequests))
+ {
+ return;
+ }
+
+ /* Free all the discarded requests */
+ Entry = DiscardedRequests->Flink;
+ while (Entry != DiscardedRequests)
+ {
+ PCHANGE_BUFFERING_STATE_REQUEST Request;
+
+ Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
+ Entry = Entry->Flink;
+
+ DPRINT("Req %p for %p (%p) discarded\n", Request, Request->SrvOpenKey, Request->SrvOpen);
+
+ RxPrepareRequestForReuse(Request);
+ RxFreePool(Request);
+ }
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxpDispatchChangeBufferingStateRequests(
+ PSRV_CALL SrvCall,
+ PSRV_OPEN SrvOpen,
+ PLIST_ENTRY DiscardedRequests)
+{
+ KIRQL OldIrql;
+ NTSTATUS Status;
+ BOOLEAN StartDispatcher;
+ LIST_ENTRY AcceptedReqs;
+ LIST_ENTRY DispatcherList;
+ PRX_BUFFERING_MANAGER BufferingManager;
+
+ /* Initialize our lists */
+ InitializeListHead(&AcceptedReqs);
+ InitializeListHead(DiscardedRequests);
+
+ /* Transfer the requests to dispatch locally */
+ BufferingManager = &SrvCall->BufferingManager;
+ KeAcquireSpinLock(&BufferingManager->SpinLock, &OldIrql);
+ RxTransferList(&DispatcherList, &BufferingManager->DispatcherList);
+ KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql);
+
+ /* If there were requests */
+ if (!IsListEmpty(&DispatcherList))
+ {
+ PLIST_ENTRY Entry;
+
+ /* For each of the entries... */
+ Entry = DispatcherList.Flink;
+ while (Entry != &DispatcherList)
+ {
+ PCHANGE_BUFFERING_STATE_REQUEST Request;
+
+ Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
+ Entry = Entry->Flink;
+
+ /* If we have been provided a SRV_OPEN, see whether it matches */
+ if (SrvOpen != NULL)
+ {
+ /* Match, the request is accepted */
+ if (Request->SrvOpenKey == SrvOpen->Key)
+ {
+ Request->SrvOpen = SrvOpen;
+ RxReferenceSrvOpen(SrvOpen);
+
+ RemoveEntryList(&Request->ListEntry);
+ InsertTailList(&AcceptedReqs, &Request->ListEntry);
+
+ /* Move to the next entry */
+ continue;
+ }
+ else
+ {
+ Status = STATUS_PENDING;
+ }
+ }
+ else
+ {
+ /* No SRV_OPEN provided, try to find one */
+ Status = RxpLookupSrvOpenForRequestLite(SrvCall, Request);
+ }
+
+ /* We found a matching SRV_OPEN, accept the request */
+ if (Status == STATUS_SUCCESS)
+ {
+ RemoveEntryList(&Request->ListEntry);
+ InsertTailList(&AcceptedReqs, &Request->ListEntry);
+ }
+ /* Another run might help handling it, don't discard it */
+ else if (Status == STATUS_PENDING)
+ {
+ continue;
+ }
+ /* Otherwise, discard the request */
+ else
+ {
+ ASSERT(Status == STATUS_NOT_FOUND);
+
+ RemoveEntryList(&Request->ListEntry);
+ InsertTailList(DiscardedRequests, &Request->ListEntry);
+ }
+ }
+ }
+
+ KeAcquireSpinLock(&BufferingManager->SpinLock, &OldIrql);
+ /* Nothing to dispatch, no need to start dispatcher */
+ if (IsListEmpty(&DispatcherList))
+ {
+ StartDispatcher = FALSE;
+ }
+ else
+ {
+ /* Transfer back the list of the not treated entries to the buffering manager */
+ RxTransferList(&BufferingManager->DispatcherList, &DispatcherList);
+ StartDispatcher = (BufferingManager->DispatcherActive == FALSE);
+ /* If the dispatcher isn't active, start it */
+ if (StartDispatcher)
+ {
+ BufferingManager->DispatcherActive = TRUE;
+ }
+ }
+
+ /* If there were accepted requests, move them to the buffering manager */
+ if (!IsListEmpty(&AcceptedReqs))
+ {
+ RxTransferList(&BufferingManager->HandlerList, &AcceptedReqs);
+ }
+ KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql);
+
+ /* If we're to start the dispatcher, do it */
+ if (StartDispatcher)
+ {
+ RxReferenceSrvCall(SrvCall);
+ DPRINT("Starting dispatcher\n");
+ RxPostToWorkerThread(RxFileSystemDeviceObject, HyperCriticalWorkQueue,
+ &BufferingManager->DispatcherWorkItem,
+ RxDispatchChangeBufferingStateRequests, SrvCall);
+ }
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxpLookupSrvOpenForRequestLite(
+ IN PSRV_CALL SrvCall,
+ IN OUT PCHANGE_BUFFERING_STATE_REQUEST Request)
+{
+ NTSTATUS Status;
+ PLIST_ENTRY Entry;
+ PSRV_OPEN SrvOpen;
+
+ PAGED_CODE();
+
+ Status = STATUS_SUCCESS;
+ /* Browse all our associated SRV_OPENs to find the one! */
+ for (Entry = SrvCall->BufferingManager.SrvOpenLists[0].Flink;
+ Entry != &SrvCall->BufferingManager.SrvOpenLists[0];
+ Entry = Entry->Flink)
+ {
+ /* Same key, not orphaned, this is ours */
+ SrvOpen = CONTAINING_RECORD(Entry, SRV_OPEN, SrvOpenKeyList);
+ if (SrvOpen->Key == Request->SrvOpenKey)
+ {
+ if (!BooleanFlagOn(SrvOpen->pFcb->FcbState, FCB_STATE_ORPHANED))
+ {
+ RxReferenceSrvOpen(SrvOpen);
+ break;
+ }
+ }
+ }
+
+ /* We didn't manage to find a SRV_OPEN */
+ if (Entry == &SrvCall->BufferingManager.SrvOpenLists[0])
+ {
+ SrvOpen = NULL;
+
+ /* The coming open might help, mark as pending for later retry */
+ if (SrvCall->BufferingManager.NumberOfOutstandingOpens != 0)
+ {
+ Status = STATUS_PENDING;
+ }
+ /* Else, it's a complete failure */
+ else
+ {
+ Status = STATUS_NOT_FOUND;
+ }
+ }
+
+ /* Return the (not) found SRV_OPEN */
+ Request->SrvOpen = SrvOpen;
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxpMarkInstanceForScavengedFinalization(
+ PVOID Instance)
+{
+ NODE_TYPE_CODE NodeType;
+ PNODE_TYPE_AND_SIZE Node;
+ PRDBSS_SCAVENGER Scavenger;
+ PRDBSS_DEVICE_OBJECT DeviceObject;
+ PLIST_ENTRY ScavengerHead, InstEntry;
+
+ PAGED_CODE();
+
+ /* If still referenced, don't mark it (broken caller) */
+ Node = (PNODE_TYPE_AND_SIZE)Instance;
+ if (Node->NodeReferenceCount > 1)
+ {
+ return;
+ }
+
+ DeviceObject = RxGetDeviceObjectOfInstance(Instance);
+ Scavenger = DeviceObject->pRdbssScavenger;
+
+ /* Mark the node */
+ NodeType = NodeType(Instance);
+ SetFlag(NodeType(Node), RX_SCAVENGER_MASK);
+ DPRINT("Node %p has now the scavenger mark!\n", Instance);
+
+ /* Increase the count in the scavenger, and queue it */
+ ScavengerHead = NULL;
+ switch (NodeType)
+ {
+ case RDBSS_NTC_FOBX:
+ ++Scavenger->FobxsToBeFinalized;
+ ScavengerHead = &Scavenger->FobxFinalizationList;
+ InstEntry = &((PFOBX)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_SRVCALL:
+ ++Scavenger->SrvCallsToBeFinalized;
+ ScavengerHead = &Scavenger->SrvCallFinalizationList;
+ InstEntry = &((PSRV_CALL)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_NETROOT:
+ ++Scavenger->NetRootsToBeFinalized;
+ ScavengerHead = &Scavenger->NetRootFinalizationList;
+ InstEntry = &((PNET_ROOT)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_V_NETROOT:
+ ++Scavenger->VNetRootsToBeFinalized;
+ ScavengerHead = &Scavenger->VNetRootFinalizationList;
+ InstEntry = &((PV_NET_ROOT)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_SRVOPEN:
+ ++Scavenger->SrvOpensToBeFinalized;
+ ScavengerHead = &Scavenger->SrvOpenFinalizationList;
+ InstEntry = &((PSRV_OPEN)Instance)->ScavengerFinalizationList;
+ break;
+ }
+
+ /* Extra ref for scavenger */
+ InterlockedIncrement((volatile long *)&Node->NodeReferenceCount);
+
+ /* If matching type */
+ if (ScavengerHead != NULL)
+ {
+ /* Insert in the scavenger list */
+ InsertTailList(ScavengerHead, InstEntry);
+
+ /* And if it wasn't started, start it */
+ if (Scavenger->State == RDBSS_SCAVENGER_INACTIVE)
+ {
+ Scavenger->State = RDBSS_SCAVENGER_DORMANT;
+ RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem,
+ RxScavengerTimerRoutine, DeviceObject, Scavenger->TimeLimit);
+ }
+ }
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+RxPostOneShotTimerRequest(
+ IN PRDBSS_DEVICE_OBJECT pDeviceObject,
+ IN PRX_WORK_ITEM pWorkItem,
+ IN PRX_WORKERTHREAD_ROUTINE Routine,
+ IN PVOID pContext,
+ IN LARGE_INTEGER TimeInterval)
{
- UNIMPLEMENTED;
-}
+ KIRQL OldIrql;
-VOID
-RxpDispatchChangeBufferingStateRequests(
- PSRV_CALL SrvCall,
- PSRV_OPEN SrvOpen,
- PLIST_ENTRY DiscardedRequests)
-{
- UNIMPLEMENTED;
+ ASSERT(pWorkItem != NULL);
+
+ /* Prepare the work item */
+ ExInitializeWorkItem(&pWorkItem->WorkQueueItem, Routine, pContext);
+ pWorkItem->WorkQueueItem.pDeviceObject = pDeviceObject;
+
+ /* Last tick can be computed with the number of times it was caller (timertickcount)
+ * and the interval between calls
+ */
+ KeAcquireSpinLock(&RxTimerLock, &OldIrql);
+ pWorkItem->LastTick = (TimeInterval.QuadPart / 550000) + RxTimerTickCount + 1;
+ /* Insert in work queue */
+ InsertTailList(&RxTimerQueueHead, &pWorkItem->WorkQueueItem.List);
+ KeReleaseSpinLock(&RxTimerLock, OldIrql);
+
+ /* If there are queued events, queue an execution */
+ if (IsListEmpty(&RxTimerQueueHead))
+ {
+ KeSetTimer(&RxTimer, RxTimerInterval, &RxTimerDpc);
+ }
+
+ return STATUS_SUCCESS;
}
/*
RxContext->ReferenceCount = 0;
}
+/*
+ * @implemented
+ */
+VOID
+RxPrepareRequestForReuse(
+ PCHANGE_BUFFERING_STATE_REQUEST Request)
+{
+ PSRV_OPEN SrvOpen;
+
+ PAGED_CODE();
+
+ SrvOpen = Request->SrvOpen;
+
+ /* If the request was already prepared for service */
+ if (BooleanFlagOn(Request->Flags, RX_REQUEST_PREPARED_FOR_HANDLING))
+ {
+ /* We have to dereference the associated SRV_OPEN depending on the lock */
+ if (RxIsFcbAcquiredExclusive(SrvOpen->pFcb))
+ {
+ RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
+ }
+ else
+ {
+ RxDereferenceSrvOpen(SrvOpen, LHS_LockNotHeld);
+ }
+ }
+ /* Otherwise, just dereference */
+ else if (SrvOpen != NULL)
+ {
+ RxDereferenceSrvOpen(SrvOpen, LHS_LockNotHeld);
+ }
+
+ Request->SrvOpen = NULL;
+}
+
/*
* @implemented
*/
RxpProcessChangeBufferingStateRequests(SrvCall, TRUE);
}
+/*
+ * @implemented
+ */
+VOID
+RxProcessChangeBufferingStateRequestsForSrvOpen(
+ PSRV_OPEN SrvOpen)
+{
+ LONG NumberOfBufferingChangeRequests, OldBufferingToken;
+
+ /* Get the current number of change requests */
+ NumberOfBufferingChangeRequests = ((PSRV_CALL)SrvOpen->pVNetRoot->pNetRoot->pSrvCall)->BufferingManager.CumulativeNumberOfBufferingChangeRequests;
+ /* Get our old token */
+ OldBufferingToken = InterlockedCompareExchange(&SrvOpen->BufferingToken,
+ NumberOfBufferingChangeRequests, NumberOfBufferingChangeRequests);
+ /* Do we have stuff to process? */
+ if (OldBufferingToken != SrvOpen->BufferingToken)
+ {
+ PFCB Fcb;
+ NTSTATUS Status;
+
+ /* Acquire the FCB and start processing */
+ Fcb = (PFCB)SrvOpen->pFcb;
+ Status = RxAcquireExclusiveFcb(NULL, Fcb);
+ if (Status == STATUS_SUCCESS)
+ {
+ RxProcessFcbChangeBufferingStateRequest(Fcb);
+ RxReleaseFcb(NULL, Fcb);
+ }
+ }
+}
+
VOID
RxProcessFcbChangeBufferingStateRequest(
PFCB Fcb)
UNIMPLEMENTED;
}
+/*
+ * @implemented
+ */
VOID
RxpUndoScavengerFinalizationMarking(
PVOID Instance)
{
+ PLIST_ENTRY ListEntry;
PNODE_TYPE_AND_SIZE Node;
+ PRDBSS_SCAVENGER Scavenger;
PAGED_CODE();
Node = (PNODE_TYPE_AND_SIZE)Instance;
/* There's no marking - nothing to do */
- if (!BooleanFlagOn(Node->NodeTypeCode, RX_SCAVENGER_MASK))
+ if (!BooleanFlagOn(NodeType(Node), RX_SCAVENGER_MASK))
{
return;
}
- UNIMPLEMENTED;
+ /* First of all, remove the mark */
+ ClearFlag(NodeType(Node), RX_SCAVENGER_MASK);
+ DPRINT("Node %p no longer has the scavenger mark\n");
+
+ /* And now, remove from the scavenger */
+ Scavenger = RxGetDeviceObjectOfInstance(Instance)->pRdbssScavenger;
+ switch (NodeType(Node))
+ {
+ case RDBSS_NTC_FOBX:
+ --Scavenger->FobxsToBeFinalized;
+ ListEntry = &((PFOBX)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_SRVCALL:
+ --Scavenger->SrvCallsToBeFinalized;
+ ListEntry = &((PSRV_CALL)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_NETROOT:
+ --Scavenger->NetRootsToBeFinalized;
+ ListEntry = &((PNET_ROOT)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_V_NETROOT:
+ --Scavenger->VNetRootsToBeFinalized;
+ ListEntry = &((PV_NET_ROOT)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_SRVOPEN:
+ --Scavenger->SrvOpensToBeFinalized;
+ ListEntry = &((PSRV_OPEN)Instance)->ScavengerFinalizationList;
+ break;
+ }
+
+ /* Also, remove the extra ref from the scavenger */
+ RemoveEntryList(ListEntry);
+ InterlockedDecrement((volatile long *)&Node->NodeReferenceCount);
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxPurgeChangeBufferingStateRequestsForSrvOpen(
+ PSRV_OPEN SrvOpen)
+{
+ PSRV_CALL SrvCall;
+ LIST_ENTRY Discarded;
+
+ PAGED_CODE();
+
+ ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
+
+ /* Initialize our discarded list */
+ InitializeListHead(&Discarded);
+
+ SrvCall = (PSRV_CALL)SrvOpen->Fcb->VNetRoot->pNetRoot->pSrvCall;
+ RxAcquireBufferingManagerMutex(&SrvCall->BufferingManager);
+
+ /* Set the flag, and get the requests */
+ InitializeListHead(&SrvOpen->SrvOpenKeyList);
+ SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_REQUESTS_PURGED);
+ RxGatherRequestsForSrvOpen(SrvCall, SrvOpen, &Discarded);
+
+ RxReleaseBufferingManagerMutex(&SrvCall->BufferingManager);
+
+ /* If there were discarded requests */
+ if (!IsListEmpty(&Discarded))
+ {
+ /* And a pending buffering state change */
+ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
+ {
+ /* Clear the flag, and set the associated event - job done */
+ RxAcquireSerializationMutex();
+ ClearFlag(SrvOpen->Fcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
+ if (SrvOpen->Fcb->pBufferingStateChangeCompletedEvent != NULL)
+ {
+ KeSetEvent(SrvOpen->Fcb->pBufferingStateChangeCompletedEvent, IO_NETWORK_INCREMENT, FALSE);
+ }
+ RxReleaseSerializationMutex();
+ }
+
+ /* Drop the discarded requests */
+ RxpDiscardChangeBufferingStateRequests(&Discarded);
+ }
}
/*
return Status;
}
+/*
+ * @implemented
+ */
+NTSTATUS
+RxPurgeFobxFromCache(
+ PFOBX FobxToBePurged)
+{
+ NTSTATUS Status;
+ PFCB FcbToBePurged;
+
+ PAGED_CODE();
+
+ FcbToBePurged = (PFCB)FobxToBePurged->pSrvOpen->pFcb;
+ ASSERT(FcbToBePurged != NULL);
+
+ /* If we cannot have our FCB exclusively, give up */
+ Status = RxAcquireExclusiveFcb(NULL, FcbToBePurged);
+ if (Status != STATUS_SUCCESS)
+ {
+ RxDereferenceNetFobx(FobxToBePurged, LHS_LockNotHeld);
+ return Status;
+ }
+
+ /* Don't let the FCB disappear */
+ RxReferenceNetFcb(FcbToBePurged);
+
+ /* If the SRV_OPEN was already closed, or if there are unclean FOBX, give up */
+ if (BooleanFlagOn(FobxToBePurged->Flags, FOBX_FLAG_SRVOPEN_CLOSED) || FobxToBePurged->pSrvOpen->UncleanFobxCount != 0)
+ {
+ DPRINT("FCB purge skipped\n");
+ }
+ else
+ {
+ Status = RxPurgeFcbInSystemCache(FcbToBePurged, NULL, 0, FALSE, TRUE);
+ }
+
+ RxDereferenceNetFobx(FobxToBePurged, LHS_ExclusiveLockHeld);
+ /* Drop our extra reference */
+ if (!RxDereferenceAndFinalizeNetFcb(FcbToBePurged, NULL, FALSE, FALSE))
+ {
+ RxReleaseFcb(NULL, FcbToBePurged);
+ }
+
+ return Status;
+}
+
/*
* @implemented
*/
RxReleaseScavengerMutex();
}
+/*
+ * @implemented
+ */
+VOID
+RxRemoveNameNetFcb(
+ OUT PFCB ThisFcb)
+{
+ PNET_ROOT NetRoot;
+
+ PAGED_CODE();
+
+ ASSERT(NodeTypeIsFcb(ThisFcb));
+
+ /* Just remove the entry from the FCB_TABLE */
+ NetRoot = (PNET_ROOT)ThisFcb->VNetRoot->pNetRoot;
+ ASSERT(RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
+ ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
+
+ RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb);
+ DPRINT("FCB (%p) %wZ removed\n", ThisFcb, &ThisFcb->FcbTableEntry.Path);
+ /* Mark, so that we don't try to do it twice */
+ SetFlag(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED);
+}
+
/*
* @implemented
*/
}
}
+VOID
+RxResumeBlockedOperations_ALL(
+ IN OUT PRX_CONTEXT RxContext)
+{
+ LIST_ENTRY BlockedOps;
+
+ PAGED_CODE();
+
+ /* Get the blocked operations */
+ RxTransferListWithMutex(&BlockedOps, &RxContext->BlockedOperations, RxContext->BlockedOpsMutex);
+
+ if (!IsListEmpty(&BlockedOps))
+ {
+ UNIMPLEMENTED;
+ }
+}
+
VOID
NTAPI
RxResumeBlockedOperations_Serially(
return TRUE;
}
+VOID
+RxScavengerFinalizeEntries(
+ PRDBSS_DEVICE_OBJECT DeviceObject)
+{
+ UNIMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxScavengerTimerRoutine(
+ PVOID Context)
+{
+ BOOLEAN Requeue;
+ PRDBSS_DEVICE_OBJECT DeviceObject;
+ PRDBSS_SCAVENGER Scavenger;
+
+ PAGED_CODE();
+
+ DeviceObject = Context;
+ Scavenger = DeviceObject->pRdbssScavenger;
+
+ Requeue = FALSE;
+ RxAcquireScavengerMutex();
+ /* If the scavenger was dormant, wake it up! */
+ if (Scavenger->State == RDBSS_SCAVENGER_DORMANT)
+ {
+ /* Done */
+ Scavenger->State = RDBSS_SCAVENGER_ACTIVE;
+ KeResetEvent(&Scavenger->ScavengeEvent);
+
+ /* Scavenger the entries */
+ RxReleaseScavengerMutex();
+ RxScavengerFinalizeEntries(DeviceObject);
+ RxAcquireScavengerMutex();
+
+ /* If we're still active (race) */
+ if (Scavenger->State == RDBSS_SCAVENGER_ACTIVE)
+ {
+ /* If there are new entries to scavenge, stay dormant and requeue a run */
+ if (Scavenger->NumberOfDormantFiles + Scavenger->SrvCallsToBeFinalized +
+ Scavenger->NetRootsToBeFinalized + Scavenger->VNetRootsToBeFinalized +
+ Scavenger->FcbsToBeFinalized + Scavenger->SrvOpensToBeFinalized +
+ Scavenger->FobxsToBeFinalized != 0)
+ {
+ Requeue = TRUE;
+ Scavenger->State = RDBSS_SCAVENGER_DORMANT;
+ }
+ /* Otherwise, we're inactive again */
+ else
+ {
+ Scavenger->State == RDBSS_SCAVENGER_INACTIVE;
+ }
+ }
+
+ RxReleaseScavengerMutex();
+
+ /* Requeue an execution */
+ if (Requeue)
+ {
+ RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem,
+ RxScavengerTimerRoutine, DeviceObject, Scavenger->TimeLimit);
+ }
+ }
+ else
+ {
+ RxReleaseScavengerMutex();
+ }
+
+ KeSetEvent(&Scavenger->ScavengeEvent, IO_NO_INCREMENT, FALSE);
+}
+
BOOLEAN
RxScavengeVNetRoots(
PRDBSS_DEVICE_OBJECT RxDeviceObject)
return STATUS_SUCCESS;
}
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxTimerDispatch(
+ _In_ struct _KDPC *Dpc,
+ _In_opt_ PVOID DeferredContext,
+ _In_opt_ PVOID SystemArgument1,
+ _In_opt_ PVOID SystemArgument2)
+{
+ BOOLEAN Set;
+ LIST_ENTRY LocalList;
+ PLIST_ENTRY ListEntry;
+ PRX_WORK_ITEM WorkItem;
+
+ InitializeListHead(&LocalList);
+
+ KeAcquireSpinLockAtDpcLevel(&RxTimerLock);
+ ++RxTimerTickCount;
+
+ /* Find any entry matching */
+ if (!IsListEmpty(&RxTimerQueueHead))
+ {
+ ListEntry = RxTimerQueueHead.Flink;
+ do
+ {
+ WorkItem = CONTAINING_RECORD(ListEntry, RX_WORK_ITEM, WorkQueueItem.List);
+ if (WorkItem->LastTick == RxTimerTickCount)
+ {
+ ListEntry = ListEntry->Flink;
+
+ RemoveEntryList(&WorkItem->WorkQueueItem.List);
+ InsertTailList(&LocalList, &WorkItem->WorkQueueItem.List);
+ }
+ else
+ {
+ ListEntry = ListEntry->Flink;
+ }
+ } while (ListEntry != &RxTimerQueueHead);
+ }
+ /* Do we have to requeue a later execution? */
+ Set = !IsListEmpty(&RxTimerQueueHead);
+
+ KeReleaseSpinLockFromDpcLevel(&RxTimerLock);
+
+ /* Requeue if list wasn't empty */
+ if (Set)
+ {
+ KeSetTimer(&RxTimer, RxTimerInterval, &RxTimerDpc);
+ }
+
+ /* If we had matching entries */
+ if (!IsListEmpty(&LocalList))
+ {
+ /* Post them, one after another */
+ ListEntry = LocalList.Flink;
+ do
+ {
+ WorkItem = CONTAINING_RECORD(ListEntry, RX_WORK_ITEM, WorkQueueItem.List);
+ ListEntry = ListEntry->Flink;
+
+ WorkItem->WorkQueueItem.List.Flink = NULL;
+ WorkItem->WorkQueueItem.List.Blink = NULL;
+ RxPostToWorkerThread(WorkItem->WorkQueueItem.pDeviceObject, CriticalWorkQueue,
+ &WorkItem->WorkQueueItem, WorkItem->WorkQueueItem.WorkerRoutine,
+ WorkItem->WorkQueueItem.Parameter);
+ }
+ while (ListEntry != &LocalList);
+ }
+}
+
/*
* @implemented
*/
UNIMPLEMENTED;
}
- /* Nor missing contexts... */
+ /* If we don't have a context, assume we can wait! */
if (RxContext == NULL)
{
- UNIMPLEMENTED;
+ CanWait = TRUE;
}
+ else
+ {
+ /* That said: we have a real context! */
+ ContextIsPresent = TRUE;
- /* That said: we have a real context! */
- ContextIsPresent = TRUE;
+ /* If we've been cancelled in between, give up */
+ Status = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED) ? STATUS_CANCELLED : STATUS_SUCCESS;
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
- /* If we've been cancelled in between, give up */
- Status = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED) ? STATUS_CANCELLED : STATUS_SUCCESS;
- if (!NT_SUCCESS(Status))
- {
- return Status;
+ /* Can we wait? */
+ CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
}
- /* Can we wait? */
- CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
-
while (TRUE)
{
/* Assume we cannot lock */