sys: file: GATHER_DESCENDANTS, SCATTER_DESCENDANTS macros

This commit is contained in:
Bill Zissimopoulos 2016-11-22 11:32:40 -08:00
parent b0a59e42fc
commit 8f10ba4fc9

View File

@ -851,6 +851,65 @@ NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
return IoStatus.Status; return IoStatus.Status;
} }
#define GATHER_DESCENDANTS(FILENAME, SUBPATHONLY, REFERENCE, ...)\
FSP_FILE_NODE *DescendantFileNode;\
FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;\
ULONG DescendantFileNodeCount, DescendantFileNodeIndex;\
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey;\
DescendantFileNodes = DescendantFileNodeArray;\
DescendantFileNodeCount = 0;\
memset(&RestartKey, 0, sizeof RestartKey);\
for (;;) \
{ \
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\
FILENAME, SUBPATHONLY, &RestartKey);\
if (0 == DescendantFileNode) \
break; \
ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\
__VA_ARGS__; \
if (REFERENCE) \
FspFileNodeReference((PVOID)((UINT_PTR)DescendantFileNode & ~7));\
if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount)\
DescendantFileNodes[DescendantFileNodeCount] = DescendantFileNode;\
DescendantFileNodeCount++; \
} \
if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount ||\
DEBUGTEST_EX(0 != DescendantFileNodeCount, 10, FALSE)) \
{ \
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; \
ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\
__VA_ARGS__; \
DescendantFileNodes[DescendantFileNodeIndex] = DescendantFileNode;\
DescendantFileNodeIndex++; \
ASSERT(DescendantFileNodeCount >= DescendantFileNodeIndex);\
} \
ASSERT(DescendantFileNodeCount == DescendantFileNodeIndex);\
} \
((VOID)0)
#define SCATTER_DESCENDANTS(REFERENCE) \
if (REFERENCE) \
{ \
for ( \
DescendantFileNodeIndex = 0;\
DescendantFileNodeCount > DescendantFileNodeIndex;\
DescendantFileNodeIndex++) \
{ \
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];\
FspFileNodeDereference((PVOID)((UINT_PTR)DescendantFileNode & ~7));\
} \
} \
if (DescendantFileNodeArray != DescendantFileNodes)\
FspFree(DescendantFileNodes); \
((VOID)0)
NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams( NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
PDEVICE_OBJECT FsvolDeviceObject, PDEVICE_OBJECT FsvolDeviceObject,
PIRP OplockIrp, PIRP OplockIrp,
@ -867,91 +926,30 @@ NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
ASSERT(0 == FileNode->MainFileNode); ASSERT(0 == FileNode->MainFileNode);
FSP_FILE_NODE *DescendantFileNode;
FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;
ULONG DescendantFileNodeCount, DescendantFileNodeIndex;
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey;
USHORT FileNameLength = FileNode->FileName.Length; USHORT FileNameLength = FileNode->FileName.Length;
BOOLEAN CaseInsensitive = !FspFsvolDeviceExtension(FsvolDeviceObject)-> BOOLEAN CaseInsensitive = !FspFsvolDeviceExtension(FsvolDeviceObject)->
VolumeParams.CaseSensitiveSearch; VolumeParams.CaseSensitiveSearch;
ULONG IsBatchOplock, IsHandleOplock; ULONG IsBatchOplock, IsHandleOplock;
NTSTATUS Result; NTSTATUS Result;
DescendantFileNodes = DescendantFileNodeArray;
DescendantFileNodeCount = 0;
FspFsvolDeviceLockContextTable(FsvolDeviceObject); FspFsvolDeviceLockContextTable(FsvolDeviceObject);
/* count descendant file nodes and try to gather them in a local array if possible */ GATHER_DESCENDANTS(&FileNode->FileName, FALSE, TRUE,
memset(&RestartKey, 0, sizeof RestartKey);
for (;;)
{
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
&FileNode->FileName, FALSE, &RestartKey);
if (0 == DescendantFileNode)
break;
if (DescendantFileNode->FileName.Length > FileNameLength && if (DescendantFileNode->FileName.Length > FileNameLength &&
L'\\' == DescendantFileNode->FileName.Buffer[FileNameLength / sizeof(WCHAR)]) L'\\' == DescendantFileNode->FileName.Buffer[FileNameLength / sizeof(WCHAR)])
break; break;
if (0 >= DescendantFileNode->HandleCount)
if (1 >= DescendantFileNode->HandleCount)
continue; continue;
if (0 != StreamFileName) if (0 != StreamFileName)
{ {
if (DescendantFileNode != FileNode && if (DescendantFileNode != FileNode &&
0 != FspFileNameCompare(&DescendantFileNode->FileName, StreamFileName, 0 != FspFileNameCompare(&DescendantFileNode->FileName, StreamFileName,
CaseInsensitive, 0)) CaseInsensitive, 0))
continue; continue;
} });
ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));
/* keep a reference to the FileNode in case it goes away in later processing */
FspFileNodeReference(DescendantFileNode);
if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount)
DescendantFileNodes[DescendantFileNodeCount] = DescendantFileNode;
DescendantFileNodeCount++;
}
ASSERT(0 != StreamFileName || DescendantFileNodeCount <= 2);
/* if the local array is out of space, gather descendant file nodes in the pool */
if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount)
{
ASSERT(0 == StreamFileName);
DescendantFileNodes = FspAllocMustSucceed(DescendantFileNodeCount * sizeof(FSP_FILE_NODE *));
DescendantFileNodeIndex = 0;
memset(&RestartKey, 0, sizeof RestartKey);
for (;;)
{
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
&FileNode->FileName, FALSE, &RestartKey);
if (0 == DescendantFileNode)
break;
if (DescendantFileNode->FileName.Length > FileNameLength &&
L'\\' == DescendantFileNode->FileName.Buffer[FileNameLength / sizeof(WCHAR)])
break;
if (1 >= DescendantFileNode->HandleCount)
continue;
DescendantFileNodes[DescendantFileNodeIndex] = DescendantFileNode;
DescendantFileNodeIndex++;
ASSERT(DescendantFileNodeCount >= DescendantFileNodeIndex);
}
ASSERT(DescendantFileNodeCount == DescendantFileNodeIndex);
}
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
/*
* At this point all descendant FileNode's are enumerated and referenced.
*/
/* break any Batch or Handle oplocks on descendants */ /* break any Batch or Handle oplocks on descendants */
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
for ( for (
@ -993,6 +991,7 @@ NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
} }
} }
/* release the FileNode so that we can safely wait without deadlocks */
FspFileNodeReleaseF(FileNode, AcquireFlags); FspFileNodeReleaseF(FileNode, AcquireFlags);
/* wait for oplock breaks to finish */ /* wait for oplock breaks to finish */
@ -1024,20 +1023,7 @@ NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
} }
} }
/* dereference all FileNode's referenced during initial enumeration */ SCATTER_DESCENDANTS(TRUE);
for (
DescendantFileNodeIndex = 0;
DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex++)
{
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
FspFileNodeDereference(DescendantFileNode);
}
if (DescendantFileNodeArray != DescendantFileNodes)
FspFree(DescendantFileNodes);
return Result; return Result;
} }
@ -1047,28 +1033,10 @@ BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
{ {
PAGED_CODE(); PAGED_CODE();
/*
* Special rules for renaming open files:
* - A file cannot be renamed if it has any open handles,
* unless it is only open because of a batch opportunistic lock (oplock)
* and the batch oplock can be broken immediately.
* - A file cannot be renamed if a file with the same name exists
* and has open handles (except in the batch-oplock case described earlier).
* - A directory cannot be renamed if it or any of its subdirectories contains a file
* that has open handles (except in the batch-oplock case described earlier).
*/
FSP_FILE_NODE *DescendantFileNode;
FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;
ULONG DescendantFileNodeCount, DescendantFileNodeIndex;
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey;
BOOLEAN CheckingOldName = 0 != FileNode; BOOLEAN CheckingOldName = 0 != FileNode;
BOOLEAN HasOpenHandles; BOOLEAN HasOpenHandles;
BOOLEAN Success = TRUE; BOOLEAN Success = TRUE;
DescendantFileNodes = DescendantFileNodeArray;
DescendantFileNodeCount = 0;
FspFsvolDeviceLockContextTable(FsvolDeviceObject); FspFsvolDeviceLockContextTable(FsvolDeviceObject);
/* if we are checking the existing file name, do a quick check here */ /* if we are checking the existing file name, do a quick check here */
@ -1077,32 +1045,16 @@ BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
/* if file has single open handle (also means no streams open) and not a directory, exit now */ /* if file has single open handle (also means no streams open) and not a directory, exit now */
if (1 == FileNode->HandleCount && !FileNode->IsDirectory) if (1 == FileNode->HandleCount && !FileNode->IsDirectory)
{ {
ASSERT(Success); FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
goto unlock_exit; return TRUE;
} }
/* Note: when CheckingOldName==TRUE, the old FileNode is not included in enumerations below */ /* Note: when CheckingOldName==TRUE, the old FileNode is not included in enumerations below */
} }
/* count descendant file nodes and try to gather them in a local array if possible */ GATHER_DESCENDANTS(FileName, CheckingOldName, TRUE,
memset(&RestartKey, 0, sizeof RestartKey); DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode |
for (;;) (0 < DescendantFileNode->HandleCount)));
{
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
FileName, CheckingOldName, &RestartKey);
if (0 == DescendantFileNode)
break;
/* keep a reference to the FileNode in case it goes away in later processing */
FspFileNodeReference(DescendantFileNode);
HasOpenHandles = 0 < DescendantFileNode->HandleCount;
if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount)
DescendantFileNodes[DescendantFileNodeCount] =
(PVOID)((UINT_PTR)DescendantFileNode | HasOpenHandles);
DescendantFileNodeCount++;
}
if (0 == DescendantFileNodeCount) if (0 == DescendantFileNodeCount)
{ {
@ -1110,30 +1062,6 @@ BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
goto unlock_exit; goto unlock_exit;
} }
/* if the local array is out of space, gather descendant file nodes in the pool */
if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount)
{
DescendantFileNodes = FspAllocMustSucceed(DescendantFileNodeCount * sizeof(FSP_FILE_NODE *));
DescendantFileNodeIndex = 0;
memset(&RestartKey, 0, sizeof RestartKey);
for (;;)
{
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
FileName, CheckingOldName, &RestartKey);
if (0 == DescendantFileNode)
break;
HasOpenHandles = 0 < DescendantFileNode->HandleCount;
DescendantFileNodes[DescendantFileNodeIndex] =
(PVOID)((UINT_PTR)DescendantFileNode | HasOpenHandles);
DescendantFileNodeIndex++;
ASSERT(DescendantFileNodeCount >= DescendantFileNodeIndex);
}
ASSERT(DescendantFileNodeCount == DescendantFileNodeIndex);
}
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
/* /*
@ -1197,20 +1125,7 @@ BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
unlock_exit: unlock_exit:
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
/* dereference all FileNode's referenced during initial enumeration */ SCATTER_DESCENDANTS(TRUE);
for (
DescendantFileNodeIndex = 0;
DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex++)
{
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~1);
FspFileNodeDereference(DescendantFileNode);
}
if (DescendantFileNodeArray != DescendantFileNodes)
FspFree(DescendantFileNodes);
return Success; return Success;
} }
@ -1239,52 +1154,13 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName)
PAGED_CODE(); PAGED_CODE();
PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject; PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject;
FSP_FILE_NODE *DescendantFileNode;
FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;
ULONG DescendantFileNodeCount, DescendantFileNodeIndex;
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey;
BOOLEAN Deleted, Inserted, AcquireForeign; BOOLEAN Deleted, Inserted, AcquireForeign;
USHORT FileNameLength; USHORT FileNameLength;
PWSTR ExternalFileName; PWSTR ExternalFileName;
FspFsvolDeviceLockContextTable(FsvolDeviceObject); FspFsvolDeviceLockContextTable(FsvolDeviceObject);
DescendantFileNodes = DescendantFileNodeArray; GATHER_DESCENDANTS(&FileNode->FileName, FALSE, FALSE, {});
DescendantFileNodes[0] = FileNode;
DescendantFileNodeCount = 1;
memset(&RestartKey, 0, sizeof RestartKey);
for (;;)
{
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
&FileNode->FileName, TRUE, &RestartKey);
if (0 == DescendantFileNode)
break;
if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount)
DescendantFileNodes[DescendantFileNodeCount] = DescendantFileNode;
DescendantFileNodeCount++;
}
if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount)
{
DescendantFileNodes = FspAllocMustSucceed(DescendantFileNodeCount * sizeof(FSP_FILE_NODE *));
DescendantFileNodes[0] = FileNode;
DescendantFileNodeIndex = 1;
memset(&RestartKey, 0, sizeof RestartKey);
for (;;)
{
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
&FileNode->FileName, TRUE, &RestartKey);
if (0 == DescendantFileNode)
break;
DescendantFileNodes[DescendantFileNodeIndex] = DescendantFileNode;
DescendantFileNodeIndex++;
ASSERT(DescendantFileNodeCount >= DescendantFileNodeIndex);
}
ASSERT(DescendantFileNodeCount == DescendantFileNodeIndex);
}
FileNameLength = FileNode->FileName.Length; FileNameLength = FileNode->FileName.Length;
for ( for (
@ -1333,8 +1209,7 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName)
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (DescendantFileNodeArray != DescendantFileNodes) SCATTER_DESCENDANTS(FALSE);
FspFree(DescendantFileNodes);
} }
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo) VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo)