sys: IRP_MJ_FLUSH_BUFFERS: flush volume implementation

This commit is contained in:
Bill Zissimopoulos 2016-04-04 14:33:23 -07:00
parent 71c1469b46
commit 83c59a6f37
4 changed files with 173 additions and 37 deletions

View File

@ -40,6 +40,9 @@ VOID FspFsvolDeviceDeleteContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier,
static RTL_AVL_COMPARE_ROUTINE FspFsvolDeviceCompareContext; static RTL_AVL_COMPARE_ROUTINE FspFsvolDeviceCompareContext;
static RTL_AVL_ALLOCATE_ROUTINE FspFsvolDeviceAllocateContext; static RTL_AVL_ALLOCATE_ROUTINE FspFsvolDeviceAllocateContext;
static RTL_AVL_FREE_ROUTINE FspFsvolDeviceFreeContext; static RTL_AVL_FREE_ROUTINE FspFsvolDeviceFreeContext;
NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
PVOID **PContexts, PULONG PContextCount);
VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount);
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
BOOLEAN SubpathOnly, PVOID *PRestartKey); BOOLEAN SubpathOnly, PVOID *PRestartKey);
PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName); PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName);
@ -79,6 +82,8 @@ VOID FspDeviceDeleteAll(VOID);
#pragma alloc_text(PAGE, FspFsvolDeviceCompareContext) #pragma alloc_text(PAGE, FspFsvolDeviceCompareContext)
#pragma alloc_text(PAGE, FspFsvolDeviceAllocateContext) #pragma alloc_text(PAGE, FspFsvolDeviceAllocateContext)
#pragma alloc_text(PAGE, FspFsvolDeviceFreeContext) #pragma alloc_text(PAGE, FspFsvolDeviceFreeContext)
#pragma alloc_text(PAGE, FspFsvolDeviceCopyContextByNameList)
#pragma alloc_text(PAGE, FspFsvolDeviceDeleteContextByNameList)
#pragma alloc_text(PAGE, FspFsvolDeviceEnumerateContextByName) #pragma alloc_text(PAGE, FspFsvolDeviceEnumerateContextByName)
#pragma alloc_text(PAGE, FspFsvolDeviceLookupContextByName) #pragma alloc_text(PAGE, FspFsvolDeviceLookupContextByName)
#pragma alloc_text(PAGE, FspFsvolDeviceInsertContextByName) #pragma alloc_text(PAGE, FspFsvolDeviceInsertContextByName)
@ -653,6 +658,45 @@ static VOID NTAPI FspFsvolDeviceFreeContext(
PAGED_CODE(); PAGED_CODE();
} }
NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
PVOID **PContexts, PULONG PContextCount)
{
PAGED_CODE();
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT_DATA *Data;
PVOID *Contexts;
ULONG ContextCount, Index;
*PContexts = 0;
*PContextCount = 0;
ContextCount = RtlNumberGenericTableElementsAvl(&FsvolDeviceExtension->ContextByNameTable);
Contexts = FspAlloc(sizeof(PVOID) * ContextCount);
if (0 == Contexts)
return STATUS_INSUFFICIENT_RESOURCES;
Index = 0;
Data = RtlEnumerateGenericTableAvl(&FsvolDeviceExtension->ContextByNameTable, TRUE);
while (Index < ContextCount && 0 != Data)
{
Contexts[Index++] = Data->Context;
Data = RtlEnumerateGenericTableAvl(&FsvolDeviceExtension->ContextByNameTable, FALSE);
}
*PContexts = Contexts;
*PContextCount = Index;
return STATUS_SUCCESS;
}
VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount)
{
PAGED_CODE();
FspFree(Contexts);
}
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
BOOLEAN SubpathOnly, PVOID *PRestartKey) BOOLEAN SubpathOnly, PVOID *PRestartKey)
{ {
@ -668,7 +712,7 @@ PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE
Result = RtlEnumerateGenericTableLikeADirectory(&FsvolDeviceExtension->ContextByNameTable, Result = RtlEnumerateGenericTableLikeADirectory(&FsvolDeviceExtension->ContextByNameTable,
0, 0, SubpathOnly, PRestartKey, &DeleteCount, &FileName); 0, 0, SubpathOnly, PRestartKey, &DeleteCount, &FileName);
if (0 != Result && if (0 != Result &&
RtlPrefixUnicodeString(FileName, Result->FileName, CaseInsensitive) && RtlPrefixUnicodeString(FileName, Result->FileName, CaseInsensitive) &&
FileName->Length < Result->FileName->Length && FileName->Length < Result->FileName->Length &&

View File

@ -764,6 +764,9 @@ PVOID FspFsvolDeviceInsertContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier
FSP_DEVICE_CONTEXT_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted); FSP_DEVICE_CONTEXT_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted);
VOID FspFsvolDeviceDeleteContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, VOID FspFsvolDeviceDeleteContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier,
PBOOLEAN PDeleted); PBOOLEAN PDeleted);
NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject,
PVOID **PContexts, PULONG PContextCount);
VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount);
PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName,
BOOLEAN SubpathOnly, PVOID *PRestartKey); BOOLEAN SubpathOnly, PVOID *PRestartKey);
PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName); PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName);
@ -881,6 +884,9 @@ typedef struct
UINT64 DirInfo; UINT64 DirInfo;
ULONG DirInfoCacheHint; ULONG DirInfoCacheHint;
} FSP_FILE_DESC; } FSP_FILE_DESC;
NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount);
VOID FspFileNodeDeleteList(FSP_FILE_NODE **FileNodes, ULONG FileNodeCount);
NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject, NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject,
ULONG ExtraSize, FSP_FILE_NODE **PFileNode); ULONG ExtraSize, FSP_FILE_NODE **PFileNode);
VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode); VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode);

