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"
20 #define SECTOR_BLOCK 16
22 NTSTATUS
add_calc_job(device_extension
* Vcb
, UINT8
* data
, UINT32 sectors
, UINT32
* csum
, calc_job
** pcj
) {
25 cj
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(calc_job
), ALLOC_TAG
);
27 ERR("out of memory\n");
28 return STATUS_INSUFFICIENT_RESOURCES
;
32 cj
->sectors
= sectors
;
37 KeInitializeEvent(&cj
->event
, NotificationEvent
, FALSE
);
39 ExAcquireResourceExclusiveLite(&Vcb
->calcthreads
.lock
, TRUE
);
40 InsertTailList(&Vcb
->calcthreads
.job_list
, &cj
->list_entry
);
41 ExReleaseResourceLite(&Vcb
->calcthreads
.lock
);
43 KeSetEvent(&Vcb
->calcthreads
.event
, 0, FALSE
);
44 KeClearEvent(&Vcb
->calcthreads
.event
);
48 return STATUS_SUCCESS
;
51 void free_calc_job(calc_job
* cj
) {
52 LONG rc
= InterlockedDecrement(&cj
->refcount
);
58 static BOOL
do_calc(device_extension
* Vcb
, calc_job
* cj
) {
64 pos
= InterlockedIncrement(&cj
->pos
) - 1;
66 if ((UINT32
)pos
* SECTOR_BLOCK
>= cj
->sectors
)
69 csum
= &cj
->csum
[pos
* SECTOR_BLOCK
];
70 data
= cj
->data
+ (pos
* SECTOR_BLOCK
* Vcb
->superblock
.sector_size
);
72 blocksize
= min(SECTOR_BLOCK
, cj
->sectors
- (pos
* SECTOR_BLOCK
));
73 for (i
= 0; i
< blocksize
; i
++) {
74 *csum
= ~calc_crc32c(0xffffffff, data
, Vcb
->superblock
.sector_size
);
76 data
+= Vcb
->superblock
.sector_size
;
79 done
= InterlockedIncrement(&cj
->done
);
81 if ((UINT32
)done
* SECTOR_BLOCK
>= cj
->sectors
) {
82 ExAcquireResourceExclusiveLite(&Vcb
->calcthreads
.lock
, TRUE
);
83 RemoveEntryList(&cj
->list_entry
);
84 ExReleaseResourceLite(&Vcb
->calcthreads
.lock
);
86 KeSetEvent(&cj
->event
, 0, FALSE
);
92 _Function_class_(KSTART_ROUTINE
)
94 void NTAPI
calc_thread(void* context
) {
96 void calc_thread(void* context
) {
98 drv_calc_thread
* thread
= context
;
99 device_extension
* Vcb
= thread
->DeviceObject
->DeviceExtension
;
101 ObReferenceObject(thread
->DeviceObject
);
104 KeWaitForSingleObject(&Vcb
->calcthreads
.event
, Executive
, KernelMode
, FALSE
, NULL
);
110 ExAcquireResourceExclusiveLite(&Vcb
->calcthreads
.lock
, TRUE
);
112 if (IsListEmpty(&Vcb
->calcthreads
.job_list
)) {
113 ExReleaseResourceLite(&Vcb
->calcthreads
.lock
);
117 cj
= CONTAINING_RECORD(Vcb
->calcthreads
.job_list
.Flink
, calc_job
, list_entry
);
120 ExReleaseResourceLite(&Vcb
->calcthreads
.lock
);
122 b
= do_calc(Vcb
, cj
);
134 ObDereferenceObject(thread
->DeviceObject
);
136 KeSetEvent(&thread
->finished
, 0, FALSE
);
138 PsTerminateSystemThread(STATUS_SUCCESS
);