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 void 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 fcb_lock = FALSE;
34 
35     Irp->IoStatus.Information = 0;
36 
37     if (!ExIsResourceAcquiredSharedLite(fcb->Header.Resource)) {
38         ExAcquireResourceSharedLite(fcb->Header.Resource, TRUE);
39         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 (fcb_lock)
49         ExReleaseResourceLite(fcb->Header.Resource);
50 
51     if (!NT_SUCCESS(Status))
52         ERR("do_read returned %08x\n", Status);
53 
54     Irp->IoStatus.Status = Status;
55 
56     TRACE("read %lu bytes\n", Irp->IoStatus.Information);
57 
58     IoCompleteRequest(Irp, IO_NO_INCREMENT);
59 
60     if (top_level)
61         IoSetTopLevelIrp(NULL);
62 
63     TRACE("returning %08x\n", Status);
64 }
65 
66 void do_write_job(device_extension* Vcb, PIRP Irp) {
67     BOOL top_level = is_top_level(Irp);
68     NTSTATUS Status;
69 
70     _SEH2_TRY {
71         Status = write_file(Vcb, Irp, TRUE, TRUE);
72     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
73         Status = _SEH2_GetExceptionCode();
74     } _SEH2_END;
75 
76     if (!NT_SUCCESS(Status))
77         ERR("write_file returned %08x\n", Status);
78 
79     Irp->IoStatus.Status = Status;
80 
81     TRACE("wrote %u bytes\n", Irp->IoStatus.Information);
82 
83     IoCompleteRequest(Irp, IO_NO_INCREMENT);
84 
85     if (top_level)
86         IoSetTopLevelIrp(NULL);
87 
88     TRACE("returning %08x\n", Status);
89 }
90 
91 _Function_class_(WORKER_THREAD_ROUTINE)
92 #ifdef __REACTOS__
93 static void NTAPI do_job(void* context) {
94 #else
95 static void do_job(void* context) {
96 #endif
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 %08x\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