1 /* Copyright (c) Mark Harmstone 2016-17 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 #define SECTOR_BLOCK 16 21 22 NTSTATUS add_calc_job(device_extension* Vcb, UINT8* data, UINT32 sectors, UINT32* csum, calc_job** pcj) { 23 calc_job* cj; 24 25 cj = ExAllocatePoolWithTag(NonPagedPool, sizeof(calc_job), ALLOC_TAG); 26 if (!cj) { 27 ERR("out of memory\n"); 28 return STATUS_INSUFFICIENT_RESOURCES; 29 } 30 31 cj->data = data; 32 cj->sectors = sectors; 33 cj->csum = csum; 34 cj->pos = 0; 35 cj->done = 0; 36 cj->refcount = 1; 37 KeInitializeEvent(&cj->event, NotificationEvent, FALSE); 38 39 ExAcquireResourceExclusiveLite(&Vcb->calcthreads.lock, TRUE); 40 InsertTailList(&Vcb->calcthreads.job_list, &cj->list_entry); 41 ExReleaseResourceLite(&Vcb->calcthreads.lock); 42 43 KeSetEvent(&Vcb->calcthreads.event, 0, FALSE); 44 KeClearEvent(&Vcb->calcthreads.event); 45 46 *pcj = cj; 47 48 return STATUS_SUCCESS; 49 } 50 51 void free_calc_job(calc_job* cj) { 52 LONG rc = InterlockedDecrement(&cj->refcount); 53 54 if (rc == 0) 55 ExFreePool(cj); 56 } 57 58 static BOOL do_calc(device_extension* Vcb, calc_job* cj) { 59 LONG pos, done; 60 UINT32* csum; 61 UINT8* data; 62 ULONG blocksize, i; 63 64 pos = InterlockedIncrement(&cj->pos) - 1; 65 66 if ((UINT32)pos * SECTOR_BLOCK >= cj->sectors) 67 return FALSE; 68 69 csum = &cj->csum[pos * SECTOR_BLOCK]; 70 data = cj->data + (pos * SECTOR_BLOCK * Vcb->superblock.sector_size); 71 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); 75 csum++; 76 data += Vcb->superblock.sector_size; 77 } 78 79 done = InterlockedIncrement(&cj->done); 80 81 if ((UINT32)done * SECTOR_BLOCK >= cj->sectors) { 82 ExAcquireResourceExclusiveLite(&Vcb->calcthreads.lock, TRUE); 83 RemoveEntryList(&cj->list_entry); 84 ExReleaseResourceLite(&Vcb->calcthreads.lock); 85 86 KeSetEvent(&cj->event, 0, FALSE); 87 } 88 89 return TRUE; 90 } 91 92 _Function_class_(KSTART_ROUTINE) 93 #ifdef __REACTOS__ 94 void NTAPI calc_thread(void* context) { 95 #else 96 void calc_thread(void* context) { 97 #endif 98 drv_calc_thread* thread = context; 99 device_extension* Vcb = thread->DeviceObject->DeviceExtension; 100 101 ObReferenceObject(thread->DeviceObject); 102 103 while (TRUE) { 104 KeWaitForSingleObject(&Vcb->calcthreads.event, Executive, KernelMode, FALSE, NULL); 105 106 while (TRUE) { 107 calc_job* cj; 108 BOOL b; 109 110 ExAcquireResourceExclusiveLite(&Vcb->calcthreads.lock, TRUE); 111 112 if (IsListEmpty(&Vcb->calcthreads.job_list)) { 113 ExReleaseResourceLite(&Vcb->calcthreads.lock); 114 break; 115 } 116 117 cj = CONTAINING_RECORD(Vcb->calcthreads.job_list.Flink, calc_job, list_entry); 118 cj->refcount++; 119 120 ExReleaseResourceLite(&Vcb->calcthreads.lock); 121 122 b = do_calc(Vcb, cj); 123 124 free_calc_job(cj); 125 126 if (!b) 127 break; 128 } 129 130 if (thread->quit) 131 break; 132 } 133 134 ObDereferenceObject(thread->DeviceObject); 135 136 KeSetEvent(&thread->finished, 0, FALSE); 137 138 PsTerminateSystemThread(STATUS_SUCCESS); 139 } 140