2895fb4ba05b8f74e98bff33df62af093c58cefa
[reactos.git] / reactos / drivers / filesystems / btrfs / worker-thread.c
1 /* Copyright (c) Mark Harmstone 2016
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 void do_read_job(PIRP Irp) {
21 NTSTATUS Status;
22 ULONG bytes_read;
23 BOOL top_level = is_top_level(Irp);
24
25 Irp->IoStatus.Information = 0;
26
27 Status = do_read(Irp, TRUE, &bytes_read);
28
29 Irp->IoStatus.Status = Status;
30
31 // // fastfat doesn't do this, but the Wine ntdll file test seems to think we ought to
32 // if (Irp->UserIosb)
33 // *Irp->UserIosb = Irp->IoStatus;
34
35 TRACE("Irp->IoStatus.Status = %08x\n", Irp->IoStatus.Status);
36 TRACE("Irp->IoStatus.Information = %lu\n", Irp->IoStatus.Information);
37 TRACE("returning %08x\n", Status);
38
39 IoCompleteRequest(Irp, IO_NO_INCREMENT);
40
41 if (top_level)
42 IoSetTopLevelIrp(NULL);
43 }
44
45 void do_write_job(device_extension* Vcb, PIRP Irp) {
46 BOOL top_level = is_top_level(Irp);
47 NTSTATUS Status;
48
49 _SEH2_TRY {
50 Status = write_file(Vcb, Irp, TRUE, TRUE);
51 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
52 Status = _SEH2_GetExceptionCode();
53 } _SEH2_END;
54
55 Irp->IoStatus.Status = Status;
56
57 TRACE("wrote %u bytes\n", Irp->IoStatus.Information);
58
59 IoCompleteRequest(Irp, IO_NO_INCREMENT);
60
61 if (top_level)
62 IoSetTopLevelIrp(NULL);
63
64 TRACE("returning %08x\n", Status);
65 }
66
67 static void do_job(drv_thread* thread, LIST_ENTRY* le) {
68 thread_job* tj = CONTAINING_RECORD(le, thread_job, list_entry);
69 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(tj->Irp);
70
71 if (IrpSp->MajorFunction == IRP_MJ_READ) {
72 do_read_job(tj->Irp);
73 } else if (IrpSp->MajorFunction == IRP_MJ_WRITE) {
74 do_write_job(thread->DeviceObject->DeviceExtension, tj->Irp);
75 } else {
76 ERR("unsupported major function %x\n", IrpSp->MajorFunction);
77 tj->Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
78 tj->Irp->IoStatus.Information = 0;
79 IoCompleteRequest(tj->Irp, IO_NO_INCREMENT);
80 }
81
82 ExFreePool(tj);
83 }
84
85 void STDCALL worker_thread(void* context) {
86 drv_thread* thread = context;
87 KIRQL irql;
88
89 ObReferenceObject(thread->DeviceObject);
90
91 while (TRUE) {
92 KeWaitForSingleObject(&thread->event, Executive, KernelMode, FALSE, NULL);
93
94 FsRtlEnterFileSystem();
95
96 while (TRUE) {
97 LIST_ENTRY* le;
98 device_extension* Vcb = thread->DeviceObject->DeviceExtension;
99
100 KeAcquireSpinLock(&thread->spin_lock, &irql);
101
102 if (IsListEmpty(&thread->jobs)) {
103 KeReleaseSpinLock(&thread->spin_lock, irql);
104 break;
105 }
106
107 le = thread->jobs.Flink;
108 RemoveEntryList(le);
109
110 KeReleaseSpinLock(&thread->spin_lock, irql);
111
112 InterlockedDecrement(&Vcb->threads.pending_jobs);
113 do_job(thread, le);
114 }
115
116 FsRtlExitFileSystem();
117
118 if (thread->quit)
119 break;
120 }
121
122 ObDereferenceObject(thread->DeviceObject);
123
124 KeSetEvent(&thread->finished, 0, FALSE);
125
126 PsTerminateSystemThread(STATUS_SUCCESS);
127 }