1 /* Copyright (c) Mark Harmstone 2016-17 2 * 3 * This file is part of WinBtrfs. 4 * 5 * WinBtrfs is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU Lesser General Public Licence as published by 7 * the Free Software Foundation, either version 3 of the Licence, or 8 * (at your option) any later version. 9 * 10 * WinBtrfs is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public Licence for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public Licence 16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */ 17 18 #include "btrfs_drv.h" 19 20 typedef struct { 21 device_extension* Vcb; 22 PIRP Irp; 23 WORK_QUEUE_ITEM item; 24 } job_info; 25 26 NTSTATUS do_read_job(PIRP Irp) { 27 NTSTATUS Status; 28 ULONG bytes_read; 29 bool top_level = is_top_level(Irp); 30 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 31 PFILE_OBJECT FileObject = IrpSp->FileObject; 32 fcb* fcb = FileObject->FsContext; 33 bool acquired_fcb_lock = false; 34 35 Irp->IoStatus.Information = 0; 36 37 if (!ExIsResourceAcquiredSharedLite(fcb->Header.Resource)) { 38 ExAcquireResourceSharedLite(fcb->Header.Resource, true); 39 acquired_fcb_lock = true; 40 } 41 42 _SEH2_TRY { 43 Status = do_read(Irp, true, &bytes_read); 44 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 45 Status = _SEH2_GetExceptionCode(); 46 } _SEH2_END; 47 48 if (acquired_fcb_lock) 49 ExReleaseResourceLite(fcb->Header.Resource); 50 51 if (!NT_SUCCESS(Status)) 52 ERR("do_read returned %08lx\n", Status); 53 54 Irp->IoStatus.Status = Status; 55 56 TRACE("read %Iu bytes\n", Irp->IoStatus.Information); 57 58 IoCompleteRequest(Irp, IO_NO_INCREMENT); 59 60 if (top_level) 61 IoSetTopLevelIrp(NULL); 62 63 TRACE("returning %08lx\n", Status); 64 65 return Status; 66 } 67 68 NTSTATUS do_write_job(device_extension* Vcb, PIRP Irp) { 69 bool top_level = is_top_level(Irp); 70 NTSTATUS Status; 71 72 _SEH2_TRY { 73 Status = write_file(Vcb, Irp, true, true); 74 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 75 Status = _SEH2_GetExceptionCode(); 76 } _SEH2_END; 77 78 if (!NT_SUCCESS(Status)) 79 ERR("write_file returned %08lx\n", Status); 80 81 Irp->IoStatus.Status = Status; 82 83 TRACE("wrote %Iu bytes\n", Irp->IoStatus.Information); 84 85 IoCompleteRequest(Irp, IO_NO_INCREMENT); 86 87 if (top_level) 88 IoSetTopLevelIrp(NULL); 89 90 TRACE("returning %08lx\n", Status); 91 92 return Status; 93 } 94 95 _Function_class_(WORKER_THREAD_ROUTINE) 96 static void __stdcall do_job(void* context) { 97 job_info* ji = context; 98 PIO_STACK_LOCATION IrpSp = ji->Irp ? IoGetCurrentIrpStackLocation(ji->Irp) : NULL; 99 100 if (IrpSp->MajorFunction == IRP_MJ_READ) { 101 do_read_job(ji->Irp); 102 } else if (IrpSp->MajorFunction == IRP_MJ_WRITE) { 103 do_write_job(ji->Vcb, ji->Irp); 104 } 105 106 ExFreePool(ji); 107 } 108 109 bool add_thread_job(device_extension* Vcb, PIRP Irp) { 110 job_info* ji; 111 112 ji = ExAllocatePoolWithTag(NonPagedPool, sizeof(job_info), ALLOC_TAG); 113 if (!ji) { 114 ERR("out of memory\n"); 115 return false; 116 } 117 118 ji->Vcb = Vcb; 119 ji->Irp = Irp; 120 121 if (!Irp->MdlAddress) { 122 PMDL Mdl; 123 LOCK_OPERATION op; 124 ULONG len; 125 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 126 127 if (IrpSp->MajorFunction == IRP_MJ_READ) { 128 op = IoWriteAccess; 129 len = IrpSp->Parameters.Read.Length; 130 } else if (IrpSp->MajorFunction == IRP_MJ_WRITE) { 131 op = IoReadAccess; 132 len = IrpSp->Parameters.Write.Length; 133 } else { 134 ERR("unexpected major function %u\n", IrpSp->MajorFunction); 135 ExFreePool(ji); 136 return false; 137 } 138 139 Mdl = IoAllocateMdl(Irp->UserBuffer, len, false, false, Irp); 140 141 if (!Mdl) { 142 ERR("out of memory\n"); 143 ExFreePool(ji); 144 return false; 145 } 146 147 _SEH2_TRY { 148 MmProbeAndLockPages(Mdl, Irp->RequestorMode, op); 149 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 150 ERR("MmProbeAndLockPages raised status %08lx\n", _SEH2_GetExceptionCode()); 151 152 IoFreeMdl(Mdl); 153 Irp->MdlAddress = NULL; 154 ExFreePool(ji); 155 156 _SEH2_YIELD(return FALSE); 157 } _SEH2_END; 158 } 159 160 ExInitializeWorkItem(&ji->item, do_job, ji); 161 ExQueueWorkItem(&ji->item, DelayedWorkQueue); 162 163 return true; 164 } 165