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_ALLOCATE_ROUTINE FspFsvolDeviceAllocateContext;
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,
BOOLEAN SubpathOnly, PVOID *PRestartKey);
PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName);
@ -79,6 +82,8 @@ VOID FspDeviceDeleteAll(VOID);
#pragma alloc_text(PAGE, FspFsvolDeviceCompareContext)
#pragma alloc_text(PAGE, FspFsvolDeviceAllocateContext)
#pragma alloc_text(PAGE, FspFsvolDeviceFreeContext)
#pragma alloc_text(PAGE, FspFsvolDeviceCopyContextByNameList)
#pragma alloc_text(PAGE, FspFsvolDeviceDeleteContextByNameList)
#pragma alloc_text(PAGE, FspFsvolDeviceEnumerateContextByName)
#pragma alloc_text(PAGE, FspFsvolDeviceLookupContextByName)
#pragma alloc_text(PAGE, FspFsvolDeviceInsertContextByName)
@ -653,6 +658,45 @@ static VOID NTAPI FspFsvolDeviceFreeContext(
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,
BOOLEAN SubpathOnly, PVOID *PRestartKey)
{

View File

@ -764,6 +764,9 @@ PVOID FspFsvolDeviceInsertContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier
FSP_DEVICE_CONTEXT_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted);
VOID FspFsvolDeviceDeleteContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier,
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,
BOOLEAN SubpathOnly, PVOID *PRestartKey);
PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName);
@ -881,6 +884,9 @@ typedef struct
UINT64 DirInfo;
ULONG DirInfoCacheHint;
} 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,
ULONG ExtraSize, FSP_FILE_NODE **PFileNode);
VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode);

View File

@ -6,6 +6,9 @@
#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,
ULONG ExtraSize, FSP_FILE_NODE **PFileNode);
VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode);
@ -51,6 +54,8 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
PUNICODE_STRING FileName, BOOLEAN Reset);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspFileNodeCopyList)
#pragma alloc_text(PAGE, FspFileNodeDeleteList)
#pragma alloc_text(PAGE, FspFileNodeCreate)
#pragma alloc_text(PAGE, FspFileNodeDelete)
#pragma alloc_text(PAGE, FspFileNodeAcquireSharedF)
@ -102,6 +107,38 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc,
if (IrpValid) \
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,
ULONG ExtraSize, FSP_FILE_NODE **PFileNode)
{

View File

@ -7,7 +7,7 @@
#include <sys/driver.h>
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;
static FSP_IOP_REQUEST_FINI FspFsvolFlushBuffersRequestFini;
FSP_DRIVER_DISPATCH FspFlushBuffers;
@ -23,36 +23,72 @@ enum
{
/* FlushBuffers */
RequestFileNode = 0,
RequestFlushResult = 1,
};
static NTSTATUS FspFsvolFlushBuffers(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
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;
/* 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);
if (!NT_SUCCESS(Result))
return Result;
/* a NULL UserContext indicates to user-mode to flush the whole volume! */
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;
}
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
IO_STATUS_BLOCK IoStatus;
else
{
ASSERT(FileNode == FileDesc->FileNode);
/* 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);
@ -75,15 +111,28 @@ static NTSTATUS FspFsvolFlushBuffers(
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestFileNode) = FileNode;
FspIopRequestContext(Request, RequestFlushResult) = 0;
return FSP_STATUS_IOQ_POST;
}
}
NTSTATUS FspFsvolFlushBuffersComplete(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
{
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",
IrpSp->FileObject);
}