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
);
41 InsertTailList(&Vcb
->calcthreads
.job_list
, &cj
->list_entry
);
43 KeSetEvent(&Vcb
->calcthreads
.event
, 0, FALSE
);
44 KeClearEvent(&Vcb
->calcthreads
.event
);
46 ExReleaseResourceLite(&Vcb
->calcthreads
.lock
);
50 return STATUS_SUCCESS
;
53 void free_calc_job(calc_job
* cj
) {
54 LONG rc
= InterlockedDecrement(&cj
->refcount
);
60 static BOOL
do_calc(device_extension
* Vcb
, calc_job
* cj
) {
66 pos
= InterlockedIncrement(&cj
->pos
) - 1;
68 if ((UINT32
)pos
* SECTOR_BLOCK
>= cj
->sectors
)
71 csum
= &cj
->csum
[pos
* SECTOR_BLOCK
];
72 data
= cj
->data
+ (pos
* SECTOR_BLOCK
* Vcb
->superblock
.sector_size
);
74 blocksize
= min(SECTOR_BLOCK
, cj
->sectors
- (pos
* SECTOR_BLOCK
));
75 for (i
= 0; i
< blocksize
; i
++) {
76 *csum
= ~calc_crc32c(0xffffffff, data
, Vcb
->superblock
.sector_size
);
78 data
+= Vcb
->superblock
.sector_size
;
81 done
= InterlockedIncrement(&cj
->done
);
83 if ((UINT32
)done
* SECTOR_BLOCK
>= cj
->sectors
) {
84 ExAcquireResourceExclusiveLite(&Vcb
->calcthreads
.lock
, TRUE
);
85 RemoveEntryList(&cj
->list_entry
);
86 ExReleaseResourceLite(&Vcb
->calcthreads
.lock
);
88 KeSetEvent(&cj
->event
, 0, FALSE
);
94 _Function_class_(KSTART_ROUTINE
)
96 void NTAPI
calc_thread(void* context
) {
98 void calc_thread(void* context
) {
100 drv_calc_thread
* thread
= context
;
101 device_extension
* Vcb
= thread
->DeviceObject
->DeviceExtension
;
103 ObReferenceObject(thread
->DeviceObject
);
106 KeWaitForSingleObject(&Vcb
->calcthreads
.event
, Executive
, KernelMode
, FALSE
, NULL
);
112 ExAcquireResourceExclusiveLite(&Vcb
->calcthreads
.lock
, TRUE
);
114 if (IsListEmpty(&Vcb
->calcthreads
.job_list
)) {
115 ExReleaseResourceLite(&Vcb
->calcthreads
.lock
);
119 cj
= CONTAINING_RECORD(Vcb
->calcthreads
.job_list
.Flink
, calc_job
, list_entry
);
122 ExReleaseResourceLite(&Vcb
->calcthreads
.lock
);
124 b
= do_calc(Vcb
, cj
);
136 ObDereferenceObject(thread
->DeviceObject
);
138 KeSetEvent(&thread
->finished
, 0, FALSE
);
140 PsTerminateSystemThread(STATUS_SUCCESS
);