2017-09-08 08:02:43 +00:00
|
|
|
/* Copyright (c) Mark Harmstone 2016-17
|
|
|
|
*
|
2016-09-04 15:27:46 +00:00
|
|
|
* This file is part of WinBtrfs.
|
2017-09-08 08:02:43 +00:00
|
|
|
*
|
2016-09-04 15:27:46 +00:00
|
|
|
* WinBtrfs is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Lesser General Public Licence as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the Licence, or
|
|
|
|
* (at your option) any later version.
|
2017-09-08 08:02:43 +00:00
|
|
|
*
|
2016-09-04 15:27:46 +00:00
|
|
|
* WinBtrfs is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Lesser General Public Licence for more details.
|
2017-09-08 08:02:43 +00:00
|
|
|
*
|
2016-09-04 15:27:46 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public Licence
|
|
|
|
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
|
2016-07-27 19:24:26 +00:00
|
|
|
#include "btrfs_drv.h"
|
|
|
|
|
2016-10-29 17:05:10 +00:00
|
|
|
typedef struct {
|
|
|
|
device_extension* Vcb;
|
|
|
|
PIRP Irp;
|
|
|
|
WORK_QUEUE_ITEM item;
|
|
|
|
} job_info;
|
|
|
|
|
2019-09-01 12:53:20 +00:00
|
|
|
NTSTATUS do_read_job(PIRP Irp) {
|
2016-07-27 19:24:26 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
ULONG bytes_read;
|
2019-09-01 12:53:20 +00:00
|
|
|
bool top_level = is_top_level(Irp);
|
2016-10-29 17:05:10 +00:00
|
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
|
|
fcb* fcb = FileObject->FsContext;
|
2019-09-01 12:53:20 +00:00
|
|
|
bool acquired_fcb_lock = false;
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-07-27 19:24:26 +00:00
|
|
|
Irp->IoStatus.Information = 0;
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-10-29 17:05:10 +00:00
|
|
|
if (!ExIsResourceAcquiredSharedLite(fcb->Header.Resource)) {
|
2019-09-01 12:53:20 +00:00
|
|
|
ExAcquireResourceSharedLite(fcb->Header.Resource, true);
|
|
|
|
acquired_fcb_lock = true;
|
2016-10-29 17:05:10 +00:00
|
|
|
}
|
2017-09-08 08:02:43 +00:00
|
|
|
|
|
|
|
_SEH2_TRY {
|
2019-09-01 12:53:20 +00:00
|
|
|
Status = do_read(Irp, true, &bytes_read);
|
2017-09-08 08:02:43 +00:00
|
|
|
} _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
Status = _SEH2_GetExceptionCode();
|
|
|
|
} _SEH2_END;
|
|
|
|
|
2019-09-01 12:53:20 +00:00
|
|
|
if (acquired_fcb_lock)
|
2016-10-29 17:05:10 +00:00
|
|
|
ExReleaseResourceLite(fcb->Header.Resource);
|
2016-07-27 19:24:26 +00:00
|
|
|
|
2017-09-08 08:02:43 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2020-04-23 02:38:57 +00:00
|
|
|
ERR("do_read returned %08lx\n", Status);
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-07-27 19:24:26 +00:00
|
|
|
Irp->IoStatus.Status = Status;
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2020-04-23 02:38:57 +00:00
|
|
|
TRACE("read %Iu bytes\n", Irp->IoStatus.Information);
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-07-27 19:24:26 +00:00
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
2017-09-08 08:02:43 +00:00
|
|
|
|
|
|
|
if (top_level)
|
2016-07-27 19:24:26 +00:00
|
|
|
IoSetTopLevelIrp(NULL);
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2020-04-23 02:38:57 +00:00
|
|
|
TRACE("returning %08lx\n", Status);
|
2019-09-01 12:53:20 +00:00
|
|
|
|
|
|
|
return Status;
|
2016-07-27 19:24:26 +00:00
|
|
|
}
|
|
|
|
|
2019-09-01 12:53:20 +00:00
|
|
|
NTSTATUS do_write_job(device_extension* Vcb, PIRP Irp) {
|
|
|
|
bool top_level = is_top_level(Irp);
|
2016-07-27 19:24:26 +00:00
|
|
|
NTSTATUS Status;
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-07-27 19:24:26 +00:00
|
|
|
_SEH2_TRY {
|
2019-09-01 12:53:20 +00:00
|
|
|
Status = write_file(Vcb, Irp, true, true);
|
2016-07-27 19:24:26 +00:00
|
|
|
} _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
Status = _SEH2_GetExceptionCode();
|
|
|
|
} _SEH2_END;
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-10-29 17:05:10 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2020-04-23 02:38:57 +00:00
|
|
|
ERR("write_file returned %08lx\n", Status);
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-07-27 19:24:26 +00:00
|
|
|
Irp->IoStatus.Status = Status;
|
|
|
|
|
2020-04-23 02:38:57 +00:00
|
|
|
TRACE("wrote %Iu bytes\n", Irp->IoStatus.Information);
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-07-27 19:24:26 +00:00
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
2017-09-08 08:02:43 +00:00
|
|
|
|
|
|
|
if (top_level)
|
2016-07-27 19:24:26 +00:00
|
|
|
IoSetTopLevelIrp(NULL);
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2020-04-23 02:38:57 +00:00
|
|
|
TRACE("returning %08lx\n", Status);
|
2019-09-01 12:53:20 +00:00
|
|
|
|
|
|
|
return Status;
|
2016-07-27 19:24:26 +00:00
|
|
|
}
|
|
|
|
|
2017-09-08 08:02:43 +00:00
|
|
|
_Function_class_(WORKER_THREAD_ROUTINE)
|
2019-09-01 12:53:20 +00:00
|
|
|
static void __stdcall do_job(void* context) {
|
2016-10-29 17:05:10 +00:00
|
|
|
job_info* ji = context;
|
|
|
|
PIO_STACK_LOCATION IrpSp = ji->Irp ? IoGetCurrentIrpStackLocation(ji->Irp) : NULL;
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-07-27 19:24:26 +00:00
|
|
|
if (IrpSp->MajorFunction == IRP_MJ_READ) {
|
2016-10-29 17:05:10 +00:00
|
|
|
do_read_job(ji->Irp);
|
2016-07-27 19:24:26 +00:00
|
|
|
} else if (IrpSp->MajorFunction == IRP_MJ_WRITE) {
|
2016-10-29 17:05:10 +00:00
|
|
|
do_write_job(ji->Vcb, ji->Irp);
|
2016-07-27 19:24:26 +00:00
|
|
|
}
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-10-29 17:05:10 +00:00
|
|
|
ExFreePool(ji);
|
2016-07-27 19:24:26 +00:00
|
|
|
}
|
|
|
|
|
2019-09-01 12:53:20 +00:00
|
|
|
bool add_thread_job(device_extension* Vcb, PIRP Irp) {
|
2016-10-29 17:05:10 +00:00
|
|
|
job_info* ji;
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-10-29 17:05:10 +00:00
|
|
|
ji = ExAllocatePoolWithTag(NonPagedPool, sizeof(job_info), ALLOC_TAG);
|
|
|
|
if (!ji) {
|
|
|
|
ERR("out of memory\n");
|
2019-09-01 12:53:20 +00:00
|
|
|
return false;
|
2016-10-29 17:05:10 +00:00
|
|
|
}
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-10-29 17:05:10 +00:00
|
|
|
ji->Vcb = Vcb;
|
|
|
|
ji->Irp = Irp;
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-10-29 17:05:10 +00:00
|
|
|
if (!Irp->MdlAddress) {
|
|
|
|
PMDL Mdl;
|
|
|
|
LOCK_OPERATION op;
|
|
|
|
ULONG len;
|
|
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-10-29 17:05:10 +00:00
|
|
|
if (IrpSp->MajorFunction == IRP_MJ_READ) {
|
|
|
|
op = IoWriteAccess;
|
|
|
|
len = IrpSp->Parameters.Read.Length;
|
|
|
|
} else if (IrpSp->MajorFunction == IRP_MJ_WRITE) {
|
|
|
|
op = IoReadAccess;
|
|
|
|
len = IrpSp->Parameters.Write.Length;
|
|
|
|
} else {
|
|
|
|
ERR("unexpected major function %u\n", IrpSp->MajorFunction);
|
2017-09-08 08:02:43 +00:00
|
|
|
ExFreePool(ji);
|
2019-09-01 12:53:20 +00:00
|
|
|
return false;
|
2016-07-27 19:24:26 +00:00
|
|
|
}
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2019-09-01 12:53:20 +00:00
|
|
|
Mdl = IoAllocateMdl(Irp->UserBuffer, len, false, false, Irp);
|
2016-10-29 17:05:10 +00:00
|
|
|
|
|
|
|
if (!Mdl) {
|
|
|
|
ERR("out of memory\n");
|
2017-09-08 08:02:43 +00:00
|
|
|
ExFreePool(ji);
|
2019-09-01 12:53:20 +00:00
|
|
|
return false;
|
2016-10-29 17:05:10 +00:00
|
|
|
}
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-10-29 17:05:10 +00:00
|
|
|
_SEH2_TRY {
|
|
|
|
MmProbeAndLockPages(Mdl, Irp->RequestorMode, op);
|
|
|
|
} _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
2020-04-23 02:38:57 +00:00
|
|
|
ERR("MmProbeAndLockPages raised status %08lx\n", _SEH2_GetExceptionCode());
|
2016-10-29 17:05:10 +00:00
|
|
|
|
|
|
|
IoFreeMdl(Mdl);
|
|
|
|
Irp->MdlAddress = NULL;
|
2017-09-08 08:02:43 +00:00
|
|
|
ExFreePool(ji);
|
2016-10-29 17:05:10 +00:00
|
|
|
|
|
|
|
_SEH2_YIELD(return FALSE);
|
|
|
|
} _SEH2_END;
|
2016-07-27 19:24:26 +00:00
|
|
|
}
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2016-10-29 17:05:10 +00:00
|
|
|
ExInitializeWorkItem(&ji->item, do_job, ji);
|
|
|
|
ExQueueWorkItem(&ji->item, DelayedWorkQueue);
|
2017-09-08 08:02:43 +00:00
|
|
|
|
2019-09-01 12:53:20 +00:00
|
|
|
return true;
|
2016-07-27 19:24:26 +00:00
|
|
|
}
|