1 /* Copyright (c) Mark Harmstone 2016-17
3 * This file is part of WinBtrfs.
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.
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.
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/>. */
18 #include "btrfs_drv.h"
22 void calc_thread_main(device_extension
* Vcb
, calc_job
* cj
) {
28 bool last_one
= false;
30 KeAcquireSpinLock(&Vcb
->calcthreads
.spinlock
, &irql
);
32 if (cj
&& cj
->not_started
== 0) {
33 KeReleaseSpinLock(&Vcb
->calcthreads
.spinlock
, irql
);
40 if (IsListEmpty(&Vcb
->calcthreads
.job_list
)) {
41 KeReleaseSpinLock(&Vcb
->calcthreads
.spinlock
, irql
);
45 cj2
= CONTAINING_RECORD(Vcb
->calcthreads
.job_list
.Flink
, calc_job
, list_entry
);
52 case calc_thread_crc32c
:
53 case calc_thread_xxhash
:
54 case calc_thread_sha256
:
55 case calc_thread_blake2
:
56 cj2
->in
= (uint8_t*)cj2
->in
+ Vcb
->superblock
.sector_size
;
57 cj2
->out
= (uint8_t*)cj2
->out
+ Vcb
->csum_size
;
66 if (cj2
->not_started
== 0) {
67 RemoveEntryList(&cj2
->list_entry
);
71 KeReleaseSpinLock(&Vcb
->calcthreads
.spinlock
, irql
);
74 case calc_thread_crc32c
:
75 *(uint32_t*)dest
= ~calc_crc32c(0xffffffff, src
, Vcb
->superblock
.sector_size
);
78 case calc_thread_xxhash
:
79 *(uint64_t*)dest
= XXH64(src
, Vcb
->superblock
.sector_size
, 0);
82 case calc_thread_sha256
:
83 calc_sha256(dest
, src
, Vcb
->superblock
.sector_size
);
86 case calc_thread_blake2
:
87 blake2b(dest
, BLAKE2_HASH_SIZE
, src
, Vcb
->superblock
.sector_size
);
90 case calc_thread_decomp_zlib
:
91 cj2
->Status
= zlib_decompress(src
, cj2
->inlen
, dest
, cj2
->outlen
);
93 if (!NT_SUCCESS(cj2
->Status
))
94 ERR("zlib_decompress returned %08lx\n", cj2
->Status
);
97 case calc_thread_decomp_lzo
:
98 cj2
->Status
= lzo_decompress(src
, cj2
->inlen
, dest
, cj2
->outlen
, cj2
->off
);
100 if (!NT_SUCCESS(cj2
->Status
))
101 ERR("lzo_decompress returned %08lx\n", cj2
->Status
);
104 case calc_thread_decomp_zstd
:
105 cj2
->Status
= zstd_decompress(src
, cj2
->inlen
, dest
, cj2
->outlen
);
107 if (!NT_SUCCESS(cj2
->Status
))
108 ERR("zstd_decompress returned %08lx\n", cj2
->Status
);
111 case calc_thread_comp_zlib
:
112 cj2
->Status
= zlib_compress(src
, cj2
->inlen
, dest
, cj2
->outlen
, Vcb
->options
.zlib_level
, &cj2
->space_left
);
114 if (!NT_SUCCESS(cj2
->Status
))
115 ERR("zlib_compress returned %08lx\n", cj2
->Status
);
118 case calc_thread_comp_lzo
:
119 cj2
->Status
= lzo_compress(src
, cj2
->inlen
, dest
, cj2
->outlen
, &cj2
->space_left
);
121 if (!NT_SUCCESS(cj2
->Status
))
122 ERR("lzo_compress returned %08lx\n", cj2
->Status
);
125 case calc_thread_comp_zstd
:
126 cj2
->Status
= zstd_compress(src
, cj2
->inlen
, dest
, cj2
->outlen
, Vcb
->options
.zstd_level
, &cj2
->space_left
);
128 if (!NT_SUCCESS(cj2
->Status
))
129 ERR("zstd_compress returned %08lx\n", cj2
->Status
);
133 if (InterlockedDecrement(&cj2
->left
) == 0)
134 KeSetEvent(&cj2
->event
, 0, false);
141 void do_calc_job(device_extension
* Vcb
, uint8_t* data
, uint32_t sectors
, void* csum
) {
147 cj
.left
= cj
.not_started
= sectors
;
149 switch (Vcb
->superblock
.csum_type
) {
150 case CSUM_TYPE_CRC32C
:
151 cj
.type
= calc_thread_crc32c
;
154 case CSUM_TYPE_XXHASH
:
155 cj
.type
= calc_thread_xxhash
;
158 case CSUM_TYPE_SHA256
:
159 cj
.type
= calc_thread_sha256
;
162 case CSUM_TYPE_BLAKE2
:
163 cj
.type
= calc_thread_blake2
;
167 KeInitializeEvent(&cj
.event
, NotificationEvent
, false);
169 KeAcquireSpinLock(&Vcb
->calcthreads
.spinlock
, &irql
);
171 InsertTailList(&Vcb
->calcthreads
.job_list
, &cj
.list_entry
);
173 KeSetEvent(&Vcb
->calcthreads
.event
, 0, false);
174 KeClearEvent(&Vcb
->calcthreads
.event
);
176 KeReleaseSpinLock(&Vcb
->calcthreads
.spinlock
, irql
);
178 calc_thread_main(Vcb
, &cj
);
180 KeWaitForSingleObject(&cj
.event
, Executive
, KernelMode
, false, NULL
);
183 NTSTATUS
add_calc_job_decomp(device_extension
* Vcb
, uint8_t compression
, void* in
, unsigned int inlen
,
184 void* out
, unsigned int outlen
, unsigned int off
, calc_job
** pcj
) {
188 cj
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(calc_job
), ALLOC_TAG
);
190 ERR("out of memory\n");
191 return STATUS_INSUFFICIENT_RESOURCES
;
199 cj
->left
= cj
->not_started
= 1;
200 cj
->Status
= STATUS_SUCCESS
;
202 switch (compression
) {
203 case BTRFS_COMPRESSION_ZLIB
:
204 cj
->type
= calc_thread_decomp_zlib
;
207 case BTRFS_COMPRESSION_LZO
:
208 cj
->type
= calc_thread_decomp_lzo
;
211 case BTRFS_COMPRESSION_ZSTD
:
212 cj
->type
= calc_thread_decomp_zstd
;
216 ERR("unexpected compression type %x\n", compression
);
218 return STATUS_NOT_SUPPORTED
;
221 KeInitializeEvent(&cj
->event
, NotificationEvent
, false);
223 KeAcquireSpinLock(&Vcb
->calcthreads
.spinlock
, &irql
);
225 InsertTailList(&Vcb
->calcthreads
.job_list
, &cj
->list_entry
);
227 KeSetEvent(&Vcb
->calcthreads
.event
, 0, false);
228 KeClearEvent(&Vcb
->calcthreads
.event
);
230 KeReleaseSpinLock(&Vcb
->calcthreads
.spinlock
, irql
);
234 return STATUS_SUCCESS
;
237 NTSTATUS
add_calc_job_comp(device_extension
* Vcb
, uint8_t compression
, void* in
, unsigned int inlen
,
238 void* out
, unsigned int outlen
, calc_job
** pcj
) {
242 cj
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(calc_job
), ALLOC_TAG
);
244 ERR("out of memory\n");
245 return STATUS_INSUFFICIENT_RESOURCES
;
252 cj
->left
= cj
->not_started
= 1;
253 cj
->Status
= STATUS_SUCCESS
;
255 switch (compression
) {
256 case BTRFS_COMPRESSION_ZLIB
:
257 cj
->type
= calc_thread_comp_zlib
;
260 case BTRFS_COMPRESSION_LZO
:
261 cj
->type
= calc_thread_comp_lzo
;
264 case BTRFS_COMPRESSION_ZSTD
:
265 cj
->type
= calc_thread_comp_zstd
;
269 ERR("unexpected compression type %x\n", compression
);
271 return STATUS_NOT_SUPPORTED
;
274 KeInitializeEvent(&cj
->event
, NotificationEvent
, false);
276 KeAcquireSpinLock(&Vcb
->calcthreads
.spinlock
, &irql
);
278 InsertTailList(&Vcb
->calcthreads
.job_list
, &cj
->list_entry
);
280 KeSetEvent(&Vcb
->calcthreads
.event
, 0, false);
281 KeClearEvent(&Vcb
->calcthreads
.event
);
283 KeReleaseSpinLock(&Vcb
->calcthreads
.spinlock
, irql
);
287 return STATUS_SUCCESS
;
290 _Function_class_(KSTART_ROUTINE
)
291 void __stdcall
calc_thread(void* context
) {
292 drv_calc_thread
* thread
= context
;
293 device_extension
* Vcb
= thread
->DeviceObject
->DeviceExtension
;
295 ObReferenceObject(thread
->DeviceObject
);
297 KeSetSystemAffinityThread((KAFFINITY
)(1 << thread
->number
));
300 KeWaitForSingleObject(&Vcb
->calcthreads
.event
, Executive
, KernelMode
, false, NULL
);
302 calc_thread_main(Vcb
, NULL
);
308 ObDereferenceObject(thread
->DeviceObject
);
310 KeSetEvent(&thread
->finished
, 0, false);
312 PsTerminateSystemThread(STATUS_SUCCESS
);