mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
318da0c18c
CORE-16354
137 lines
3.8 KiB
C
137 lines
3.8 KiB
C
/* Copyright (c) Mark Harmstone 2016-17
|
|
*
|
|
* This file is part of WinBtrfs.
|
|
*
|
|
* WinBtrfs is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public Licence as published by
|
|
* the Free Software Foundation, either version 3 of the Licence, or
|
|
* (at your option) any later version.
|
|
*
|
|
* WinBtrfs is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public Licence for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public Licence
|
|
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include "btrfs_drv.h"
|
|
|
|
#define SECTOR_BLOCK 16
|
|
|
|
NTSTATUS add_calc_job(device_extension* Vcb, uint8_t* data, uint32_t sectors, uint32_t* csum, calc_job** pcj) {
|
|
calc_job* cj;
|
|
|
|
cj = ExAllocatePoolWithTag(NonPagedPool, sizeof(calc_job), ALLOC_TAG);
|
|
if (!cj) {
|
|
ERR("out of memory\n");
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
cj->data = data;
|
|
cj->sectors = sectors;
|
|
cj->csum = csum;
|
|
cj->pos = 0;
|
|
cj->done = 0;
|
|
cj->refcount = 1;
|
|
KeInitializeEvent(&cj->event, NotificationEvent, false);
|
|
|
|
ExAcquireResourceExclusiveLite(&Vcb->calcthreads.lock, true);
|
|
|
|
InsertTailList(&Vcb->calcthreads.job_list, &cj->list_entry);
|
|
|
|
KeSetEvent(&Vcb->calcthreads.event, 0, false);
|
|
KeClearEvent(&Vcb->calcthreads.event);
|
|
|
|
ExReleaseResourceLite(&Vcb->calcthreads.lock);
|
|
|
|
*pcj = cj;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
void free_calc_job(calc_job* cj) {
|
|
LONG rc = InterlockedDecrement(&cj->refcount);
|
|
|
|
if (rc == 0)
|
|
ExFreePool(cj);
|
|
}
|
|
|
|
static bool do_calc(device_extension* Vcb, calc_job* cj) {
|
|
LONG pos, done;
|
|
uint32_t* csum;
|
|
uint8_t* data;
|
|
ULONG blocksize, i;
|
|
|
|
pos = InterlockedIncrement(&cj->pos) - 1;
|
|
|
|
if ((uint32_t)pos * SECTOR_BLOCK >= cj->sectors)
|
|
return false;
|
|
|
|
csum = &cj->csum[pos * SECTOR_BLOCK];
|
|
data = cj->data + (pos * SECTOR_BLOCK * Vcb->superblock.sector_size);
|
|
|
|
blocksize = min(SECTOR_BLOCK, cj->sectors - (pos * SECTOR_BLOCK));
|
|
for (i = 0; i < blocksize; i++) {
|
|
*csum = ~calc_crc32c(0xffffffff, data, Vcb->superblock.sector_size);
|
|
csum++;
|
|
data += Vcb->superblock.sector_size;
|
|
}
|
|
|
|
done = InterlockedIncrement(&cj->done);
|
|
|
|
if ((uint32_t)done * SECTOR_BLOCK >= cj->sectors) {
|
|
ExAcquireResourceExclusiveLite(&Vcb->calcthreads.lock, true);
|
|
RemoveEntryList(&cj->list_entry);
|
|
ExReleaseResourceLite(&Vcb->calcthreads.lock);
|
|
|
|
KeSetEvent(&cj->event, 0, false);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
_Function_class_(KSTART_ROUTINE)
|
|
void __stdcall calc_thread(void* context) {
|
|
drv_calc_thread* thread = context;
|
|
device_extension* Vcb = thread->DeviceObject->DeviceExtension;
|
|
|
|
ObReferenceObject(thread->DeviceObject);
|
|
|
|
while (true) {
|
|
KeWaitForSingleObject(&Vcb->calcthreads.event, Executive, KernelMode, false, NULL);
|
|
|
|
while (true) {
|
|
calc_job* cj;
|
|
bool b;
|
|
|
|
ExAcquireResourceExclusiveLite(&Vcb->calcthreads.lock, true);
|
|
|
|
if (IsListEmpty(&Vcb->calcthreads.job_list)) {
|
|
ExReleaseResourceLite(&Vcb->calcthreads.lock);
|
|
break;
|
|
}
|
|
|
|
cj = CONTAINING_RECORD(Vcb->calcthreads.job_list.Flink, calc_job, list_entry);
|
|
cj->refcount++;
|
|
|
|
ExReleaseResourceLite(&Vcb->calcthreads.lock);
|
|
|
|
b = do_calc(Vcb, cj);
|
|
|
|
free_calc_job(cj);
|
|
|
|
if (!b)
|
|
break;
|
|
}
|
|
|
|
if (thread->quit)
|
|
break;
|
|
}
|
|
|
|
ObDereferenceObject(thread->DeviceObject);
|
|
|
|
KeSetEvent(&thread->finished, 0, false);
|
|
|
|
PsTerminateSystemThread(STATUS_SUCCESS);
|
|
}
|