View File

@ -6,6 +6,9 @@
#include <sys/driver.h> #include <sys/driver.h>
NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount);
VOID FspFileNodeDeleteList(FSP_FILE_NODE **FileNodes, ULONG FileNodeCount);
NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject, NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject,
ULONG ExtraSize, FSP_FILE_NODE **PFileNode); ULONG ExtraSize, FSP_FILE_NODE **PFileNode);
VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode); VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode);
@ -51,6 +54,8 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN Reset); PUNICODE_STRING FileName, BOOLEAN Reset);
#ifdef ALLOC_PRAGMA #ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspFileNodeCopyList)
#pragma alloc_text(PAGE, FspFileNodeDeleteList)
#pragma alloc_text(PAGE, FspFileNodeCreate) #pragma alloc_text(PAGE, FspFileNodeCreate)
#pragma alloc_text(PAGE, FspFileNodeDelete) #pragma alloc_text(PAGE, FspFileNodeDelete)
#pragma alloc_text(PAGE, FspFileNodeAcquireSharedF) #pragma alloc_text(PAGE, FspFileNodeAcquireSharedF)
@ -102,6 +107,38 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
if (IrpValid) \ if (IrpValid) \
FspIrpSetFlags(Irp, FspIrpFlags(Irp) & (~Flags & 3)) FspIrpSetFlags(Irp, FspIrpFlags(Irp) & (~Flags & 3))
NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject,
FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount)
{
PAGED_CODE();
NTSTATUS Result;
ULONG Index;
FspFsvolDeviceLockContextTable(DeviceObject);
Result = FspFsvolDeviceCopyContextByNameList(DeviceObject, PFileNodes, PFileNodeCount);
if (NT_SUCCESS(Result))
{
for (Index = 0; *PFileNodeCount > Index; Index++)
FspFileNodeReference((*PFileNodes)[Index]);
}
FspFsvolDeviceUnlockContextTable(DeviceObject);
return Result;
}
VOID FspFileNodeDeleteList(FSP_FILE_NODE **FileNodes, ULONG FileNodeCount)
{
PAGED_CODE();
ULONG Index;
for (Index = 0; FileNodeCount > Index; Index++)
FspFileNodeDereference(FileNodes[Index]);
FspFsvolDeviceDeleteContextByNameList(FileNodes, FileNodeCount);
}
NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject, NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject,
ULONG ExtraSize, FSP_FILE_NODE **PFileNode) ULONG ExtraSize, FSP_FILE_NODE **PFileNode)
{ {

View File

@ -7,7 +7,7 @@
#include <sys/driver.h> #include <sys/driver.h>
static NTSTATUS FspFsvolFlushBuffers( static NTSTATUS FspFsvolFlushBuffers(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOCMPL_DISPATCH FspFsvolFlushBuffersComplete; FSP_IOCMPL_DISPATCH FspFsvolFlushBuffersComplete;
static FSP_IOP_REQUEST_FINI FspFsvolFlushBuffersRequestFini; static FSP_IOP_REQUEST_FINI FspFsvolFlushBuffersRequestFini;
FSP_DRIVER_DISPATCH FspFlushBuffers; FSP_DRIVER_DISPATCH FspFlushBuffers;
@ -23,60 +23,98 @@ enum
{ {
/* FlushBuffers */ /* FlushBuffers */
RequestFileNode = 0, RequestFileNode = 0,
RequestFlushResult = 1,
}; };
static NTSTATUS FspFsvolFlushBuffers( static NTSTATUS FspFsvolFlushBuffers(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{ {
PAGED_CODE(); PAGED_CODE();
NTSTATUS Result; NTSTATUS Result, FlushResult;
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
FSP_FILE_NODE **FileNodes;
ULONG FileNodeCount, Index;
IO_STATUS_BLOCK IoStatus;
FSP_FSCTL_TRANSACT_REQ *Request; FSP_FSCTL_TRANSACT_REQ *Request;
/* is this a valid FileObject? */ /*
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext)) * A flush request on the volume (or the root directory according to FastFat)
* is a request to flush the whole volume.
*/
if (!FspFileNodeIsValid(FileNode) || FileNode->IsRootDirectory)
{ {
/* indicate that we are flushing the whole volume! */ Result = FspFileNodeCopyList(FsvolDeviceObject, &FileNodes, &FileNodeCount);
if (!NT_SUCCESS(Result))
return Result;
/*
* Enumerate in reverse order so that files are flushed before containing directories.
* This would be useful if we ever started flushing directories, but since we do not
* it is not as important now.
*/
FlushResult = STATUS_SUCCESS;
for (Index = FileNodeCount - 1; FileNodeCount > Index; Index--)
if (!FileNodes[Index]->IsDirectory)
{
Result = FspCcFlushCache(&FileNodes[Index]->NonPaged->SectionObjectPointers,
0, 0, &IoStatus);
if (!NT_SUCCESS(Result) && NT_SUCCESS(FlushResult))
FlushResult = Result;
}
FspFileNodeDeleteList(FileNodes, FileNodeCount);
Result = FspIopCreateRequest(Irp, 0, 0, &Request); Result = FspIopCreateRequest(Irp, 0, 0, &Request);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
/* a NULL UserContext indicates to user-mode to flush the whole volume! */
Request->Kind = FspFsctlTransactFlushBuffersKind; Request->Kind = FspFsctlTransactFlushBuffersKind;
//Request->Req.FlushBuffers.UserContext = 0;
//Request->Req.FlushBuffers.UserContext2 = 0;
FspIopRequestContext(Request, RequestFileNode) = 0;
FspIopRequestContext(Request, RequestFlushResult) = (PVOID)(UINT_PTR)FlushResult;
return FSP_STATUS_IOQ_POST; return FSP_STATUS_IOQ_POST;
} }
else
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
IO_STATUS_BLOCK IoStatus;
ASSERT(FileNode == FileDesc->FileNode);
FspFileNodeAcquireExclusive(FileNode, Full);
Result = FspCcFlushCache(FileObject->SectionObjectPointer, 0, 0, &IoStatus);
if (!NT_SUCCESS(Result))
{ {
FspFileNodeRelease(FileNode, Full); ASSERT(FileNode == FileDesc->FileNode);
return Result;
/* cannot really flush directories but we will say we did it! */
if (FileNode->IsDirectory)
return STATUS_SUCCESS;
FspFileNodeAcquireExclusive(FileNode, Full);
Result = FspCcFlushCache(FileObject->SectionObjectPointer, 0, 0, &IoStatus);
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Full);
return Result;
}
Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolFlushBuffersRequestFini, &Request);
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Full);
return Result;
}
Request->Kind = FspFsctlTransactFlushBuffersKind;
Request->Req.FlushBuffers.UserContext = FileNode->UserContext;
Request->Req.FlushBuffers.UserContext2 = FileDesc->UserContext2;
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestFileNode) = FileNode;
FspIopRequestContext(Request, RequestFlushResult) = 0;
return FSP_STATUS_IOQ_POST;
} }
Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolFlushBuffersRequestFini, &Request);
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Full);
return Result;
}
Request->Kind = FspFsctlTransactFlushBuffersKind;
Request->Req.FlushBuffers.UserContext = FileNode->UserContext;
Request->Req.FlushBuffers.UserContext2 = FileDesc->UserContext2;
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestFileNode) = FileNode;
return FSP_STATUS_IOQ_POST;
} }
NTSTATUS FspFsvolFlushBuffersComplete( NTSTATUS FspFsvolFlushBuffersComplete(
@ -84,6 +122,17 @@ NTSTATUS FspFsvolFlushBuffersComplete(
{ {
FSP_ENTER_IOC(PAGED_CODE()); FSP_ENTER_IOC(PAGED_CODE());
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
NTSTATUS FlushResult = (NTSTATUS)(UINT_PTR)FspIopRequestContext(Request, RequestFlushResult);
Irp->IoStatus.Information = 0;
if (!NT_SUCCESS(Response->IoStatus.Status))
Result = Response->IoStatus.Status;
else if (!NT_SUCCESS(FlushResult))
Result = FlushResult;
else
Result = STATUS_SUCCESS;
FSP_LEAVE_IOC("FileObject=%p", FSP_LEAVE_IOC("FileObject=%p",
IrpSp->FileObject); IrpSp->FileObject);
} }