2b6da81743db5c7c351e4641e574b8d99b5f1e76
[reactos.git] / drivers / filesystems / btrfs / calcthread.c
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 }