From cb6b10385bc7774e6bd126f1ee1bc18a3e836747 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Sun, 13 Nov 2016 22:06:53 -0800 Subject: [PATCH] sys: rename: oplocks --- src/sys/driver.h | 4 +- src/sys/file.c | 160 +++++++++++++++++++++++++++++++++++++-------- src/sys/fileinfo.c | 9 +-- 3 files changed, 139 insertions(+), 34 deletions(-) diff --git a/src/sys/driver.h b/src/sys/driver.h index 355d82d1..fecb61be 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -1114,9 +1114,9 @@ VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, BOOLEAN HandleCleanup); /* TRUE to decrement handle count */ NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode, UINT64 FlushOffset64, ULONG FlushLength, BOOLEAN FlushAndPurge); +BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, + FSP_FILE_NODE *FileNode, PUNICODE_STRING FileName); VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName); -BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject, - PUNICODE_STRING FileName, BOOLEAN SubpathOnly); VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject, diff --git a/src/sys/file.c b/src/sys/file.c index 9f3d3504..8b9cac5c 100644 --- a/src/sys/file.c +++ b/src/sys/file.c @@ -41,9 +41,9 @@ VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, BOOLEAN HandleCleanup); /* TRUE to decrement handle count */ NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode, UINT64 FlushOffset64, ULONG FlushLength, BOOLEAN FlushAndPurge); +BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, + FSP_FILE_NODE *FileNode, PUNICODE_STRING FileName); VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName); -BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject, - PUNICODE_STRING FileName, BOOLEAN SubpathOnly); VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject, @@ -103,8 +103,8 @@ NTSTATUS FspMainFileClose( #pragma alloc_text(PAGE, FspFileNodeCleanupComplete) #pragma alloc_text(PAGE, FspFileNodeClose) #pragma alloc_text(PAGE, FspFileNodeFlushAndPurgeCache) +#pragma alloc_text(PAGE, FspFileNodeRenameCheck) #pragma alloc_text(PAGE, FspFileNodeRename) -#pragma alloc_text(PAGE, FspFileNodeHasOpenHandles) #pragma alloc_text(PAGE, FspFileNodeGetFileInfo) #pragma alloc_text(PAGE, FspFileNodeTryGetFileInfo) #pragma alloc_text(PAGE, FspFileNodeSetFileInfo) @@ -833,6 +833,137 @@ NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode, return IoStatus.Status; } +BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, + FSP_FILE_NODE *FileNode, PUNICODE_STRING FileName) +{ + PAGED_CODE(); + + FSP_FILE_NODE *DescendantFileNode; + FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes; + ULONG DescendantFileNodeCount, DescendantFileNodeIndex; + FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey; + BOOLEAN SubpathOnly = 0 != FileNode; + BOOLEAN Success = TRUE; + + FspFsvolDeviceLockContextTable(FsvolDeviceObject); + + DescendantFileNodes = DescendantFileNodeArray; + + if (0 != FileNode) + { + if (1 < FileNode->HandleCount) + { + Success = FALSE; + goto unlock_exit; + } + + if (!FileNode->IsDirectory) + goto unlock_exit; + } + + DescendantFileNodeCount = 0; + memset(&RestartKey, 0, sizeof RestartKey); + for (;;) + { + DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject, + FileName, SubpathOnly, &RestartKey); + if (0 == DescendantFileNode) + break; + + if (0 < DescendantFileNode->HandleCount) + { + if (FsRtlCurrentBatchOplock(FspFileNodeAddrOfOplock(DescendantFileNode)) || + FsRtlCurrentOplockH(FspFileNodeAddrOfOplock(DescendantFileNode))) + { + if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount) + DescendantFileNodes[DescendantFileNodeCount] = DescendantFileNode; + DescendantFileNodeCount++; + } + else + { + Success = FALSE; + goto unlock_exit; + } + } + } + + if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount) + { + DescendantFileNodes = FspAllocMustSucceed(DescendantFileNodeCount * sizeof(FSP_FILE_NODE *)); + DescendantFileNodeIndex = 0; + memset(&RestartKey, 0, sizeof RestartKey); + for (;;) + { + DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject, + FileName, SubpathOnly, &RestartKey); + if (0 == DescendantFileNode) + break; + + if (0 < DescendantFileNode->HandleCount) + { + if (FsRtlCurrentBatchOplock(FspFileNodeAddrOfOplock(DescendantFileNode)) || + FsRtlCurrentOplockH(FspFileNodeAddrOfOplock(DescendantFileNode))) + { + DescendantFileNodes[DescendantFileNodeIndex] = DescendantFileNode; + DescendantFileNodeIndex++; + ASSERT(DescendantFileNodeCount >= DescendantFileNodeIndex); + } + else + { + Success = FALSE; + goto unlock_exit; + } + } + } + + ASSERT(DescendantFileNodeCount == DescendantFileNodeIndex); + } + + FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); + + for ( + DescendantFileNodeIndex = 0; + DescendantFileNodeCount > DescendantFileNodeIndex; + DescendantFileNodeIndex++) + { + DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex]; + + FspCheckOplock(FspFileNodeAddrOfOplock(DescendantFileNode), Irp, 0, 0, 0); + } + + FspFsvolDeviceLockContextTable(FsvolDeviceObject); + + memset(&RestartKey, 0, sizeof RestartKey); + for (;;) + { + DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject, + FileName, SubpathOnly, &RestartKey); + if (0 == DescendantFileNode) + break; + + if (0 < DescendantFileNode->HandleCount) + { + Success = FALSE; + goto unlock_exit; + } + } + + FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); + + if (DescendantFileNodeArray != DescendantFileNodes) + FspFree(DescendantFileNodes); + + return Success; + +unlock_exit: + FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); + + if (DescendantFileNodeArray != DescendantFileNodes) + FspFree(DescendantFileNodes); + + return Success; +} + VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName) { /* @@ -953,29 +1084,6 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName) FspFree(DescendantFileNodes); } -BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject, - PUNICODE_STRING FileName, BOOLEAN SubpathOnly) -{ - /* - * The ContextByNameTable must be already locked. - */ - - PAGED_CODE(); - - FSP_FILE_NODE *FileNode; - FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey = { 0 }; - - for (;;) - { - FileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject, FileName, SubpathOnly, - &RestartKey); - if (0 == FileNode) - return FALSE; - if (0 < FileNode->HandleCount) - return TRUE; - } -} - VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo) { PAGED_CODE(); diff --git a/src/sys/fileinfo.c b/src/sys/fileinfo.c index 174c882f..33a17c7e 100644 --- a/src/sys/fileinfo.c +++ b/src/sys/fileinfo.c @@ -1280,13 +1280,9 @@ retry: * that has open handles (except in the batch-oplock case described earlier). */ Result = STATUS_SUCCESS; - FspFsvolDeviceLockContextTable(FsvolDeviceObject); - if (1 < FileNode->HandleCount || - (FileNode->IsDirectory && - FspFileNodeHasOpenHandles(FsvolDeviceObject, &FileNode->FileName, TRUE)) || - FspFileNodeHasOpenHandles(FsvolDeviceObject, &NewFileName, FALSE)) + if (!FspFileNodeRenameCheck(FsvolDeviceObject, Irp, FileNode, &FileNode->FileName) && + !FspFileNodeRenameCheck(FsvolDeviceObject, Irp, 0, &NewFileName)) Result = STATUS_ACCESS_DENIED; - FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); if (!NT_SUCCESS(Result)) return Result; @@ -1408,6 +1404,7 @@ static NTSTATUS FspFsvolSetInformation( ASSERT(FileNode == FileDesc->FileNode); +retry: FspFileNodeAcquireExclusive(FileNode, Full); if (FileAllocationInformation == FileInformationClass ||