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
do_read_job(PIRP Irp)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
do_write_job(device_extension * Vcb,PIRP Irp)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
_Function_class_(WORKER_THREAD_ROUTINE)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
add_thread_job(device_extension * Vcb,PIRP Irp)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