1*c2c66affSColin Finck /* Copyright (c) Mark Harmstone 2016-17
2*c2c66affSColin Finck  *
3*c2c66affSColin Finck  * This file is part of WinBtrfs.
4*c2c66affSColin Finck  *
5*c2c66affSColin Finck  * WinBtrfs is free software: you can redistribute it and/or modify
6*c2c66affSColin Finck  * it under the terms of the GNU Lesser General Public Licence as published by
7*c2c66affSColin Finck  * the Free Software Foundation, either version 3 of the Licence, or
8*c2c66affSColin Finck  * (at your option) any later version.
9*c2c66affSColin Finck  *
10*c2c66affSColin Finck  * WinBtrfs is distributed in the hope that it will be useful,
11*c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*c2c66affSColin Finck  * GNU Lesser General Public Licence for more details.
14*c2c66affSColin Finck  *
15*c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public Licence
16*c2c66affSColin Finck  * along with WinBtrfs.  If not, see <http://www.gnu.org/licenses/>. */
17*c2c66affSColin Finck 
18*c2c66affSColin Finck #include "btrfs_drv.h"
19*c2c66affSColin Finck 
20*c2c66affSColin Finck #define SECTOR_BLOCK 16
21*c2c66affSColin Finck 
22*c2c66affSColin Finck NTSTATUS add_calc_job(device_extension* Vcb, UINT8* data, UINT32 sectors, UINT32* csum, calc_job** pcj) {
23*c2c66affSColin Finck     calc_job* cj;
24*c2c66affSColin Finck 
25*c2c66affSColin Finck     cj = ExAllocatePoolWithTag(NonPagedPool, sizeof(calc_job), ALLOC_TAG);
26*c2c66affSColin Finck     if (!cj) {
27*c2c66affSColin Finck         ERR("out of memory\n");
28*c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
29*c2c66affSColin Finck     }
30*c2c66affSColin Finck 
31*c2c66affSColin Finck     cj->data = data;
32*c2c66affSColin Finck     cj->sectors = sectors;
33*c2c66affSColin Finck     cj->csum = csum;
34*c2c66affSColin Finck     cj->pos = 0;
35*c2c66affSColin Finck     cj->done = 0;
36*c2c66affSColin Finck     cj->refcount = 1;
37*c2c66affSColin Finck     KeInitializeEvent(&cj->event, NotificationEvent, FALSE);
38*c2c66affSColin Finck 
39*c2c66affSColin Finck     ExAcquireResourceExclusiveLite(&Vcb->calcthreads.lock, TRUE);
40*c2c66affSColin Finck     InsertTailList(&Vcb->calcthreads.job_list, &cj->list_entry);
41*c2c66affSColin Finck     ExReleaseResourceLite(&Vcb->calcthreads.lock);
42*c2c66affSColin Finck 
43*c2c66affSColin Finck     KeSetEvent(&Vcb->calcthreads.event, 0, FALSE);
44*c2c66affSColin Finck     KeClearEvent(&Vcb->calcthreads.event);
45*c2c66affSColin Finck 
46*c2c66affSColin Finck     *pcj = cj;
47*c2c66affSColin Finck 
48*c2c66affSColin Finck     return STATUS_SUCCESS;
49*c2c66affSColin Finck }
50*c2c66affSColin Finck 
51*c2c66affSColin Finck void free_calc_job(calc_job* cj) {
52*c2c66affSColin Finck     LONG rc = InterlockedDecrement(&cj->refcount);
53*c2c66affSColin Finck 
54*c2c66affSColin Finck     if (rc == 0)
55*c2c66affSColin Finck         ExFreePool(cj);
56*c2c66affSColin Finck }
57*c2c66affSColin Finck 
58*c2c66affSColin Finck static BOOL do_calc(device_extension* Vcb, calc_job* cj) {
59*c2c66affSColin Finck     LONG pos, done;
60*c2c66affSColin Finck     UINT32* csum;
61*c2c66affSColin Finck     UINT8* data;
62*c2c66affSColin Finck     ULONG blocksize, i;
63*c2c66affSColin Finck 
64*c2c66affSColin Finck     pos = InterlockedIncrement(&cj->pos) - 1;
65*c2c66affSColin Finck 
66*c2c66affSColin Finck     if ((UINT32)pos * SECTOR_BLOCK >= cj->sectors)
67*c2c66affSColin Finck         return FALSE;
68*c2c66affSColin Finck 
69*c2c66affSColin Finck     csum = &cj->csum[pos * SECTOR_BLOCK];
70*c2c66affSColin Finck     data = cj->data + (pos * SECTOR_BLOCK * Vcb->superblock.sector_size);
71*c2c66affSColin Finck 
72*c2c66affSColin Finck     blocksize = min(SECTOR_BLOCK, cj->sectors - (pos * SECTOR_BLOCK));
73*c2c66affSColin Finck     for (i = 0; i < blocksize; i++) {
74*c2c66affSColin Finck         *csum = ~calc_crc32c(0xffffffff, data, Vcb->superblock.sector_size);
75*c2c66affSColin Finck         csum++;
76*c2c66affSColin Finck         data += Vcb->superblock.sector_size;
77*c2c66affSColin Finck     }
78*c2c66affSColin Finck 
79*c2c66affSColin Finck     done = InterlockedIncrement(&cj->done);
80*c2c66affSColin Finck 
81*c2c66affSColin Finck     if ((UINT32)done * SECTOR_BLOCK >= cj->sectors) {
82*c2c66affSColin Finck         ExAcquireResourceExclusiveLite(&Vcb->calcthreads.lock, TRUE);
83*c2c66affSColin Finck         RemoveEntryList(&cj->list_entry);
84*c2c66affSColin Finck         ExReleaseResourceLite(&Vcb->calcthreads.lock);
85*c2c66affSColin Finck 
86*c2c66affSColin Finck         KeSetEvent(&cj->event, 0, FALSE);
87*c2c66affSColin Finck     }
88*c2c66affSColin Finck 
89*c2c66affSColin Finck     return TRUE;
90*c2c66affSColin Finck }
91*c2c66affSColin Finck 
92*c2c66affSColin Finck _Function_class_(KSTART_ROUTINE)
93*c2c66affSColin Finck #ifdef __REACTOS__
94*c2c66affSColin Finck void NTAPI calc_thread(void* context) {
95*c2c66affSColin Finck #else
96*c2c66affSColin Finck void calc_thread(void* context) {
97*c2c66affSColin Finck #endif
98*c2c66affSColin Finck     drv_calc_thread* thread = context;
99*c2c66affSColin Finck     device_extension* Vcb = thread->DeviceObject->DeviceExtension;
100*c2c66affSColin Finck 
101*c2c66affSColin Finck     ObReferenceObject(thread->DeviceObject);
102*c2c66affSColin Finck 
103*c2c66affSColin Finck     while (TRUE) {
104*c2c66affSColin Finck         KeWaitForSingleObject(&Vcb->calcthreads.event, Executive, KernelMode, FALSE, NULL);
105*c2c66affSColin Finck 
106*c2c66affSColin Finck         while (TRUE) {
107*c2c66affSColin Finck             calc_job* cj;
108*c2c66affSColin Finck             BOOL b;
109*c2c66affSColin Finck 
110*c2c66affSColin Finck             ExAcquireResourceExclusiveLite(&Vcb->calcthreads.lock, TRUE);
111*c2c66affSColin Finck 
112*c2c66affSColin Finck             if (IsListEmpty(&Vcb->calcthreads.job_list)) {
113*c2c66affSColin Finck                 ExReleaseResourceLite(&Vcb->calcthreads.lock);
114*c2c66affSColin Finck                 break;
115*c2c66affSColin Finck             }
116*c2c66affSColin Finck 
117*c2c66affSColin Finck             cj = CONTAINING_RECORD(Vcb->calcthreads.job_list.Flink, calc_job, list_entry);
118*c2c66affSColin Finck             cj->refcount++;
119*c2c66affSColin Finck 
120*c2c66affSColin Finck             ExReleaseResourceLite(&Vcb->calcthreads.lock);
121*c2c66affSColin Finck 
122*c2c66affSColin Finck             b = do_calc(Vcb, cj);
123*c2c66affSColin Finck 
124*c2c66affSColin Finck             free_calc_job(cj);
125*c2c66affSColin Finck 
126*c2c66affSColin Finck             if (!b)
127*c2c66affSColin Finck                 break;
128*c2c66affSColin Finck         }
129*c2c66affSColin Finck 
130*c2c66affSColin Finck         if (thread->quit)
131*c2c66affSColin Finck             break;
132*c2c66affSColin Finck     }
133*c2c66affSColin Finck 
134*c2c66affSColin Finck     ObDereferenceObject(thread->DeviceObject);
135*c2c66affSColin Finck 
136*c2c66affSColin Finck     KeSetEvent(&thread->finished, 0, FALSE);
137*c2c66affSColin Finck 
138*c2c66affSColin Finck     PsTerminateSystemThread(STATUS_SUCCESS);
139*c2c66affSColin Finck }
140