From aee12e1c5f591b341b893347b4194856154caf9d Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Mon, 14 Dec 2015 12:36:40 -0800 Subject: [PATCH] sys: FspFsvrtTransact: now has timeout --- inc/winfsp/fsctl.h | 7 +++++++ src/sys/driver.h | 3 ++- src/sys/fsctl.c | 19 +++++++++++++------ src/sys/ioq.c | 14 +++++++------- tst/winfsp-tests/mount-test.c | 11 +++-------- 5 files changed, 32 insertions(+), 22 deletions(-) diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index b40dc72e..9c2cda5b 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -70,11 +70,18 @@ enum FspFsctlTransactQuerySecurityKind = 'S', FspFsctlTransactSetSecurityKind = 's', }; +enum +{ + FspFsctlTransactTimeoutMinimum = 1000, + FspFsctlTransactTimeoutMaximum = 10000, + FspFsctlTransactTimeoutDefault = 1000, +}; typedef struct { UINT16 Version; UINT16 SectorSize; UINT32 SerialNumber; + UINT32 TransactTimeout; /* milliseconds; values between 1000ms and 10000ms */ UINT32 EaSupported:1; /* supports extended attributes (unimplemented; set to 0) */ UINT32 FileNameRequired:1; /* FileName required for all operations (not just Create) */ UINT32 NoSystemAccessCheck:1; /* if set the user-mode flie system performs access checks */ diff --git a/src/sys/driver.h b/src/sys/driver.h index 50f5c7c8..c315cc10 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -246,6 +246,7 @@ FAST_IO_ACQUIRE_FOR_CCFLUSH FspAcquireForCcFlush; FAST_IO_RELEASE_FOR_CCFLUSH FspReleaseForCcFlush; /* I/O queue */ +#define FspIoqTimeout ((PIRP)1) typedef struct { KSPIN_LOCK SpinLock; @@ -258,7 +259,7 @@ VOID FspIoqInitialize(FSP_IOQ *Ioq); VOID FspIoqStop(FSP_IOQ *Ioq); BOOLEAN FspIoqStopped(FSP_IOQ *Ioq); BOOLEAN FspIoqPostIrp(FSP_IOQ *Ioq, PIRP Irp); -PIRP FspIoqNextPendingIrp(FSP_IOQ *Ioq, ULONG millis); +PIRP FspIoqNextPendingIrp(FSP_IOQ *Ioq, PLARGE_INTEGER Timeout); BOOLEAN FspIoqStartProcessingIrp(FSP_IOQ *Ioq, PIRP Irp); PIRP FspIoqEndProcessingIrp(FSP_IOQ *Ioq, UINT_PTR IrpHint); diff --git a/src/sys/fsctl.c b/src/sys/fsctl.c index f5a7bd29..cda06b21 100644 --- a/src/sys/fsctl.c +++ b/src/sys/fsctl.c @@ -353,6 +353,8 @@ static NTSTATUS FspFsvrtTransact( FSP_FSCTL_TRANSACT_RSP *Response, *NextResponse; FSP_FSCTL_TRANSACT_REQ *Request, *PendingIrpRequest; PIRP ProcessIrp, PendingIrp; + ULONG TransactTimeout; + LARGE_INTEGER Timeout; /* access check */ Result = FspSecuritySubjectContextAccessCheck( @@ -380,12 +382,21 @@ static NTSTATUS FspFsvrtTransact( } /* wait for an IRP to arrive */ -retry: - while (0 == (PendingIrp = FspIoqNextPendingIrp(&FsvrtDeviceExtension->Ioq, (ULONG)-1L))) + TransactTimeout = FsvrtDeviceExtension->VolumeParams.TransactTimeout; + if (FspFsctlTransactTimeoutMinimum > TransactTimeout || TransactTimeout > FspFsctlTransactTimeoutMaximum) + TransactTimeout = FspFsctlTransactTimeoutDefault; + KeQuerySystemTime(&Timeout); + Timeout.QuadPart += TransactTimeout * 10000; /* convert millis to nanos and add to absolute time */ + while (0 == (PendingIrp = FspIoqNextPendingIrp(&FsvrtDeviceExtension->Ioq, &Timeout))) { if (FspIoqStopped(&FsvrtDeviceExtension->Ioq)) return STATUS_CANCELLED; } + if (FspIoqTimeout == PendingIrp) + { + Irp->IoStatus.Information = 0; + return STATUS_SUCCESS; + } /* send any pending IRP's to the user-mode file system */ Request = SystemBuffer; @@ -426,10 +437,6 @@ retry: break; } - - if (Request == SystemBuffer) - goto retry; - Irp->IoStatus.Information = (PUINT8)Request - (PUINT8)SystemBuffer; return STATUS_SUCCESS; diff --git a/src/sys/ioq.c b/src/sys/ioq.c index 422681a2..877136a9 100644 --- a/src/sys/ioq.c +++ b/src/sys/ioq.c @@ -209,17 +209,17 @@ BOOLEAN FspIoqPostIrp(FSP_IOQ *Ioq, PIRP Irp) return NT_SUCCESS(Result); } -PIRP FspIoqNextPendingIrp(FSP_IOQ *Ioq, ULONG millis) +PIRP FspIoqNextPendingIrp(FSP_IOQ *Ioq, PLARGE_INTEGER Timeout) { - if (0 != millis) + /* timeout of 0 normally means infinite wait; for us it means do not do any wait at all! */ + if (0 != Timeout) { NTSTATUS Result; - LARGE_INTEGER Timeout; - Timeout.QuadPart = (LONGLONG)millis * 10000; Result = KeWaitForSingleObject(&Ioq->PendingIrpEvent, Executive, KernelMode, FALSE, - -1 == millis ? 0 : &Timeout); - if (STATUS_SUCCESS != Result) - return 0; + Timeout); + ASSERT(STATUS_SUCCESS == Result || STATUS_TIMEOUT == Result); + if (STATUS_TIMEOUT == Result) + return FspIoqTimeout; } return IoCsqRemoveNextIrp(&Ioq->PendingIoCsq, (PVOID)1); } diff --git a/tst/winfsp-tests/mount-test.c b/tst/winfsp-tests/mount-test.c index 79919b37..079bff58 100644 --- a/tst/winfsp-tests/mount-test.c +++ b/tst/winfsp-tests/mount-test.c @@ -194,13 +194,8 @@ void mount_volume_transact_dotest(PWSTR DeviceName) Response->Size = sizeof *Response; Response->Hint = Request->Hint; Response->Kind = Request->Kind; - Response->IoStatus.Status = STATUS_SUCCESS; - Response->IoStatus.Information = FILE_CREATED; - Response->Rsp.Create.Opened.UserContext = 41; - Response->Rsp.Create.Opened.UserContext2 = 42; - Response->Rsp.Create.Opened.FileAttributes = FILE_ATTRIBUTE_NORMAL; - Response->Rsp.Create.Opened.SecurityDescriptor.Offset = 0; - Response->Rsp.Create.Opened.SecurityDescriptor.Size = 0; + Response->IoStatus.Status = STATUS_ACCESS_DENIED; + Response->IoStatus.Information = 0; Response = FspFsctlTransactProduceResponse(Response, Response->Size); ASSERT(0 != Response); @@ -224,7 +219,7 @@ void mount_volume_transact_dotest(PWSTR DeviceName) GetExitCodeThread(Thread, &ExitCode); CloseHandle(Thread); - ASSERT(0 == ExitCode); + ASSERT(ERROR_ACCESS_DENIED == ExitCode); } void mount_volume_transact_test(void)