1c2c66affSColin Finck /* Copyright (c) Mark Harmstone 2016-17 2c2c66affSColin Finck * 3c2c66affSColin Finck * This file is part of WinBtrfs. 4c2c66affSColin Finck * 5c2c66affSColin Finck * WinBtrfs is free software: you can redistribute it and/or modify 6c2c66affSColin Finck * it under the terms of the GNU Lesser General Public Licence as published by 7c2c66affSColin Finck * the Free Software Foundation, either version 3 of the Licence, or 8c2c66affSColin Finck * (at your option) any later version. 9c2c66affSColin Finck * 10c2c66affSColin Finck * WinBtrfs is distributed in the hope that it will be useful, 11c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of 12c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13c2c66affSColin Finck * GNU Lesser General Public Licence for more details. 14c2c66affSColin Finck * 15c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public Licence 16c2c66affSColin Finck * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */ 17c2c66affSColin Finck 18c2c66affSColin Finck #include "btrfs_drv.h" 19194ea909SVictor Perevertkin #include "xxhash.h" 20194ea909SVictor Perevertkin #include "crc32c.h" 21c2c66affSColin Finck 22c2c66affSColin Finck enum read_data_status { 23c2c66affSColin Finck ReadDataStatus_Pending, 24c2c66affSColin Finck ReadDataStatus_Success, 25c2c66affSColin Finck ReadDataStatus_Error, 26c2c66affSColin Finck ReadDataStatus_MissingDevice, 27c2c66affSColin Finck ReadDataStatus_Skip 28c2c66affSColin Finck }; 29c2c66affSColin Finck 30c2c66affSColin Finck struct read_data_context; 31c2c66affSColin Finck 32c2c66affSColin Finck typedef struct { 33c2c66affSColin Finck struct read_data_context* context; 34318da0c1SPierre Schweitzer uint16_t stripenum; 35318da0c1SPierre Schweitzer bool rewrite; 36c2c66affSColin Finck PIRP Irp; 37c2c66affSColin Finck IO_STATUS_BLOCK iosb; 38c2c66affSColin Finck enum read_data_status status; 39c2c66affSColin Finck PMDL mdl; 40318da0c1SPierre Schweitzer uint64_t stripestart; 41318da0c1SPierre Schweitzer uint64_t stripeend; 42c2c66affSColin Finck } read_data_stripe; 43c2c66affSColin Finck 44c2c66affSColin Finck typedef struct { 45c2c66affSColin Finck KEVENT Event; 46c2c66affSColin Finck NTSTATUS Status; 47c2c66affSColin Finck chunk* c; 48318da0c1SPierre Schweitzer uint64_t address; 49318da0c1SPierre Schweitzer uint32_t buflen; 50c2c66affSColin Finck LONG num_stripes, stripes_left; 51318da0c1SPierre Schweitzer uint64_t type; 52318da0c1SPierre Schweitzer uint32_t sector_size; 53318da0c1SPierre Schweitzer uint16_t firstoff, startoffstripe, sectors_per_stripe; 54194ea909SVictor Perevertkin void* csum; 55318da0c1SPierre Schweitzer bool tree; 56c2c66affSColin Finck read_data_stripe* stripes; 57318da0c1SPierre Schweitzer uint8_t* va; 58c2c66affSColin Finck } read_data_context; 59c2c66affSColin Finck 60318da0c1SPierre Schweitzer extern bool diskacc; 61c2c66affSColin Finck extern tPsUpdateDiskCounters fPsUpdateDiskCounters; 62c2c66affSColin Finck extern tCcCopyReadEx fCcCopyReadEx; 63c2c66affSColin Finck extern tFsRtlUpdateDiskCounters fFsRtlUpdateDiskCounters; 64c2c66affSColin Finck 65318da0c1SPierre Schweitzer #define LZO_PAGE_SIZE 4096 66c2c66affSColin Finck 67c2c66affSColin Finck _Function_class_(IO_COMPLETION_ROUTINE) 68318da0c1SPierre Schweitzer static NTSTATUS __stdcall read_data_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) { 69c2c66affSColin Finck read_data_stripe* stripe = conptr; 70c2c66affSColin Finck read_data_context* context = (read_data_context*)stripe->context; 71c2c66affSColin Finck 72c2c66affSColin Finck UNUSED(DeviceObject); 73c2c66affSColin Finck 74c2c66affSColin Finck stripe->iosb = Irp->IoStatus; 75c2c66affSColin Finck 76c2c66affSColin Finck if (NT_SUCCESS(Irp->IoStatus.Status)) 77c2c66affSColin Finck stripe->status = ReadDataStatus_Success; 78c2c66affSColin Finck else 79c2c66affSColin Finck stripe->status = ReadDataStatus_Error; 80c2c66affSColin Finck 81c2c66affSColin Finck if (InterlockedDecrement(&context->stripes_left) == 0) 82318da0c1SPierre Schweitzer KeSetEvent(&context->Event, 0, false); 83c2c66affSColin Finck 84c2c66affSColin Finck return STATUS_MORE_PROCESSING_REQUIRED; 85c2c66affSColin Finck } 86c2c66affSColin Finck 87194ea909SVictor Perevertkin NTSTATUS check_csum(device_extension* Vcb, uint8_t* data, uint32_t sectors, void* csum) { 88194ea909SVictor Perevertkin void* csum2; 89c2c66affSColin Finck 90194ea909SVictor Perevertkin csum2 = ExAllocatePoolWithTag(PagedPool, Vcb->csum_size * sectors, ALLOC_TAG); 91c2c66affSColin Finck if (!csum2) { 92c2c66affSColin Finck ERR("out of memory\n"); 93c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 94c2c66affSColin Finck } 95c2c66affSColin Finck 96194ea909SVictor Perevertkin do_calc_job(Vcb, data, sectors, csum2); 97c2c66affSColin Finck 98194ea909SVictor Perevertkin if (RtlCompareMemory(csum2, csum, sectors * Vcb->csum_size) != sectors * Vcb->csum_size) { 99c2c66affSColin Finck ExFreePool(csum2); 100c2c66affSColin Finck return STATUS_CRC_ERROR; 101c2c66affSColin Finck } 102c2c66affSColin Finck 103c2c66affSColin Finck ExFreePool(csum2); 104c2c66affSColin Finck 105c2c66affSColin Finck return STATUS_SUCCESS; 106c2c66affSColin Finck } 107c2c66affSColin Finck 108194ea909SVictor Perevertkin void get_tree_checksum(device_extension* Vcb, tree_header* th, void* csum) { 109194ea909SVictor Perevertkin switch (Vcb->superblock.csum_type) { 110194ea909SVictor Perevertkin case CSUM_TYPE_CRC32C: 111194ea909SVictor Perevertkin *(uint32_t*)csum = ~calc_crc32c(0xffffffff, (uint8_t*)&th->fs_uuid, Vcb->superblock.node_size - sizeof(th->csum)); 112194ea909SVictor Perevertkin break; 113194ea909SVictor Perevertkin 114194ea909SVictor Perevertkin case CSUM_TYPE_XXHASH: 115194ea909SVictor Perevertkin *(uint64_t*)csum = XXH64((uint8_t*)&th->fs_uuid, Vcb->superblock.node_size - sizeof(th->csum), 0); 116194ea909SVictor Perevertkin break; 117194ea909SVictor Perevertkin 118194ea909SVictor Perevertkin case CSUM_TYPE_SHA256: 119194ea909SVictor Perevertkin calc_sha256(csum, &th->fs_uuid, Vcb->superblock.node_size - sizeof(th->csum)); 120194ea909SVictor Perevertkin break; 121194ea909SVictor Perevertkin 122194ea909SVictor Perevertkin case CSUM_TYPE_BLAKE2: 123194ea909SVictor Perevertkin blake2b(csum, BLAKE2_HASH_SIZE, (uint8_t*)&th->fs_uuid, Vcb->superblock.node_size - sizeof(th->csum)); 124194ea909SVictor Perevertkin break; 125194ea909SVictor Perevertkin } 126194ea909SVictor Perevertkin } 127194ea909SVictor Perevertkin 128194ea909SVictor Perevertkin bool check_tree_checksum(device_extension* Vcb, tree_header* th) { 129194ea909SVictor Perevertkin switch (Vcb->superblock.csum_type) { 130194ea909SVictor Perevertkin case CSUM_TYPE_CRC32C: { 131194ea909SVictor Perevertkin uint32_t crc32 = ~calc_crc32c(0xffffffff, (uint8_t*)&th->fs_uuid, Vcb->superblock.node_size - sizeof(th->csum)); 132194ea909SVictor Perevertkin 133194ea909SVictor Perevertkin if (crc32 == *((uint32_t*)th->csum)) 134194ea909SVictor Perevertkin return true; 135194ea909SVictor Perevertkin 136194ea909SVictor Perevertkin WARN("hash was %08x, expected %08x\n", crc32, *((uint32_t*)th->csum)); 137194ea909SVictor Perevertkin 138194ea909SVictor Perevertkin break; 139194ea909SVictor Perevertkin } 140194ea909SVictor Perevertkin 141194ea909SVictor Perevertkin case CSUM_TYPE_XXHASH: { 142194ea909SVictor Perevertkin uint64_t hash = XXH64((uint8_t*)&th->fs_uuid, Vcb->superblock.node_size - sizeof(th->csum), 0); 143194ea909SVictor Perevertkin 144194ea909SVictor Perevertkin if (hash == *((uint64_t*)th->csum)) 145194ea909SVictor Perevertkin return true; 146194ea909SVictor Perevertkin 147194ea909SVictor Perevertkin WARN("hash was %I64x, expected %I64x\n", hash, *((uint64_t*)th->csum)); 148194ea909SVictor Perevertkin 149194ea909SVictor Perevertkin break; 150194ea909SVictor Perevertkin } 151194ea909SVictor Perevertkin 152194ea909SVictor Perevertkin case CSUM_TYPE_SHA256: { 153194ea909SVictor Perevertkin uint8_t hash[SHA256_HASH_SIZE]; 154194ea909SVictor Perevertkin 155194ea909SVictor Perevertkin calc_sha256(hash, (uint8_t*)&th->fs_uuid, Vcb->superblock.node_size - sizeof(th->csum)); 156194ea909SVictor Perevertkin 157194ea909SVictor Perevertkin if (RtlCompareMemory(hash, th, SHA256_HASH_SIZE) == SHA256_HASH_SIZE) 158194ea909SVictor Perevertkin return true; 159194ea909SVictor Perevertkin 160194ea909SVictor Perevertkin WARN("hash was invalid\n"); 161194ea909SVictor Perevertkin 162194ea909SVictor Perevertkin break; 163194ea909SVictor Perevertkin } 164194ea909SVictor Perevertkin 165194ea909SVictor Perevertkin case CSUM_TYPE_BLAKE2: { 166194ea909SVictor Perevertkin uint8_t hash[BLAKE2_HASH_SIZE]; 167194ea909SVictor Perevertkin 168194ea909SVictor Perevertkin blake2b(hash, sizeof(hash), (uint8_t*)&th->fs_uuid, Vcb->superblock.node_size - sizeof(th->csum)); 169194ea909SVictor Perevertkin 170194ea909SVictor Perevertkin if (RtlCompareMemory(hash, th, BLAKE2_HASH_SIZE) == BLAKE2_HASH_SIZE) 171194ea909SVictor Perevertkin return true; 172194ea909SVictor Perevertkin 173194ea909SVictor Perevertkin WARN("hash was invalid\n"); 174194ea909SVictor Perevertkin 175194ea909SVictor Perevertkin break; 176194ea909SVictor Perevertkin } 177194ea909SVictor Perevertkin } 178194ea909SVictor Perevertkin 179194ea909SVictor Perevertkin return false; 180194ea909SVictor Perevertkin } 181194ea909SVictor Perevertkin 182194ea909SVictor Perevertkin void get_sector_csum(device_extension* Vcb, void* buf, void* csum) { 183194ea909SVictor Perevertkin switch (Vcb->superblock.csum_type) { 184194ea909SVictor Perevertkin case CSUM_TYPE_CRC32C: 185194ea909SVictor Perevertkin *(uint32_t*)csum = ~calc_crc32c(0xffffffff, buf, Vcb->superblock.sector_size); 186194ea909SVictor Perevertkin break; 187194ea909SVictor Perevertkin 188194ea909SVictor Perevertkin case CSUM_TYPE_XXHASH: 189194ea909SVictor Perevertkin *(uint64_t*)csum = XXH64(buf, Vcb->superblock.sector_size, 0); 190194ea909SVictor Perevertkin break; 191194ea909SVictor Perevertkin 192194ea909SVictor Perevertkin case CSUM_TYPE_SHA256: 193194ea909SVictor Perevertkin calc_sha256(csum, buf, Vcb->superblock.sector_size); 194194ea909SVictor Perevertkin break; 195194ea909SVictor Perevertkin 196194ea909SVictor Perevertkin case CSUM_TYPE_BLAKE2: 197194ea909SVictor Perevertkin blake2b(csum, BLAKE2_HASH_SIZE, buf, Vcb->superblock.sector_size); 198194ea909SVictor Perevertkin break; 199194ea909SVictor Perevertkin } 200194ea909SVictor Perevertkin } 201194ea909SVictor Perevertkin 202194ea909SVictor Perevertkin bool check_sector_csum(device_extension* Vcb, void* buf, void* csum) { 203194ea909SVictor Perevertkin switch (Vcb->superblock.csum_type) { 204194ea909SVictor Perevertkin case CSUM_TYPE_CRC32C: { 205194ea909SVictor Perevertkin uint32_t crc32 = ~calc_crc32c(0xffffffff, buf, Vcb->superblock.sector_size); 206194ea909SVictor Perevertkin 207194ea909SVictor Perevertkin return *(uint32_t*)csum == crc32; 208194ea909SVictor Perevertkin } 209194ea909SVictor Perevertkin 210194ea909SVictor Perevertkin case CSUM_TYPE_XXHASH: { 211194ea909SVictor Perevertkin uint64_t hash = XXH64(buf, Vcb->superblock.sector_size, 0); 212194ea909SVictor Perevertkin 213194ea909SVictor Perevertkin return *(uint64_t*)csum == hash; 214194ea909SVictor Perevertkin } 215194ea909SVictor Perevertkin 216194ea909SVictor Perevertkin case CSUM_TYPE_SHA256: { 217194ea909SVictor Perevertkin uint8_t hash[SHA256_HASH_SIZE]; 218194ea909SVictor Perevertkin 219194ea909SVictor Perevertkin calc_sha256(hash, buf, Vcb->superblock.sector_size); 220194ea909SVictor Perevertkin 221194ea909SVictor Perevertkin return RtlCompareMemory(hash, csum, SHA256_HASH_SIZE) == SHA256_HASH_SIZE; 222194ea909SVictor Perevertkin } 223194ea909SVictor Perevertkin 224194ea909SVictor Perevertkin case CSUM_TYPE_BLAKE2: { 225194ea909SVictor Perevertkin uint8_t hash[BLAKE2_HASH_SIZE]; 226194ea909SVictor Perevertkin 227194ea909SVictor Perevertkin blake2b(hash, sizeof(hash), buf, Vcb->superblock.sector_size); 228194ea909SVictor Perevertkin 229194ea909SVictor Perevertkin return RtlCompareMemory(hash, csum, BLAKE2_HASH_SIZE) == BLAKE2_HASH_SIZE; 230194ea909SVictor Perevertkin } 231194ea909SVictor Perevertkin } 232194ea909SVictor Perevertkin 233194ea909SVictor Perevertkin return false; 234194ea909SVictor Perevertkin } 235194ea909SVictor Perevertkin 236318da0c1SPierre Schweitzer static NTSTATUS read_data_dup(device_extension* Vcb, uint8_t* buf, uint64_t addr, read_data_context* context, CHUNK_ITEM* ci, 237318da0c1SPierre Schweitzer device** devices, uint64_t generation) { 238318da0c1SPierre Schweitzer bool checksum_error = false; 239318da0c1SPierre Schweitzer uint16_t j, stripe = 0; 240c2c66affSColin Finck NTSTATUS Status; 241c2c66affSColin Finck CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1]; 242c2c66affSColin Finck 243c2c66affSColin Finck for (j = 0; j < ci->num_stripes; j++) { 244c2c66affSColin Finck if (context->stripes[j].status == ReadDataStatus_Error) { 245194ea909SVictor Perevertkin WARN("stripe %u returned error %08lx\n", j, context->stripes[j].iosb.Status); 246c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); 247c2c66affSColin Finck return context->stripes[j].iosb.Status; 248c2c66affSColin Finck } else if (context->stripes[j].status == ReadDataStatus_Success) { 249c2c66affSColin Finck stripe = j; 250c2c66affSColin Finck break; 251c2c66affSColin Finck } 252c2c66affSColin Finck } 253c2c66affSColin Finck 254c2c66affSColin Finck if (context->stripes[stripe].status != ReadDataStatus_Success) 255c2c66affSColin Finck return STATUS_INTERNAL_ERROR; 256c2c66affSColin Finck 257c2c66affSColin Finck if (context->tree) { 258c2c66affSColin Finck tree_header* th = (tree_header*)buf; 259c2c66affSColin Finck 260194ea909SVictor Perevertkin if (th->address != context->address || !check_tree_checksum(Vcb, th)) { 261318da0c1SPierre Schweitzer checksum_error = true; 262c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 263c2c66affSColin Finck } else if (generation != 0 && th->generation != generation) { 264318da0c1SPierre Schweitzer checksum_error = true; 265c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_GENERATION_ERRORS); 266c2c66affSColin Finck } 267c2c66affSColin Finck } else if (context->csum) { 268c2c66affSColin Finck Status = check_csum(Vcb, buf, (ULONG)context->stripes[stripe].Irp->IoStatus.Information / context->sector_size, context->csum); 269c2c66affSColin Finck 270c2c66affSColin Finck if (Status == STATUS_CRC_ERROR) { 271318da0c1SPierre Schweitzer checksum_error = true; 272c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 273c2c66affSColin Finck } else if (!NT_SUCCESS(Status)) { 274194ea909SVictor Perevertkin ERR("check_csum returned %08lx\n", Status); 275c2c66affSColin Finck return Status; 276c2c66affSColin Finck } 277c2c66affSColin Finck } 278c2c66affSColin Finck 279c2c66affSColin Finck if (!checksum_error) 280c2c66affSColin Finck return STATUS_SUCCESS; 281c2c66affSColin Finck 282c2c66affSColin Finck if (ci->num_stripes == 1) 283c2c66affSColin Finck return STATUS_CRC_ERROR; 284c2c66affSColin Finck 285c2c66affSColin Finck if (context->tree) { 286c2c66affSColin Finck tree_header* t2; 287318da0c1SPierre Schweitzer bool recovered = false; 288c2c66affSColin Finck 289c2c66affSColin Finck t2 = ExAllocatePoolWithTag(NonPagedPool, Vcb->superblock.node_size, ALLOC_TAG); 290c2c66affSColin Finck if (!t2) { 291c2c66affSColin Finck ERR("out of memory\n"); 292c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 293c2c66affSColin Finck } 294c2c66affSColin Finck 295c2c66affSColin Finck for (j = 0; j < ci->num_stripes; j++) { 296c2c66affSColin Finck if (j != stripe && devices[j] && devices[j]->devobj) { 297318da0c1SPierre Schweitzer Status = sync_read_phys(devices[j]->devobj, devices[j]->fileobj, cis[j].offset + context->stripes[stripe].stripestart, 298318da0c1SPierre Schweitzer Vcb->superblock.node_size, (uint8_t*)t2, false); 299c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 300194ea909SVictor Perevertkin WARN("sync_read_phys returned %08lx\n", Status); 301c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); 302c2c66affSColin Finck } else { 303194ea909SVictor Perevertkin bool checksum_error = !check_tree_checksum(Vcb, t2); 304c2c66affSColin Finck 305194ea909SVictor Perevertkin if (t2->address == addr && !checksum_error && (generation == 0 || t2->generation == generation)) { 306c2c66affSColin Finck RtlCopyMemory(buf, t2, Vcb->superblock.node_size); 307318da0c1SPierre Schweitzer ERR("recovering from checksum error at %I64x, device %I64x\n", addr, devices[stripe]->devitem.dev_id); 308318da0c1SPierre Schweitzer recovered = true; 309c2c66affSColin Finck 310c2c66affSColin Finck if (!Vcb->readonly && !devices[stripe]->readonly) { // write good data over bad 311318da0c1SPierre Schweitzer Status = write_data_phys(devices[stripe]->devobj, devices[stripe]->fileobj, cis[stripe].offset + context->stripes[stripe].stripestart, 312c2c66affSColin Finck t2, Vcb->superblock.node_size); 313c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 314194ea909SVictor Perevertkin WARN("write_data_phys returned %08lx\n", Status); 315c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_WRITE_ERRORS); 316c2c66affSColin Finck } 317c2c66affSColin Finck } 318c2c66affSColin Finck 319c2c66affSColin Finck break; 320194ea909SVictor Perevertkin } else if (t2->address != addr || checksum_error) 321c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 322c2c66affSColin Finck else 323c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_GENERATION_ERRORS); 324c2c66affSColin Finck } 325c2c66affSColin Finck } 326c2c66affSColin Finck } 327c2c66affSColin Finck 328c2c66affSColin Finck if (!recovered) { 329318da0c1SPierre Schweitzer ERR("unrecoverable checksum error at %I64x\n", addr); 330c2c66affSColin Finck ExFreePool(t2); 331c2c66affSColin Finck return STATUS_CRC_ERROR; 332c2c66affSColin Finck } 333c2c66affSColin Finck 334c2c66affSColin Finck ExFreePool(t2); 335c2c66affSColin Finck } else { 336174dfab6SVincent Franchomme ULONG sectors = (ULONG)context->stripes[stripe].Irp->IoStatus.Information >> Vcb->sector_shift; 337318da0c1SPierre Schweitzer uint8_t* sector; 338194ea909SVictor Perevertkin void* ptr = context->csum; 339c2c66affSColin Finck 340c2c66affSColin Finck sector = ExAllocatePoolWithTag(NonPagedPool, Vcb->superblock.sector_size, ALLOC_TAG); 341c2c66affSColin Finck if (!sector) { 342c2c66affSColin Finck ERR("out of memory\n"); 343c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 344c2c66affSColin Finck } 345c2c66affSColin Finck 346174dfab6SVincent Franchomme for (ULONG i = 0; i < sectors; i++) { 347174dfab6SVincent Franchomme if (!check_sector_csum(Vcb, buf + (i << Vcb->sector_shift), ptr)) { 348318da0c1SPierre Schweitzer bool recovered = false; 349c2c66affSColin Finck 350c2c66affSColin Finck for (j = 0; j < ci->num_stripes; j++) { 351c2c66affSColin Finck if (j != stripe && devices[j] && devices[j]->devobj) { 352318da0c1SPierre Schweitzer Status = sync_read_phys(devices[j]->devobj, devices[j]->fileobj, 353174dfab6SVincent Franchomme cis[j].offset + context->stripes[stripe].stripestart + ((uint64_t)i << Vcb->sector_shift), 354318da0c1SPierre Schweitzer Vcb->superblock.sector_size, sector, false); 355c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 356194ea909SVictor Perevertkin WARN("sync_read_phys returned %08lx\n", Status); 357c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); 358c2c66affSColin Finck } else { 359194ea909SVictor Perevertkin if (check_sector_csum(Vcb, sector, ptr)) { 360174dfab6SVincent Franchomme RtlCopyMemory(buf + (i << Vcb->sector_shift), sector, Vcb->superblock.sector_size); 361174dfab6SVincent Franchomme ERR("recovering from checksum error at %I64x, device %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift), devices[stripe]->devitem.dev_id); 362318da0c1SPierre Schweitzer recovered = true; 363c2c66affSColin Finck 364c2c66affSColin Finck if (!Vcb->readonly && !devices[stripe]->readonly) { // write good data over bad 365318da0c1SPierre Schweitzer Status = write_data_phys(devices[stripe]->devobj, devices[stripe]->fileobj, 366174dfab6SVincent Franchomme cis[stripe].offset + context->stripes[stripe].stripestart + ((uint64_t)i << Vcb->sector_shift), 367c2c66affSColin Finck sector, Vcb->superblock.sector_size); 368c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 369194ea909SVictor Perevertkin WARN("write_data_phys returned %08lx\n", Status); 370c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_WRITE_ERRORS); 371c2c66affSColin Finck } 372c2c66affSColin Finck } 373c2c66affSColin Finck 374c2c66affSColin Finck break; 375c2c66affSColin Finck } else 376c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 377c2c66affSColin Finck } 378c2c66affSColin Finck } 379c2c66affSColin Finck } 380c2c66affSColin Finck 381c2c66affSColin Finck if (!recovered) { 382174dfab6SVincent Franchomme ERR("unrecoverable checksum error at %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift)); 383c2c66affSColin Finck ExFreePool(sector); 384c2c66affSColin Finck return STATUS_CRC_ERROR; 385c2c66affSColin Finck } 386c2c66affSColin Finck } 387194ea909SVictor Perevertkin 388194ea909SVictor Perevertkin ptr = (uint8_t*)ptr + Vcb->csum_size; 389c2c66affSColin Finck } 390c2c66affSColin Finck 391c2c66affSColin Finck ExFreePool(sector); 392c2c66affSColin Finck } 393c2c66affSColin Finck 394c2c66affSColin Finck return STATUS_SUCCESS; 395c2c66affSColin Finck } 396c2c66affSColin Finck 397318da0c1SPierre Schweitzer static NTSTATUS read_data_raid0(device_extension* Vcb, uint8_t* buf, uint64_t addr, uint32_t length, read_data_context* context, 398318da0c1SPierre Schweitzer CHUNK_ITEM* ci, device** devices, uint64_t generation, uint64_t offset) { 399174dfab6SVincent Franchomme for (uint16_t i = 0; i < ci->num_stripes; i++) { 400c2c66affSColin Finck if (context->stripes[i].status == ReadDataStatus_Error) { 401174dfab6SVincent Franchomme WARN("stripe %u returned error %08lx\n", i, context->stripes[i].iosb.Status); 402c2c66affSColin Finck log_device_error(Vcb, devices[i], BTRFS_DEV_STAT_READ_ERRORS); 403c2c66affSColin Finck return context->stripes[i].iosb.Status; 404c2c66affSColin Finck } 405c2c66affSColin Finck } 406c2c66affSColin Finck 407c2c66affSColin Finck if (context->tree) { // shouldn't happen, as trees shouldn't cross stripe boundaries 408c2c66affSColin Finck tree_header* th = (tree_header*)buf; 409194ea909SVictor Perevertkin bool checksum_error = !check_tree_checksum(Vcb, th); 410c2c66affSColin Finck 411194ea909SVictor Perevertkin if (checksum_error || addr != th->address || (generation != 0 && generation != th->generation)) { 412318da0c1SPierre Schweitzer uint64_t off; 413318da0c1SPierre Schweitzer uint16_t stripe; 414c2c66affSColin Finck 415c2c66affSColin Finck get_raid0_offset(addr - offset, ci->stripe_length, ci->num_stripes, &off, &stripe); 416c2c66affSColin Finck 417318da0c1SPierre Schweitzer ERR("unrecoverable checksum error at %I64x, device %I64x\n", addr, devices[stripe]->devitem.dev_id); 418c2c66affSColin Finck 419194ea909SVictor Perevertkin if (checksum_error) { 420c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 421c2c66affSColin Finck return STATUS_CRC_ERROR; 422c2c66affSColin Finck } else if (addr != th->address) { 423318da0c1SPierre Schweitzer WARN("address of tree was %I64x, not %I64x as expected\n", th->address, addr); 424c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 425c2c66affSColin Finck return STATUS_CRC_ERROR; 426c2c66affSColin Finck } else if (generation != 0 && generation != th->generation) { 427318da0c1SPierre Schweitzer WARN("generation of tree was %I64x, not %I64x as expected\n", th->generation, generation); 428c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_GENERATION_ERRORS); 429c2c66affSColin Finck return STATUS_CRC_ERROR; 430c2c66affSColin Finck } 431c2c66affSColin Finck } 432c2c66affSColin Finck } else if (context->csum) { 433c2c66affSColin Finck NTSTATUS Status; 434c2c66affSColin Finck 435174dfab6SVincent Franchomme Status = check_csum(Vcb, buf, length >> Vcb->sector_shift, context->csum); 436c2c66affSColin Finck 437c2c66affSColin Finck if (Status == STATUS_CRC_ERROR) { 438194ea909SVictor Perevertkin void* ptr = context->csum; 439c2c66affSColin Finck 440174dfab6SVincent Franchomme for (uint32_t i = 0; i < length >> Vcb->sector_shift; i++) { 441174dfab6SVincent Franchomme if (!check_sector_csum(Vcb, buf + (i << Vcb->sector_shift), ptr)) { 442318da0c1SPierre Schweitzer uint64_t off; 443318da0c1SPierre Schweitzer uint16_t stripe; 444c2c66affSColin Finck 445174dfab6SVincent Franchomme get_raid0_offset(addr - offset + ((uint64_t)i << Vcb->sector_shift), ci->stripe_length, ci->num_stripes, &off, &stripe); 446c2c66affSColin Finck 447318da0c1SPierre Schweitzer ERR("unrecoverable checksum error at %I64x, device %I64x\n", addr, devices[stripe]->devitem.dev_id); 448c2c66affSColin Finck 449c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 450c2c66affSColin Finck 451c2c66affSColin Finck return Status; 452c2c66affSColin Finck } 453194ea909SVictor Perevertkin 454194ea909SVictor Perevertkin ptr = (uint8_t*)ptr + Vcb->csum_size; 455c2c66affSColin Finck } 456c2c66affSColin Finck 457c2c66affSColin Finck return Status; 458c2c66affSColin Finck } else if (!NT_SUCCESS(Status)) { 459194ea909SVictor Perevertkin ERR("check_csum returned %08lx\n", Status); 460c2c66affSColin Finck return Status; 461c2c66affSColin Finck } 462c2c66affSColin Finck } 463c2c66affSColin Finck 464c2c66affSColin Finck return STATUS_SUCCESS; 465c2c66affSColin Finck } 466c2c66affSColin Finck 467318da0c1SPierre Schweitzer static NTSTATUS read_data_raid10(device_extension* Vcb, uint8_t* buf, uint64_t addr, uint32_t length, read_data_context* context, 468318da0c1SPierre Schweitzer CHUNK_ITEM* ci, device** devices, uint64_t generation, uint64_t offset) { 469*06042735SVincent Franchomme uint16_t stripe = 0; 470c2c66affSColin Finck NTSTATUS Status; 471318da0c1SPierre Schweitzer bool checksum_error = false; 472c2c66affSColin Finck CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1]; 473c2c66affSColin Finck 474174dfab6SVincent Franchomme for (uint16_t j = 0; j < ci->num_stripes; j++) { 475c2c66affSColin Finck if (context->stripes[j].status == ReadDataStatus_Error) { 476194ea909SVictor Perevertkin WARN("stripe %u returned error %08lx\n", j, context->stripes[j].iosb.Status); 477c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); 478c2c66affSColin Finck return context->stripes[j].iosb.Status; 479c2c66affSColin Finck } else if (context->stripes[j].status == ReadDataStatus_Success) 480c2c66affSColin Finck stripe = j; 481c2c66affSColin Finck } 482c2c66affSColin Finck 483c2c66affSColin Finck if (context->tree) { 484c2c66affSColin Finck tree_header* th = (tree_header*)buf; 485c2c66affSColin Finck 486194ea909SVictor Perevertkin if (!check_tree_checksum(Vcb, th)) { 487318da0c1SPierre Schweitzer checksum_error = true; 488c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 489c2c66affSColin Finck } else if (addr != th->address) { 490318da0c1SPierre Schweitzer WARN("address of tree was %I64x, not %I64x as expected\n", th->address, addr); 491318da0c1SPierre Schweitzer checksum_error = true; 492c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 493c2c66affSColin Finck } else if (generation != 0 && generation != th->generation) { 494318da0c1SPierre Schweitzer WARN("generation of tree was %I64x, not %I64x as expected\n", th->generation, generation); 495318da0c1SPierre Schweitzer checksum_error = true; 496c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_GENERATION_ERRORS); 497c2c66affSColin Finck } 498c2c66affSColin Finck } else if (context->csum) { 499174dfab6SVincent Franchomme Status = check_csum(Vcb, buf, length >> Vcb->sector_shift, context->csum); 500c2c66affSColin Finck 501c2c66affSColin Finck if (Status == STATUS_CRC_ERROR) 502318da0c1SPierre Schweitzer checksum_error = true; 503c2c66affSColin Finck else if (!NT_SUCCESS(Status)) { 504194ea909SVictor Perevertkin ERR("check_csum returned %08lx\n", Status); 505c2c66affSColin Finck return Status; 506c2c66affSColin Finck } 507c2c66affSColin Finck } 508c2c66affSColin Finck 509c2c66affSColin Finck if (!checksum_error) 510c2c66affSColin Finck return STATUS_SUCCESS; 511c2c66affSColin Finck 512c2c66affSColin Finck if (context->tree) { 513c2c66affSColin Finck tree_header* t2; 514318da0c1SPierre Schweitzer uint64_t off; 515318da0c1SPierre Schweitzer uint16_t badsubstripe = 0; 516318da0c1SPierre Schweitzer bool recovered = false; 517c2c66affSColin Finck 518c2c66affSColin Finck t2 = ExAllocatePoolWithTag(NonPagedPool, Vcb->superblock.node_size, ALLOC_TAG); 519c2c66affSColin Finck if (!t2) { 520c2c66affSColin Finck ERR("out of memory\n"); 521c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 522c2c66affSColin Finck } 523c2c66affSColin Finck 524c2c66affSColin Finck get_raid0_offset(addr - offset, ci->stripe_length, ci->num_stripes / ci->sub_stripes, &off, &stripe); 525c2c66affSColin Finck 526c2c66affSColin Finck stripe *= ci->sub_stripes; 527c2c66affSColin Finck 528174dfab6SVincent Franchomme for (uint16_t j = 0; j < ci->sub_stripes; j++) { 529c2c66affSColin Finck if (context->stripes[stripe + j].status == ReadDataStatus_Success) { 530c2c66affSColin Finck badsubstripe = j; 531c2c66affSColin Finck break; 532c2c66affSColin Finck } 533c2c66affSColin Finck } 534c2c66affSColin Finck 535174dfab6SVincent Franchomme for (uint16_t j = 0; j < ci->sub_stripes; j++) { 536c2c66affSColin Finck if (context->stripes[stripe + j].status != ReadDataStatus_Success && devices[stripe + j] && devices[stripe + j]->devobj) { 537318da0c1SPierre Schweitzer Status = sync_read_phys(devices[stripe + j]->devobj, devices[stripe + j]->fileobj, cis[stripe + j].offset + off, 538318da0c1SPierre Schweitzer Vcb->superblock.node_size, (uint8_t*)t2, false); 539c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 540194ea909SVictor Perevertkin WARN("sync_read_phys returned %08lx\n", Status); 541c2c66affSColin Finck log_device_error(Vcb, devices[stripe + j], BTRFS_DEV_STAT_READ_ERRORS); 542c2c66affSColin Finck } else { 543194ea909SVictor Perevertkin bool checksum_error = !check_tree_checksum(Vcb, t2); 544c2c66affSColin Finck 545194ea909SVictor Perevertkin if (t2->address == addr && !checksum_error && (generation == 0 || t2->generation == generation)) { 546c2c66affSColin Finck RtlCopyMemory(buf, t2, Vcb->superblock.node_size); 547318da0c1SPierre Schweitzer ERR("recovering from checksum error at %I64x, device %I64x\n", addr, devices[stripe + j]->devitem.dev_id); 548318da0c1SPierre Schweitzer recovered = true; 549c2c66affSColin Finck 550c2c66affSColin Finck if (!Vcb->readonly && !devices[stripe + badsubstripe]->readonly && devices[stripe + badsubstripe]->devobj) { // write good data over bad 551318da0c1SPierre Schweitzer Status = write_data_phys(devices[stripe + badsubstripe]->devobj, devices[stripe + badsubstripe]->fileobj, 552318da0c1SPierre Schweitzer cis[stripe + badsubstripe].offset + off, t2, Vcb->superblock.node_size); 553c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 554194ea909SVictor Perevertkin WARN("write_data_phys returned %08lx\n", Status); 555c2c66affSColin Finck log_device_error(Vcb, devices[stripe + badsubstripe], BTRFS_DEV_STAT_WRITE_ERRORS); 556c2c66affSColin Finck } 557c2c66affSColin Finck } 558c2c66affSColin Finck 559c2c66affSColin Finck break; 560194ea909SVictor Perevertkin } else if (t2->address != addr || checksum_error) 561c2c66affSColin Finck log_device_error(Vcb, devices[stripe + j], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 562c2c66affSColin Finck else 563c2c66affSColin Finck log_device_error(Vcb, devices[stripe + j], BTRFS_DEV_STAT_GENERATION_ERRORS); 564c2c66affSColin Finck } 565c2c66affSColin Finck } 566c2c66affSColin Finck } 567c2c66affSColin Finck 568c2c66affSColin Finck if (!recovered) { 569318da0c1SPierre Schweitzer ERR("unrecoverable checksum error at %I64x\n", addr); 570c2c66affSColin Finck ExFreePool(t2); 571c2c66affSColin Finck return STATUS_CRC_ERROR; 572c2c66affSColin Finck } 573c2c66affSColin Finck 574c2c66affSColin Finck ExFreePool(t2); 575c2c66affSColin Finck } else { 576174dfab6SVincent Franchomme ULONG sectors = length >> Vcb->sector_shift; 577318da0c1SPierre Schweitzer uint8_t* sector; 578194ea909SVictor Perevertkin void* ptr = context->csum; 579c2c66affSColin Finck 580c2c66affSColin Finck sector = ExAllocatePoolWithTag(NonPagedPool, Vcb->superblock.sector_size, ALLOC_TAG); 581c2c66affSColin Finck if (!sector) { 582c2c66affSColin Finck ERR("out of memory\n"); 583c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 584c2c66affSColin Finck } 585c2c66affSColin Finck 586174dfab6SVincent Franchomme for (ULONG i = 0; i < sectors; i++) { 587174dfab6SVincent Franchomme if (!check_sector_csum(Vcb, buf + (i << Vcb->sector_shift), ptr)) { 588318da0c1SPierre Schweitzer uint64_t off; 589318da0c1SPierre Schweitzer uint16_t stripe2, badsubstripe = 0; 590318da0c1SPierre Schweitzer bool recovered = false; 591c2c66affSColin Finck 592174dfab6SVincent Franchomme get_raid0_offset(addr - offset + ((uint64_t)i << Vcb->sector_shift), ci->stripe_length, 593c2c66affSColin Finck ci->num_stripes / ci->sub_stripes, &off, &stripe2); 594c2c66affSColin Finck 595c2c66affSColin Finck stripe2 *= ci->sub_stripes; 596c2c66affSColin Finck 597174dfab6SVincent Franchomme for (uint16_t j = 0; j < ci->sub_stripes; j++) { 598c2c66affSColin Finck if (context->stripes[stripe2 + j].status == ReadDataStatus_Success) { 599c2c66affSColin Finck badsubstripe = j; 600c2c66affSColin Finck break; 601c2c66affSColin Finck } 602c2c66affSColin Finck } 603c2c66affSColin Finck 604c2c66affSColin Finck log_device_error(Vcb, devices[stripe2 + badsubstripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 605c2c66affSColin Finck 606174dfab6SVincent Franchomme for (uint16_t j = 0; j < ci->sub_stripes; j++) { 607c2c66affSColin Finck if (context->stripes[stripe2 + j].status != ReadDataStatus_Success && devices[stripe2 + j] && devices[stripe2 + j]->devobj) { 608318da0c1SPierre Schweitzer Status = sync_read_phys(devices[stripe2 + j]->devobj, devices[stripe2 + j]->fileobj, cis[stripe2 + j].offset + off, 609318da0c1SPierre Schweitzer Vcb->superblock.sector_size, sector, false); 610c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 611194ea909SVictor Perevertkin WARN("sync_read_phys returned %08lx\n", Status); 612c2c66affSColin Finck log_device_error(Vcb, devices[stripe2 + j], BTRFS_DEV_STAT_READ_ERRORS); 613c2c66affSColin Finck } else { 614194ea909SVictor Perevertkin if (check_sector_csum(Vcb, sector, ptr)) { 615174dfab6SVincent Franchomme RtlCopyMemory(buf + (i << Vcb->sector_shift), sector, Vcb->superblock.sector_size); 616174dfab6SVincent Franchomme ERR("recovering from checksum error at %I64x, device %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift), devices[stripe2 + j]->devitem.dev_id); 617318da0c1SPierre Schweitzer recovered = true; 618c2c66affSColin Finck 619c2c66affSColin Finck if (!Vcb->readonly && !devices[stripe2 + badsubstripe]->readonly && devices[stripe2 + badsubstripe]->devobj) { // write good data over bad 620318da0c1SPierre Schweitzer Status = write_data_phys(devices[stripe2 + badsubstripe]->devobj, devices[stripe2 + badsubstripe]->fileobj, 621318da0c1SPierre Schweitzer cis[stripe2 + badsubstripe].offset + off, sector, Vcb->superblock.sector_size); 622c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 623194ea909SVictor Perevertkin WARN("write_data_phys returned %08lx\n", Status); 624c2c66affSColin Finck log_device_error(Vcb, devices[stripe2 + badsubstripe], BTRFS_DEV_STAT_READ_ERRORS); 625c2c66affSColin Finck } 626c2c66affSColin Finck } 627c2c66affSColin Finck 628c2c66affSColin Finck break; 629c2c66affSColin Finck } else 630c2c66affSColin Finck log_device_error(Vcb, devices[stripe2 + j], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 631c2c66affSColin Finck } 632c2c66affSColin Finck } 633c2c66affSColin Finck } 634c2c66affSColin Finck 635c2c66affSColin Finck if (!recovered) { 636174dfab6SVincent Franchomme ERR("unrecoverable checksum error at %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift)); 637c2c66affSColin Finck ExFreePool(sector); 638c2c66affSColin Finck return STATUS_CRC_ERROR; 639c2c66affSColin Finck } 640c2c66affSColin Finck } 641194ea909SVictor Perevertkin 642194ea909SVictor Perevertkin ptr = (uint8_t*)ptr + Vcb->csum_size; 643c2c66affSColin Finck } 644c2c66affSColin Finck 645c2c66affSColin Finck ExFreePool(sector); 646c2c66affSColin Finck } 647c2c66affSColin Finck 648c2c66affSColin Finck return STATUS_SUCCESS; 649c2c66affSColin Finck } 650c2c66affSColin Finck 651318da0c1SPierre Schweitzer static NTSTATUS read_data_raid5(device_extension* Vcb, uint8_t* buf, uint64_t addr, uint32_t length, read_data_context* context, CHUNK_ITEM* ci, 652318da0c1SPierre Schweitzer device** devices, uint64_t offset, uint64_t generation, chunk* c, bool degraded) { 653c2c66affSColin Finck NTSTATUS Status; 654318da0c1SPierre Schweitzer bool checksum_error = false; 655c2c66affSColin Finck CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1]; 656*06042735SVincent Franchomme uint16_t j, stripe = 0; 657318da0c1SPierre Schweitzer bool no_success = true; 658c2c66affSColin Finck 659c2c66affSColin Finck for (j = 0; j < ci->num_stripes; j++) { 660c2c66affSColin Finck if (context->stripes[j].status == ReadDataStatus_Error) { 661194ea909SVictor Perevertkin WARN("stripe %u returned error %08lx\n", j, context->stripes[j].iosb.Status); 662c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); 663c2c66affSColin Finck return context->stripes[j].iosb.Status; 664c2c66affSColin Finck } else if (context->stripes[j].status == ReadDataStatus_Success) { 665c2c66affSColin Finck stripe = j; 666318da0c1SPierre Schweitzer no_success = false; 667c2c66affSColin Finck } 668c2c66affSColin Finck } 669c2c66affSColin Finck 670c2c66affSColin Finck if (c) { // check partial stripes 671c2c66affSColin Finck LIST_ENTRY* le; 672318da0c1SPierre Schweitzer uint64_t ps_length = (ci->num_stripes - 1) * ci->stripe_length; 673c2c66affSColin Finck 674318da0c1SPierre Schweitzer ExAcquireResourceSharedLite(&c->partial_stripes_lock, true); 675c2c66affSColin Finck 676c2c66affSColin Finck le = c->partial_stripes.Flink; 677c2c66affSColin Finck while (le != &c->partial_stripes) { 678c2c66affSColin Finck partial_stripe* ps = CONTAINING_RECORD(le, partial_stripe, list_entry); 679c2c66affSColin Finck 680c2c66affSColin Finck if (ps->address + ps_length > addr && ps->address < addr + length) { 681c2c66affSColin Finck ULONG runlength, index; 682c2c66affSColin Finck 683c2c66affSColin Finck runlength = RtlFindFirstRunClear(&ps->bmp, &index); 684c2c66affSColin Finck 685c2c66affSColin Finck while (runlength != 0) { 686318da0c1SPierre Schweitzer #ifdef __REACTOS__ 687318da0c1SPierre Schweitzer uint64_t runstart, runend, start, end; 688318da0c1SPierre Schweitzer #endif 689318da0c1SPierre Schweitzer if (index >= ps->bmplen) 690318da0c1SPierre Schweitzer break; 691318da0c1SPierre Schweitzer 692318da0c1SPierre Schweitzer if (index + runlength >= ps->bmplen) { 693318da0c1SPierre Schweitzer runlength = ps->bmplen - index; 694318da0c1SPierre Schweitzer 695318da0c1SPierre Schweitzer if (runlength == 0) 696318da0c1SPierre Schweitzer break; 697318da0c1SPierre Schweitzer } 698318da0c1SPierre Schweitzer #ifndef __REACTOS__ 699174dfab6SVincent Franchomme uint64_t runstart = ps->address + (index << Vcb->sector_shift); 700174dfab6SVincent Franchomme uint64_t runend = runstart + (runlength << Vcb->sector_shift); 701318da0c1SPierre Schweitzer uint64_t start = max(runstart, addr); 702318da0c1SPierre Schweitzer uint64_t end = min(runend, addr + length); 703318da0c1SPierre Schweitzer #else 704174dfab6SVincent Franchomme runstart = ps->address + (index * Vcb->sector_shift); 705174dfab6SVincent Franchomme runend = runstart + (runlength * Vcb->sector_shift); 706318da0c1SPierre Schweitzer start = max(runstart, addr); 707318da0c1SPierre Schweitzer end = min(runend, addr + length); 708318da0c1SPierre Schweitzer #endif 709c2c66affSColin Finck 710c2c66affSColin Finck if (end > start) 711c2c66affSColin Finck RtlCopyMemory(buf + start - addr, &ps->data[start - ps->address], (ULONG)(end - start)); 712c2c66affSColin Finck 713c2c66affSColin Finck runlength = RtlFindNextForwardRunClear(&ps->bmp, index + runlength, &index); 714c2c66affSColin Finck } 715c2c66affSColin Finck } else if (ps->address >= addr + length) 716c2c66affSColin Finck break; 717c2c66affSColin Finck 718c2c66affSColin Finck le = le->Flink; 719c2c66affSColin Finck } 720c2c66affSColin Finck 721c2c66affSColin Finck ExReleaseResourceLite(&c->partial_stripes_lock); 722c2c66affSColin Finck } 723c2c66affSColin Finck 724c2c66affSColin Finck if (context->tree) { 725c2c66affSColin Finck tree_header* th = (tree_header*)buf; 726c2c66affSColin Finck 727194ea909SVictor Perevertkin if (addr != th->address || !check_tree_checksum(Vcb, th)) { 728318da0c1SPierre Schweitzer checksum_error = true; 729c2c66affSColin Finck if (!no_success && !degraded) 730c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 731c2c66affSColin Finck } else if (generation != 0 && generation != th->generation) { 732318da0c1SPierre Schweitzer checksum_error = true; 733c2c66affSColin Finck if (!no_success && !degraded) 734c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_GENERATION_ERRORS); 735c2c66affSColin Finck } 736c2c66affSColin Finck } else if (context->csum) { 737174dfab6SVincent Franchomme Status = check_csum(Vcb, buf, length >> Vcb->sector_shift, context->csum); 738c2c66affSColin Finck 739c2c66affSColin Finck if (Status == STATUS_CRC_ERROR) { 740c2c66affSColin Finck if (!degraded) 741c2c66affSColin Finck WARN("checksum error\n"); 742318da0c1SPierre Schweitzer checksum_error = true; 743c2c66affSColin Finck } else if (!NT_SUCCESS(Status)) { 744194ea909SVictor Perevertkin ERR("check_csum returned %08lx\n", Status); 745c2c66affSColin Finck return Status; 746c2c66affSColin Finck } 747c2c66affSColin Finck } else if (degraded) 748318da0c1SPierre Schweitzer checksum_error = true; 749c2c66affSColin Finck 750c2c66affSColin Finck if (!checksum_error) 751c2c66affSColin Finck return STATUS_SUCCESS; 752c2c66affSColin Finck 753c2c66affSColin Finck if (context->tree) { 754318da0c1SPierre Schweitzer uint16_t parity; 755318da0c1SPierre Schweitzer uint64_t off; 756318da0c1SPierre Schweitzer bool recovered = false, first = true, failed = false; 757318da0c1SPierre Schweitzer uint8_t* t2; 758c2c66affSColin Finck 759c2c66affSColin Finck t2 = ExAllocatePoolWithTag(NonPagedPool, Vcb->superblock.node_size * 2, ALLOC_TAG); 760c2c66affSColin Finck if (!t2) { 761c2c66affSColin Finck ERR("out of memory\n"); 762c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 763c2c66affSColin Finck } 764c2c66affSColin Finck 765c2c66affSColin Finck get_raid0_offset(addr - offset, ci->stripe_length, ci->num_stripes - 1, &off, &stripe); 766c2c66affSColin Finck 767c2c66affSColin Finck parity = (((addr - offset) / ((ci->num_stripes - 1) * ci->stripe_length)) + ci->num_stripes - 1) % ci->num_stripes; 768c2c66affSColin Finck 769c2c66affSColin Finck stripe = (parity + stripe + 1) % ci->num_stripes; 770c2c66affSColin Finck 771c2c66affSColin Finck for (j = 0; j < ci->num_stripes; j++) { 772c2c66affSColin Finck if (j != stripe) { 773c2c66affSColin Finck if (devices[j] && devices[j]->devobj) { 774c2c66affSColin Finck if (first) { 775318da0c1SPierre Schweitzer Status = sync_read_phys(devices[j]->devobj, devices[j]->fileobj, cis[j].offset + off, Vcb->superblock.node_size, t2, false); 776c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 777194ea909SVictor Perevertkin ERR("sync_read_phys returned %08lx\n", Status); 778c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); 779318da0c1SPierre Schweitzer failed = true; 780c2c66affSColin Finck break; 781c2c66affSColin Finck } 782c2c66affSColin Finck 783318da0c1SPierre Schweitzer first = false; 784c2c66affSColin Finck } else { 785318da0c1SPierre Schweitzer Status = sync_read_phys(devices[j]->devobj, devices[j]->fileobj, cis[j].offset + off, Vcb->superblock.node_size, t2 + Vcb->superblock.node_size, false); 786c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 787194ea909SVictor Perevertkin ERR("sync_read_phys returned %08lx\n", Status); 788c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); 789318da0c1SPierre Schweitzer failed = true; 790c2c66affSColin Finck break; 791c2c66affSColin Finck } 792c2c66affSColin Finck 793c2c66affSColin Finck do_xor(t2, t2 + Vcb->superblock.node_size, Vcb->superblock.node_size); 794c2c66affSColin Finck } 795c2c66affSColin Finck } else { 796318da0c1SPierre Schweitzer failed = true; 797c2c66affSColin Finck break; 798c2c66affSColin Finck } 799c2c66affSColin Finck } 800c2c66affSColin Finck } 801c2c66affSColin Finck 802c2c66affSColin Finck if (!failed) { 803c2c66affSColin Finck tree_header* t3 = (tree_header*)t2; 804c2c66affSColin Finck 805194ea909SVictor Perevertkin if (t3->address == addr && check_tree_checksum(Vcb, t3) && (generation == 0 || t3->generation == generation)) { 806c2c66affSColin Finck RtlCopyMemory(buf, t2, Vcb->superblock.node_size); 807c2c66affSColin Finck 808c2c66affSColin Finck if (!degraded) 809318da0c1SPierre Schweitzer ERR("recovering from checksum error at %I64x, device %I64x\n", addr, devices[stripe]->devitem.dev_id); 810c2c66affSColin Finck 811318da0c1SPierre Schweitzer recovered = true; 812c2c66affSColin Finck 813c2c66affSColin Finck if (!Vcb->readonly && devices[stripe] && !devices[stripe]->readonly && devices[stripe]->devobj) { // write good data over bad 814318da0c1SPierre Schweitzer Status = write_data_phys(devices[stripe]->devobj, devices[stripe]->fileobj, cis[stripe].offset + off, t2, Vcb->superblock.node_size); 815c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 816194ea909SVictor Perevertkin WARN("write_data_phys returned %08lx\n", Status); 817c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_WRITE_ERRORS); 818c2c66affSColin Finck } 819c2c66affSColin Finck } 820c2c66affSColin Finck } 821c2c66affSColin Finck } 822c2c66affSColin Finck 823c2c66affSColin Finck if (!recovered) { 824318da0c1SPierre Schweitzer ERR("unrecoverable checksum error at %I64x\n", addr); 825c2c66affSColin Finck ExFreePool(t2); 826c2c66affSColin Finck return STATUS_CRC_ERROR; 827c2c66affSColin Finck } 828c2c66affSColin Finck 829c2c66affSColin Finck ExFreePool(t2); 830c2c66affSColin Finck } else { 831174dfab6SVincent Franchomme ULONG sectors = length >> Vcb->sector_shift; 832318da0c1SPierre Schweitzer uint8_t* sector; 833194ea909SVictor Perevertkin void* ptr = context->csum; 834c2c66affSColin Finck 835c2c66affSColin Finck sector = ExAllocatePoolWithTag(NonPagedPool, Vcb->superblock.sector_size * 2, ALLOC_TAG); 836c2c66affSColin Finck if (!sector) { 837c2c66affSColin Finck ERR("out of memory\n"); 838c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 839c2c66affSColin Finck } 840c2c66affSColin Finck 841174dfab6SVincent Franchomme for (ULONG i = 0; i < sectors; i++) { 842318da0c1SPierre Schweitzer uint16_t parity; 843318da0c1SPierre Schweitzer uint64_t off; 844c2c66affSColin Finck 845174dfab6SVincent Franchomme get_raid0_offset(addr - offset + ((uint64_t)i << Vcb->sector_shift), ci->stripe_length, 846c2c66affSColin Finck ci->num_stripes - 1, &off, &stripe); 847c2c66affSColin Finck 848174dfab6SVincent Franchomme parity = (((addr - offset + ((uint64_t)i << Vcb->sector_shift)) / ((ci->num_stripes - 1) * ci->stripe_length)) + ci->num_stripes - 1) % ci->num_stripes; 849c2c66affSColin Finck 850c2c66affSColin Finck stripe = (parity + stripe + 1) % ci->num_stripes; 851c2c66affSColin Finck 852174dfab6SVincent Franchomme if (!devices[stripe] || !devices[stripe]->devobj || (ptr && !check_sector_csum(Vcb, buf + (i << Vcb->sector_shift), ptr))) { 853318da0c1SPierre Schweitzer bool recovered = false, first = true, failed = false; 854c2c66affSColin Finck 855c2c66affSColin Finck if (devices[stripe] && devices[stripe]->devobj) 856c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_READ_ERRORS); 857c2c66affSColin Finck 858c2c66affSColin Finck for (j = 0; j < ci->num_stripes; j++) { 859c2c66affSColin Finck if (j != stripe) { 860c2c66affSColin Finck if (devices[j] && devices[j]->devobj) { 861c2c66affSColin Finck if (first) { 862318da0c1SPierre Schweitzer Status = sync_read_phys(devices[j]->devobj, devices[j]->fileobj, cis[j].offset + off, Vcb->superblock.sector_size, sector, false); 863c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 864194ea909SVictor Perevertkin ERR("sync_read_phys returned %08lx\n", Status); 865318da0c1SPierre Schweitzer failed = true; 866c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); 867c2c66affSColin Finck break; 868c2c66affSColin Finck } 869c2c66affSColin Finck 870318da0c1SPierre Schweitzer first = false; 871c2c66affSColin Finck } else { 872318da0c1SPierre Schweitzer Status = sync_read_phys(devices[j]->devobj, devices[j]->fileobj, cis[j].offset + off, Vcb->superblock.sector_size, 873318da0c1SPierre Schweitzer sector + Vcb->superblock.sector_size, false); 874c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 875194ea909SVictor Perevertkin ERR("sync_read_phys returned %08lx\n", Status); 876318da0c1SPierre Schweitzer failed = true; 877c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); 878c2c66affSColin Finck break; 879c2c66affSColin Finck } 880c2c66affSColin Finck 881c2c66affSColin Finck do_xor(sector, sector + Vcb->superblock.sector_size, Vcb->superblock.sector_size); 882c2c66affSColin Finck } 883c2c66affSColin Finck } else { 884318da0c1SPierre Schweitzer failed = true; 885c2c66affSColin Finck break; 886c2c66affSColin Finck } 887c2c66affSColin Finck } 888c2c66affSColin Finck } 889c2c66affSColin Finck 890c2c66affSColin Finck if (!failed) { 891194ea909SVictor Perevertkin if (!ptr || check_sector_csum(Vcb, sector, ptr)) { 892174dfab6SVincent Franchomme RtlCopyMemory(buf + (i << Vcb->sector_shift), sector, Vcb->superblock.sector_size); 893c2c66affSColin Finck 894c2c66affSColin Finck if (!degraded) 895174dfab6SVincent Franchomme ERR("recovering from checksum error at %I64x, device %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift), devices[stripe]->devitem.dev_id); 896c2c66affSColin Finck 897318da0c1SPierre Schweitzer recovered = true; 898c2c66affSColin Finck 899c2c66affSColin Finck if (!Vcb->readonly && devices[stripe] && !devices[stripe]->readonly && devices[stripe]->devobj) { // write good data over bad 900318da0c1SPierre Schweitzer Status = write_data_phys(devices[stripe]->devobj, devices[stripe]->fileobj, cis[stripe].offset + off, 901c2c66affSColin Finck sector, Vcb->superblock.sector_size); 902c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 903194ea909SVictor Perevertkin WARN("write_data_phys returned %08lx\n", Status); 904c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_WRITE_ERRORS); 905c2c66affSColin Finck } 906c2c66affSColin Finck } 907c2c66affSColin Finck } 908c2c66affSColin Finck } 909c2c66affSColin Finck 910c2c66affSColin Finck if (!recovered) { 911174dfab6SVincent Franchomme ERR("unrecoverable checksum error at %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift)); 912c2c66affSColin Finck ExFreePool(sector); 913c2c66affSColin Finck return STATUS_CRC_ERROR; 914c2c66affSColin Finck } 915c2c66affSColin Finck } 916194ea909SVictor Perevertkin 917194ea909SVictor Perevertkin if (ptr) 918194ea909SVictor Perevertkin ptr = (uint8_t*)ptr + Vcb->csum_size; 919c2c66affSColin Finck } 920c2c66affSColin Finck 921c2c66affSColin Finck ExFreePool(sector); 922c2c66affSColin Finck } 923c2c66affSColin Finck 924c2c66affSColin Finck return STATUS_SUCCESS; 925c2c66affSColin Finck } 926c2c66affSColin Finck 927318da0c1SPierre Schweitzer void raid6_recover2(uint8_t* sectors, uint16_t num_stripes, ULONG sector_size, uint16_t missing1, uint16_t missing2, uint8_t* out) { 928c2c66affSColin Finck if (missing1 == num_stripes - 2 || missing2 == num_stripes - 2) { // reconstruct from q and data 929318da0c1SPierre Schweitzer uint16_t missing = missing1 == (num_stripes - 2) ? missing2 : missing1; 930318da0c1SPierre Schweitzer uint16_t stripe; 931c2c66affSColin Finck 932c2c66affSColin Finck stripe = num_stripes - 3; 933c2c66affSColin Finck 934c2c66affSColin Finck if (stripe == missing) 935c2c66affSColin Finck RtlZeroMemory(out, sector_size); 936c2c66affSColin Finck else 937c2c66affSColin Finck RtlCopyMemory(out, sectors + (stripe * sector_size), sector_size); 938c2c66affSColin Finck 939c2c66affSColin Finck do { 940c2c66affSColin Finck stripe--; 941c2c66affSColin Finck 942c2c66affSColin Finck galois_double(out, sector_size); 943c2c66affSColin Finck 944c2c66affSColin Finck if (stripe != missing) 945c2c66affSColin Finck do_xor(out, sectors + (stripe * sector_size), sector_size); 946c2c66affSColin Finck } while (stripe > 0); 947c2c66affSColin Finck 948c2c66affSColin Finck do_xor(out, sectors + ((num_stripes - 1) * sector_size), sector_size); 949c2c66affSColin Finck 950c2c66affSColin Finck if (missing != 0) 951318da0c1SPierre Schweitzer galois_divpower(out, (uint8_t)missing, sector_size); 952c2c66affSColin Finck } else { // reconstruct from p and q 953*06042735SVincent Franchomme uint16_t x = missing1, y = missing2, stripe; 954318da0c1SPierre Schweitzer uint8_t gyx, gx, denom, a, b, *p, *q, *pxy, *qxy; 955318da0c1SPierre Schweitzer uint32_t j; 956c2c66affSColin Finck 957c2c66affSColin Finck stripe = num_stripes - 3; 958c2c66affSColin Finck 959c2c66affSColin Finck pxy = out + sector_size; 960c2c66affSColin Finck qxy = out; 961c2c66affSColin Finck 962c2c66affSColin Finck if (stripe == missing1 || stripe == missing2) { 963c2c66affSColin Finck RtlZeroMemory(qxy, sector_size); 964c2c66affSColin Finck RtlZeroMemory(pxy, sector_size); 965c2c66affSColin Finck } else { 966c2c66affSColin Finck RtlCopyMemory(qxy, sectors + (stripe * sector_size), sector_size); 967c2c66affSColin Finck RtlCopyMemory(pxy, sectors + (stripe * sector_size), sector_size); 968c2c66affSColin Finck } 969c2c66affSColin Finck 970c2c66affSColin Finck do { 971c2c66affSColin Finck stripe--; 972c2c66affSColin Finck 973c2c66affSColin Finck galois_double(qxy, sector_size); 974c2c66affSColin Finck 975c2c66affSColin Finck if (stripe != missing1 && stripe != missing2) { 976c2c66affSColin Finck do_xor(qxy, sectors + (stripe * sector_size), sector_size); 977c2c66affSColin Finck do_xor(pxy, sectors + (stripe * sector_size), sector_size); 978*06042735SVincent Franchomme } 979c2c66affSColin Finck } while (stripe > 0); 980c2c66affSColin Finck 981c2c66affSColin Finck gyx = gpow2(y > x ? (y-x) : (255-x+y)); 982c2c66affSColin Finck gx = gpow2(255-x); 983c2c66affSColin Finck 984c2c66affSColin Finck denom = gdiv(1, gyx ^ 1); 985c2c66affSColin Finck a = gmul(gyx, denom); 986c2c66affSColin Finck b = gmul(gx, denom); 987c2c66affSColin Finck 988c2c66affSColin Finck p = sectors + ((num_stripes - 2) * sector_size); 989c2c66affSColin Finck q = sectors + ((num_stripes - 1) * sector_size); 990c2c66affSColin Finck 991c2c66affSColin Finck for (j = 0; j < sector_size; j++) { 992c2c66affSColin Finck *qxy = gmul(a, *p ^ *pxy) ^ gmul(b, *q ^ *qxy); 993c2c66affSColin Finck 994c2c66affSColin Finck p++; 995c2c66affSColin Finck q++; 996c2c66affSColin Finck pxy++; 997c2c66affSColin Finck qxy++; 998c2c66affSColin Finck } 999c2c66affSColin Finck 1000c2c66affSColin Finck do_xor(out + sector_size, out, sector_size); 1001c2c66affSColin Finck do_xor(out + sector_size, sectors + ((num_stripes - 2) * sector_size), sector_size); 1002c2c66affSColin Finck } 1003c2c66affSColin Finck } 1004c2c66affSColin Finck 1005318da0c1SPierre Schweitzer static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uint64_t addr, uint32_t length, read_data_context* context, CHUNK_ITEM* ci, 1006318da0c1SPierre Schweitzer device** devices, uint64_t offset, uint64_t generation, chunk* c, bool degraded) { 1007c2c66affSColin Finck NTSTATUS Status; 1008318da0c1SPierre Schweitzer bool checksum_error = false; 1009c2c66affSColin Finck CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1]; 1010*06042735SVincent Franchomme uint16_t stripe = 0, j; 1011318da0c1SPierre Schweitzer bool no_success = true; 1012c2c66affSColin Finck 1013c2c66affSColin Finck for (j = 0; j < ci->num_stripes; j++) { 1014c2c66affSColin Finck if (context->stripes[j].status == ReadDataStatus_Error) { 1015194ea909SVictor Perevertkin WARN("stripe %u returned error %08lx\n", j, context->stripes[j].iosb.Status); 1016c2c66affSColin Finck 1017c2c66affSColin Finck if (devices[j]) 1018c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); 1019c2c66affSColin Finck return context->stripes[j].iosb.Status; 1020c2c66affSColin Finck } else if (context->stripes[j].status == ReadDataStatus_Success) { 1021c2c66affSColin Finck stripe = j; 1022318da0c1SPierre Schweitzer no_success = false; 1023c2c66affSColin Finck } 1024c2c66affSColin Finck } 1025c2c66affSColin Finck 1026c2c66affSColin Finck if (c) { // check partial stripes 1027c2c66affSColin Finck LIST_ENTRY* le; 1028318da0c1SPierre Schweitzer uint64_t ps_length = (ci->num_stripes - 2) * ci->stripe_length; 1029c2c66affSColin Finck 1030318da0c1SPierre Schweitzer ExAcquireResourceSharedLite(&c->partial_stripes_lock, true); 1031c2c66affSColin Finck 1032c2c66affSColin Finck le = c->partial_stripes.Flink; 1033c2c66affSColin Finck while (le != &c->partial_stripes) { 1034c2c66affSColin Finck partial_stripe* ps = CONTAINING_RECORD(le, partial_stripe, list_entry); 1035c2c66affSColin Finck 1036c2c66affSColin Finck if (ps->address + ps_length > addr && ps->address < addr + length) { 1037c2c66affSColin Finck ULONG runlength, index; 1038c2c66affSColin Finck 1039c2c66affSColin Finck runlength = RtlFindFirstRunClear(&ps->bmp, &index); 1040c2c66affSColin Finck 1041c2c66affSColin Finck while (runlength != 0) { 1042318da0c1SPierre Schweitzer #ifdef __REACTOS__ 1043318da0c1SPierre Schweitzer uint64_t runstart, runend, start, end; 1044318da0c1SPierre Schweitzer #endif 1045318da0c1SPierre Schweitzer if (index >= ps->bmplen) 1046318da0c1SPierre Schweitzer break; 1047318da0c1SPierre Schweitzer 1048318da0c1SPierre Schweitzer if (index + runlength >= ps->bmplen) { 1049318da0c1SPierre Schweitzer runlength = ps->bmplen - index; 1050318da0c1SPierre Schweitzer 1051318da0c1SPierre Schweitzer if (runlength == 0) 1052318da0c1SPierre Schweitzer break; 1053318da0c1SPierre Schweitzer } 1054318da0c1SPierre Schweitzer 1055318da0c1SPierre Schweitzer #ifndef __REACTOS__ 1056174dfab6SVincent Franchomme uint64_t runstart = ps->address + (index << Vcb->sector_shift); 1057174dfab6SVincent Franchomme uint64_t runend = runstart + (runlength << Vcb->sector_shift); 1058318da0c1SPierre Schweitzer uint64_t start = max(runstart, addr); 1059318da0c1SPierre Schweitzer uint64_t end = min(runend, addr + length); 1060318da0c1SPierre Schweitzer #else 1061174dfab6SVincent Franchomme runstart = ps->address + (index * Vcb->sector_shift); 1062174dfab6SVincent Franchomme runend = runstart + (runlength * Vcb->sector_shift); 1063318da0c1SPierre Schweitzer start = max(runstart, addr); 1064318da0c1SPierre Schweitzer end = min(runend, addr + length); 1065318da0c1SPierre Schweitzer #endif 1066c2c66affSColin Finck 1067c2c66affSColin Finck if (end > start) 1068c2c66affSColin Finck RtlCopyMemory(buf + start - addr, &ps->data[start - ps->address], (ULONG)(end - start)); 1069c2c66affSColin Finck 1070c2c66affSColin Finck runlength = RtlFindNextForwardRunClear(&ps->bmp, index + runlength, &index); 1071c2c66affSColin Finck } 1072c2c66affSColin Finck } else if (ps->address >= addr + length) 1073c2c66affSColin Finck break; 1074c2c66affSColin Finck 1075c2c66affSColin Finck le = le->Flink; 1076c2c66affSColin Finck } 1077c2c66affSColin Finck 1078c2c66affSColin Finck ExReleaseResourceLite(&c->partial_stripes_lock); 1079c2c66affSColin Finck } 1080c2c66affSColin Finck 1081c2c66affSColin Finck if (context->tree) { 1082c2c66affSColin Finck tree_header* th = (tree_header*)buf; 1083c2c66affSColin Finck 1084194ea909SVictor Perevertkin if (addr != th->address || !check_tree_checksum(Vcb, th)) { 1085318da0c1SPierre Schweitzer checksum_error = true; 1086c2c66affSColin Finck if (!no_success && !degraded && devices[stripe]) 1087c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 1088c2c66affSColin Finck } else if (generation != 0 && generation != th->generation) { 1089318da0c1SPierre Schweitzer checksum_error = true; 1090c2c66affSColin Finck if (!no_success && !degraded && devices[stripe]) 1091c2c66affSColin Finck log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_GENERATION_ERRORS); 1092c2c66affSColin Finck } 1093c2c66affSColin Finck } else if (context->csum) { 1094174dfab6SVincent Franchomme Status = check_csum(Vcb, buf, length >> Vcb->sector_shift, context->csum); 1095c2c66affSColin Finck 1096c2c66affSColin Finck if (Status == STATUS_CRC_ERROR) { 1097c2c66affSColin Finck if (!degraded) 1098c2c66affSColin Finck WARN("checksum error\n"); 1099318da0c1SPierre Schweitzer checksum_error = true; 1100c2c66affSColin Finck } else if (!NT_SUCCESS(Status)) { 1101194ea909SVictor Perevertkin ERR("check_csum returned %08lx\n", Status); 1102c2c66affSColin Finck return Status; 1103c2c66affSColin Finck } 1104c2c66affSColin Finck } else if (degraded) 1105318da0c1SPierre Schweitzer checksum_error = true; 1106c2c66affSColin Finck 1107c2c66affSColin Finck if (!checksum_error) 1108c2c66affSColin Finck return STATUS_SUCCESS; 1109c2c66affSColin Finck 1110c2c66affSColin Finck if (context->tree) { 1111318da0c1SPierre Schweitzer uint8_t* sector; 1112*06042735SVincent Franchomme uint16_t k, physstripe, parity1, parity2, error_stripe = 0; 1113318da0c1SPierre Schweitzer uint64_t off; 1114318da0c1SPierre Schweitzer bool recovered = false, failed = false; 1115c2c66affSColin Finck ULONG num_errors = 0; 1116c2c66affSColin Finck 1117c2c66affSColin Finck sector = ExAllocatePoolWithTag(NonPagedPool, Vcb->superblock.node_size * (ci->num_stripes + 2), ALLOC_TAG); 1118c2c66affSColin Finck if (!sector) { 1119c2c66affSColin Finck ERR("out of memory\n"); 1120c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 1121c2c66affSColin Finck } 1122c2c66affSColin Finck 1123c2c66affSColin Finck get_raid0_offset(addr - offset, ci->stripe_length, ci->num_stripes - 2, &off, &stripe); 1124c2c66affSColin Finck 1125c2c66affSColin Finck parity1 = (((addr - offset) / ((ci->num_stripes - 2) * ci->stripe_length)) + ci->num_stripes - 2) % ci->num_stripes; 1126c2c66affSColin Finck parity2 = (parity1 + 1) % ci->num_stripes; 1127c2c66affSColin Finck 1128c2c66affSColin Finck physstripe = (parity2 + stripe + 1) % ci->num_stripes; 1129c2c66affSColin Finck 1130c2c66affSColin Finck j = (parity2 + 1) % ci->num_stripes; 1131c2c66affSColin Finck 1132c2c66affSColin Finck for (k = 0; k < ci->num_stripes - 1; k++) { 1133c2c66affSColin Finck if (j != physstripe) { 1134c2c66affSColin Finck if (devices[j] && devices[j]->devobj) { 1135318da0c1SPierre Schweitzer Status = sync_read_phys(devices[j]->devobj, devices[j]->fileobj, cis[j].offset + off, Vcb->superblock.node_size, 1136318da0c1SPierre Schweitzer sector + (k * Vcb->superblock.node_size), false); 1137c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 1138194ea909SVictor Perevertkin ERR("sync_read_phys returned %08lx\n", Status); 1139c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); 1140c2c66affSColin Finck num_errors++; 1141c2c66affSColin Finck error_stripe = k; 1142c2c66affSColin Finck 1143c2c66affSColin Finck if (num_errors > 1) { 1144318da0c1SPierre Schweitzer failed = true; 1145c2c66affSColin Finck break; 1146c2c66affSColin Finck } 1147c2c66affSColin Finck } 1148c2c66affSColin Finck } else { 1149c2c66affSColin Finck num_errors++; 1150c2c66affSColin Finck error_stripe = k; 1151c2c66affSColin Finck 1152c2c66affSColin Finck if (num_errors > 1) { 1153318da0c1SPierre Schweitzer failed = true; 1154c2c66affSColin Finck break; 1155c2c66affSColin Finck } 1156c2c66affSColin Finck } 1157c2c66affSColin Finck } 1158c2c66affSColin Finck 1159c2c66affSColin Finck j = (j + 1) % ci->num_stripes; 1160c2c66affSColin Finck } 1161c2c66affSColin Finck 1162c2c66affSColin Finck if (!failed) { 1163c2c66affSColin Finck if (num_errors == 0) { 1164c2c66affSColin Finck tree_header* th = (tree_header*)(sector + (stripe * Vcb->superblock.node_size)); 1165c2c66affSColin Finck 1166c2c66affSColin Finck RtlCopyMemory(sector + (stripe * Vcb->superblock.node_size), sector + ((ci->num_stripes - 2) * Vcb->superblock.node_size), 1167c2c66affSColin Finck Vcb->superblock.node_size); 1168c2c66affSColin Finck 1169c2c66affSColin Finck for (j = 0; j < ci->num_stripes - 2; j++) { 1170c2c66affSColin Finck if (j != stripe) 1171c2c66affSColin Finck do_xor(sector + (stripe * Vcb->superblock.node_size), sector + (j * Vcb->superblock.node_size), Vcb->superblock.node_size); 1172c2c66affSColin Finck } 1173c2c66affSColin Finck 1174194ea909SVictor Perevertkin if (th->address == addr && check_tree_checksum(Vcb, th) && (generation == 0 || th->generation == generation)) { 1175c2c66affSColin Finck RtlCopyMemory(buf, sector + (stripe * Vcb->superblock.node_size), Vcb->superblock.node_size); 1176c2c66affSColin Finck 1177c2c66affSColin Finck if (devices[physstripe] && devices[physstripe]->devobj) 1178318da0c1SPierre Schweitzer ERR("recovering from checksum error at %I64x, device %I64x\n", addr, devices[physstripe]->devitem.dev_id); 1179c2c66affSColin Finck 1180318da0c1SPierre Schweitzer recovered = true; 1181c2c66affSColin Finck 1182c2c66affSColin Finck if (!Vcb->readonly && devices[physstripe] && devices[physstripe]->devobj && !devices[physstripe]->readonly) { // write good data over bad 1183318da0c1SPierre Schweitzer Status = write_data_phys(devices[physstripe]->devobj, devices[physstripe]->fileobj, cis[physstripe].offset + off, 1184c2c66affSColin Finck sector + (stripe * Vcb->superblock.node_size), Vcb->superblock.node_size); 1185c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 1186194ea909SVictor Perevertkin WARN("write_data_phys returned %08lx\n", Status); 1187c2c66affSColin Finck log_device_error(Vcb, devices[physstripe], BTRFS_DEV_STAT_WRITE_ERRORS); 1188c2c66affSColin Finck } 1189c2c66affSColin Finck } 1190c2c66affSColin Finck } 1191c2c66affSColin Finck } 1192c2c66affSColin Finck 1193c2c66affSColin Finck if (!recovered) { 1194c2c66affSColin Finck tree_header* th = (tree_header*)(sector + (ci->num_stripes * Vcb->superblock.node_size)); 1195318da0c1SPierre Schweitzer bool read_q = false; 1196c2c66affSColin Finck 1197c2c66affSColin Finck if (devices[parity2] && devices[parity2]->devobj) { 1198318da0c1SPierre Schweitzer Status = sync_read_phys(devices[parity2]->devobj, devices[parity2]->fileobj, cis[parity2].offset + off, 1199318da0c1SPierre Schweitzer Vcb->superblock.node_size, sector + ((ci->num_stripes - 1) * Vcb->superblock.node_size), false); 1200c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 1201194ea909SVictor Perevertkin ERR("sync_read_phys returned %08lx\n", Status); 1202c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); 1203c2c66affSColin Finck } else 1204318da0c1SPierre Schweitzer read_q = true; 1205c2c66affSColin Finck } 1206c2c66affSColin Finck 1207c2c66affSColin Finck if (read_q) { 1208c2c66affSColin Finck if (num_errors == 1) { 1209c2c66affSColin Finck raid6_recover2(sector, ci->num_stripes, Vcb->superblock.node_size, stripe, error_stripe, sector + (ci->num_stripes * Vcb->superblock.node_size)); 1210c2c66affSColin Finck 1211194ea909SVictor Perevertkin if (th->address == addr && check_tree_checksum(Vcb, th) && (generation == 0 || th->generation == generation)) 1212318da0c1SPierre Schweitzer recovered = true; 1213c2c66affSColin Finck } else { 1214c2c66affSColin Finck for (j = 0; j < ci->num_stripes - 1; j++) { 1215c2c66affSColin Finck if (j != stripe) { 1216c2c66affSColin Finck raid6_recover2(sector, ci->num_stripes, Vcb->superblock.node_size, stripe, j, sector + (ci->num_stripes * Vcb->superblock.node_size)); 1217c2c66affSColin Finck 1218194ea909SVictor Perevertkin if (th->address == addr && check_tree_checksum(Vcb, th) && (generation == 0 || th->generation == generation)) { 1219318da0c1SPierre Schweitzer recovered = true; 1220c2c66affSColin Finck error_stripe = j; 1221c2c66affSColin Finck break; 1222c2c66affSColin Finck } 1223c2c66affSColin Finck } 1224c2c66affSColin Finck } 1225c2c66affSColin Finck } 1226c2c66affSColin Finck } 1227c2c66affSColin Finck 1228c2c66affSColin Finck if (recovered) { 1229318da0c1SPierre Schweitzer uint16_t error_stripe_phys = (parity2 + error_stripe + 1) % ci->num_stripes; 1230c2c66affSColin Finck 1231c2c66affSColin Finck if (devices[physstripe] && devices[physstripe]->devobj) 1232318da0c1SPierre Schweitzer ERR("recovering from checksum error at %I64x, device %I64x\n", addr, devices[physstripe]->devitem.dev_id); 1233c2c66affSColin Finck 1234c2c66affSColin Finck RtlCopyMemory(buf, sector + (ci->num_stripes * Vcb->superblock.node_size), Vcb->superblock.node_size); 1235c2c66affSColin Finck 1236c2c66affSColin Finck if (!Vcb->readonly && devices[physstripe] && devices[physstripe]->devobj && !devices[physstripe]->readonly) { // write good data over bad 1237318da0c1SPierre Schweitzer Status = write_data_phys(devices[physstripe]->devobj, devices[physstripe]->fileobj, cis[physstripe].offset + off, 1238c2c66affSColin Finck sector + (ci->num_stripes * Vcb->superblock.node_size), Vcb->superblock.node_size); 1239c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 1240194ea909SVictor Perevertkin WARN("write_data_phys returned %08lx\n", Status); 1241c2c66affSColin Finck log_device_error(Vcb, devices[physstripe], BTRFS_DEV_STAT_WRITE_ERRORS); 1242c2c66affSColin Finck } 1243c2c66affSColin Finck } 1244c2c66affSColin Finck 1245c2c66affSColin Finck if (devices[error_stripe_phys] && devices[error_stripe_phys]->devobj) { 1246c2c66affSColin Finck if (error_stripe == ci->num_stripes - 2) { 1247318da0c1SPierre Schweitzer ERR("recovering from parity error at %I64x, device %I64x\n", addr, devices[error_stripe_phys]->devitem.dev_id); 1248c2c66affSColin Finck 1249c2c66affSColin Finck log_device_error(Vcb, devices[error_stripe_phys], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 1250c2c66affSColin Finck 1251c2c66affSColin Finck RtlZeroMemory(sector + ((ci->num_stripes - 2) * Vcb->superblock.node_size), Vcb->superblock.node_size); 1252c2c66affSColin Finck 1253c2c66affSColin Finck for (j = 0; j < ci->num_stripes - 2; j++) { 1254c2c66affSColin Finck if (j == stripe) { 1255c2c66affSColin Finck do_xor(sector + ((ci->num_stripes - 2) * Vcb->superblock.node_size), sector + (ci->num_stripes * Vcb->superblock.node_size), 1256c2c66affSColin Finck Vcb->superblock.node_size); 1257c2c66affSColin Finck } else { 1258c2c66affSColin Finck do_xor(sector + ((ci->num_stripes - 2) * Vcb->superblock.node_size), sector + (j * Vcb->superblock.node_size), 1259c2c66affSColin Finck Vcb->superblock.node_size); 1260c2c66affSColin Finck } 1261c2c66affSColin Finck } 1262c2c66affSColin Finck } else { 1263318da0c1SPierre Schweitzer ERR("recovering from checksum error at %I64x, device %I64x\n", addr + ((error_stripe - stripe) * ci->stripe_length), 1264c2c66affSColin Finck devices[error_stripe_phys]->devitem.dev_id); 1265c2c66affSColin Finck 1266c2c66affSColin Finck log_device_error(Vcb, devices[error_stripe_phys], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 1267c2c66affSColin Finck 1268c2c66affSColin Finck RtlCopyMemory(sector + (error_stripe * Vcb->superblock.node_size), 1269c2c66affSColin Finck sector + ((ci->num_stripes + 1) * Vcb->superblock.node_size), Vcb->superblock.node_size); 1270c2c66affSColin Finck } 1271c2c66affSColin Finck } 1272c2c66affSColin Finck 1273c2c66affSColin Finck if (!Vcb->readonly && devices[error_stripe_phys] && devices[error_stripe_phys]->devobj && !devices[error_stripe_phys]->readonly) { // write good data over bad 1274318da0c1SPierre Schweitzer Status = write_data_phys(devices[error_stripe_phys]->devobj, devices[error_stripe_phys]->fileobj, cis[error_stripe_phys].offset + off, 1275c2c66affSColin Finck sector + (error_stripe * Vcb->superblock.node_size), Vcb->superblock.node_size); 1276c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 1277194ea909SVictor Perevertkin WARN("write_data_phys returned %08lx\n", Status); 1278c2c66affSColin Finck log_device_error(Vcb, devices[error_stripe_phys], BTRFS_DEV_STAT_WRITE_ERRORS); 1279c2c66affSColin Finck } 1280c2c66affSColin Finck } 1281c2c66affSColin Finck } 1282c2c66affSColin Finck } 1283c2c66affSColin Finck } 1284c2c66affSColin Finck 1285c2c66affSColin Finck if (!recovered) { 1286318da0c1SPierre Schweitzer ERR("unrecoverable checksum error at %I64x\n", addr); 1287c2c66affSColin Finck ExFreePool(sector); 1288c2c66affSColin Finck return STATUS_CRC_ERROR; 1289c2c66affSColin Finck } 1290c2c66affSColin Finck 1291c2c66affSColin Finck ExFreePool(sector); 1292c2c66affSColin Finck } else { 1293174dfab6SVincent Franchomme ULONG sectors = length >> Vcb->sector_shift; 1294318da0c1SPierre Schweitzer uint8_t* sector; 1295194ea909SVictor Perevertkin void* ptr = context->csum; 1296c2c66affSColin Finck 1297174dfab6SVincent Franchomme sector = ExAllocatePoolWithTag(NonPagedPool, (ci->num_stripes + 2) << Vcb->sector_shift, ALLOC_TAG); 1298c2c66affSColin Finck if (!sector) { 1299c2c66affSColin Finck ERR("out of memory\n"); 1300c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 1301c2c66affSColin Finck } 1302c2c66affSColin Finck 1303174dfab6SVincent Franchomme for (ULONG i = 0; i < sectors; i++) { 1304318da0c1SPierre Schweitzer uint64_t off; 1305318da0c1SPierre Schweitzer uint16_t physstripe, parity1, parity2; 1306c2c66affSColin Finck 1307174dfab6SVincent Franchomme get_raid0_offset(addr - offset + ((uint64_t)i << Vcb->sector_shift), ci->stripe_length, 1308c2c66affSColin Finck ci->num_stripes - 2, &off, &stripe); 1309c2c66affSColin Finck 1310174dfab6SVincent Franchomme parity1 = (((addr - offset + ((uint64_t)i << Vcb->sector_shift)) / ((ci->num_stripes - 2) * ci->stripe_length)) + ci->num_stripes - 2) % ci->num_stripes; 1311c2c66affSColin Finck parity2 = (parity1 + 1) % ci->num_stripes; 1312c2c66affSColin Finck 1313c2c66affSColin Finck physstripe = (parity2 + stripe + 1) % ci->num_stripes; 1314c2c66affSColin Finck 1315174dfab6SVincent Franchomme if (!devices[physstripe] || !devices[physstripe]->devobj || (context->csum && !check_sector_csum(Vcb, buf + (i << Vcb->sector_shift), ptr))) { 1316*06042735SVincent Franchomme uint16_t error_stripe = 0; 1317318da0c1SPierre Schweitzer bool recovered = false, failed = false; 1318c2c66affSColin Finck ULONG num_errors = 0; 1319c2c66affSColin Finck 1320c2c66affSColin Finck if (devices[physstripe] && devices[physstripe]->devobj) 1321c2c66affSColin Finck log_device_error(Vcb, devices[physstripe], BTRFS_DEV_STAT_READ_ERRORS); 1322c2c66affSColin Finck 1323c2c66affSColin Finck j = (parity2 + 1) % ci->num_stripes; 1324c2c66affSColin Finck 1325174dfab6SVincent Franchomme for (uint16_t k = 0; k < ci->num_stripes - 1; k++) { 1326c2c66affSColin Finck if (j != physstripe) { 1327c2c66affSColin Finck if (devices[j] && devices[j]->devobj) { 1328318da0c1SPierre Schweitzer Status = sync_read_phys(devices[j]->devobj, devices[j]->fileobj, cis[j].offset + off, Vcb->superblock.sector_size, 1329174dfab6SVincent Franchomme sector + ((ULONG)k << Vcb->sector_shift), false); 1330c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 1331194ea909SVictor Perevertkin ERR("sync_read_phys returned %08lx\n", Status); 1332c2c66affSColin Finck log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); 1333c2c66affSColin Finck num_errors++; 1334c2c66affSColin Finck error_stripe = k; 1335c2c66affSColin Finck 1336c2c66affSColin Finck if (num_errors > 1) { 1337318da0c1SPierre Schweitzer failed = true; 1338c2c66affSColin Finck break; 1339c2c66affSColin Finck } 1340c2c66affSColin Finck } 1341c2c66affSColin Finck } else { 1342c2c66affSColin Finck num_errors++; 1343c2c66affSColin Finck error_stripe = k; 1344c2c66affSColin Finck 1345c2c66affSColin Finck if (num_errors > 1) { 1346318da0c1SPierre Schweitzer failed = true; 1347c2c66affSColin Finck break; 1348c2c66affSColin Finck } 1349c2c66affSColin Finck } 1350c2c66affSColin Finck } 1351c2c66affSColin Finck 1352c2c66affSColin Finck j = (j + 1) % ci->num_stripes; 1353c2c66affSColin Finck } 1354c2c66affSColin Finck 1355c2c66affSColin Finck if (!failed) { 1356c2c66affSColin Finck if (num_errors == 0) { 1357174dfab6SVincent Franchomme RtlCopyMemory(sector + ((unsigned int)stripe << Vcb->sector_shift), sector + ((unsigned int)(ci->num_stripes - 2) << Vcb->sector_shift), Vcb->superblock.sector_size); 1358c2c66affSColin Finck 1359c2c66affSColin Finck for (j = 0; j < ci->num_stripes - 2; j++) { 1360c2c66affSColin Finck if (j != stripe) 1361174dfab6SVincent Franchomme do_xor(sector + ((unsigned int)stripe << Vcb->sector_shift), sector + ((unsigned int)j << Vcb->sector_shift), Vcb->superblock.sector_size); 1362c2c66affSColin Finck } 1363c2c66affSColin Finck 1364174dfab6SVincent Franchomme if (!ptr || check_sector_csum(Vcb, sector + ((unsigned int)stripe << Vcb->sector_shift), ptr)) { 1365174dfab6SVincent Franchomme RtlCopyMemory(buf + (i << Vcb->sector_shift), sector + ((unsigned int)stripe << Vcb->sector_shift), Vcb->superblock.sector_size); 1366c2c66affSColin Finck 1367c2c66affSColin Finck if (devices[physstripe] && devices[physstripe]->devobj) 1368174dfab6SVincent Franchomme ERR("recovering from checksum error at %I64x, device %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift), 1369c2c66affSColin Finck devices[physstripe]->devitem.dev_id); 1370c2c66affSColin Finck 1371318da0c1SPierre Schweitzer recovered = true; 1372c2c66affSColin Finck 1373c2c66affSColin Finck if (!Vcb->readonly && devices[physstripe] && devices[physstripe]->devobj && !devices[physstripe]->readonly) { // write good data over bad 1374318da0c1SPierre Schweitzer Status = write_data_phys(devices[physstripe]->devobj, devices[physstripe]->fileobj, cis[physstripe].offset + off, 1375174dfab6SVincent Franchomme sector + ((unsigned int)stripe << Vcb->sector_shift), Vcb->superblock.sector_size); 1376c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 1377194ea909SVictor Perevertkin WARN("write_data_phys returned %08lx\n", Status); 1378c2c66affSColin Finck log_device_error(Vcb, devices[physstripe], BTRFS_DEV_STAT_WRITE_ERRORS); 1379c2c66affSColin Finck } 1380c2c66affSColin Finck } 1381c2c66affSColin Finck } 1382c2c66affSColin Finck } 1383c2c66affSColin Finck 1384c2c66affSColin Finck if (!recovered) { 1385318da0c1SPierre Schweitzer bool read_q = false; 1386c2c66affSColin Finck 1387c2c66affSColin Finck if (devices[parity2] && devices[parity2]->devobj) { 1388318da0c1SPierre Schweitzer Status = sync_read_phys(devices[parity2]->devobj, devices[parity2]->fileobj, cis[parity2].offset + off, 1389174dfab6SVincent Franchomme Vcb->superblock.sector_size, sector + ((unsigned int)(ci->num_stripes - 1) << Vcb->sector_shift), false); 1390c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 1391194ea909SVictor Perevertkin ERR("sync_read_phys returned %08lx\n", Status); 1392c2c66affSColin Finck log_device_error(Vcb, devices[parity2], BTRFS_DEV_STAT_READ_ERRORS); 1393c2c66affSColin Finck } else 1394318da0c1SPierre Schweitzer read_q = true; 1395c2c66affSColin Finck } 1396c2c66affSColin Finck 1397c2c66affSColin Finck if (read_q) { 1398c2c66affSColin Finck if (num_errors == 1) { 1399174dfab6SVincent Franchomme raid6_recover2(sector, ci->num_stripes, Vcb->superblock.sector_size, stripe, error_stripe, sector + ((unsigned int)ci->num_stripes << Vcb->sector_shift)); 1400c2c66affSColin Finck 1401c2c66affSColin Finck if (!devices[physstripe] || !devices[physstripe]->devobj) 1402318da0c1SPierre Schweitzer recovered = true; 1403194ea909SVictor Perevertkin else 1404174dfab6SVincent Franchomme recovered = check_sector_csum(Vcb, sector + ((unsigned int)ci->num_stripes << Vcb->sector_shift), ptr); 1405c2c66affSColin Finck } else { 1406c2c66affSColin Finck for (j = 0; j < ci->num_stripes - 1; j++) { 1407c2c66affSColin Finck if (j != stripe) { 1408174dfab6SVincent Franchomme raid6_recover2(sector, ci->num_stripes, Vcb->superblock.sector_size, stripe, j, sector + ((unsigned int)ci->num_stripes << Vcb->sector_shift)); 1409c2c66affSColin Finck 1410174dfab6SVincent Franchomme if (check_sector_csum(Vcb, sector + ((unsigned int)ci->num_stripes << Vcb->sector_shift), ptr)) { 1411318da0c1SPierre Schweitzer recovered = true; 1412c2c66affSColin Finck error_stripe = j; 1413c2c66affSColin Finck break; 1414c2c66affSColin Finck } 1415c2c66affSColin Finck } 1416c2c66affSColin Finck } 1417c2c66affSColin Finck } 1418c2c66affSColin Finck } 1419c2c66affSColin Finck 1420c2c66affSColin Finck if (recovered) { 1421318da0c1SPierre Schweitzer uint16_t error_stripe_phys = (parity2 + error_stripe + 1) % ci->num_stripes; 1422c2c66affSColin Finck 1423c2c66affSColin Finck if (devices[physstripe] && devices[physstripe]->devobj) 1424318da0c1SPierre Schweitzer ERR("recovering from checksum error at %I64x, device %I64x\n", 1425174dfab6SVincent Franchomme addr + ((uint64_t)i << Vcb->sector_shift), devices[physstripe]->devitem.dev_id); 1426c2c66affSColin Finck 1427174dfab6SVincent Franchomme RtlCopyMemory(buf + (i << Vcb->sector_shift), sector + ((unsigned int)ci->num_stripes << Vcb->sector_shift), Vcb->superblock.sector_size); 1428c2c66affSColin Finck 1429c2c66affSColin Finck if (!Vcb->readonly && devices[physstripe] && devices[physstripe]->devobj && !devices[physstripe]->readonly) { // write good data over bad 1430318da0c1SPierre Schweitzer Status = write_data_phys(devices[physstripe]->devobj, devices[physstripe]->fileobj, cis[physstripe].offset + off, 1431174dfab6SVincent Franchomme sector + ((unsigned int)ci->num_stripes << Vcb->sector_shift), Vcb->superblock.sector_size); 1432c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 1433194ea909SVictor Perevertkin WARN("write_data_phys returned %08lx\n", Status); 1434c2c66affSColin Finck log_device_error(Vcb, devices[physstripe], BTRFS_DEV_STAT_WRITE_ERRORS); 1435c2c66affSColin Finck } 1436c2c66affSColin Finck } 1437c2c66affSColin Finck 1438c2c66affSColin Finck if (devices[error_stripe_phys] && devices[error_stripe_phys]->devobj) { 1439c2c66affSColin Finck if (error_stripe == ci->num_stripes - 2) { 1440174dfab6SVincent Franchomme ERR("recovering from parity error at %I64x, device %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift), 1441c2c66affSColin Finck devices[error_stripe_phys]->devitem.dev_id); 1442c2c66affSColin Finck 1443c2c66affSColin Finck log_device_error(Vcb, devices[error_stripe_phys], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 1444c2c66affSColin Finck 1445174dfab6SVincent Franchomme RtlZeroMemory(sector + ((unsigned int)(ci->num_stripes - 2) << Vcb->sector_shift), Vcb->superblock.sector_size); 1446c2c66affSColin Finck 1447c2c66affSColin Finck for (j = 0; j < ci->num_stripes - 2; j++) { 1448c2c66affSColin Finck if (j == stripe) { 1449174dfab6SVincent Franchomme do_xor(sector + ((unsigned int)(ci->num_stripes - 2) << Vcb->sector_shift), sector + ((unsigned int)ci->num_stripes << Vcb->sector_shift), 1450c2c66affSColin Finck Vcb->superblock.sector_size); 1451c2c66affSColin Finck } else { 1452174dfab6SVincent Franchomme do_xor(sector + ((unsigned int)(ci->num_stripes - 2) << Vcb->sector_shift), sector + ((unsigned int)j << Vcb->sector_shift), 1453c2c66affSColin Finck Vcb->superblock.sector_size); 1454c2c66affSColin Finck } 1455c2c66affSColin Finck } 1456c2c66affSColin Finck } else { 1457318da0c1SPierre Schweitzer ERR("recovering from checksum error at %I64x, device %I64x\n", 1458174dfab6SVincent Franchomme addr + ((uint64_t)i << Vcb->sector_shift) + ((error_stripe - stripe) * ci->stripe_length), 1459c2c66affSColin Finck devices[error_stripe_phys]->devitem.dev_id); 1460c2c66affSColin Finck 1461c2c66affSColin Finck log_device_error(Vcb, devices[error_stripe_phys], BTRFS_DEV_STAT_CORRUPTION_ERRORS); 1462c2c66affSColin Finck 1463174dfab6SVincent Franchomme RtlCopyMemory(sector + ((unsigned int)error_stripe << Vcb->sector_shift), 1464174dfab6SVincent Franchomme sector + ((unsigned int)(ci->num_stripes + 1) << Vcb->sector_shift), Vcb->superblock.sector_size); 1465c2c66affSColin Finck } 1466c2c66affSColin Finck } 1467c2c66affSColin Finck 1468c2c66affSColin Finck if (!Vcb->readonly && devices[error_stripe_phys] && devices[error_stripe_phys]->devobj && !devices[error_stripe_phys]->readonly) { // write good data over bad 1469318da0c1SPierre Schweitzer Status = write_data_phys(devices[error_stripe_phys]->devobj, devices[error_stripe_phys]->fileobj, cis[error_stripe_phys].offset + off, 1470174dfab6SVincent Franchomme sector + ((unsigned int)error_stripe << Vcb->sector_shift), Vcb->superblock.sector_size); 1471c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 1472194ea909SVictor Perevertkin WARN("write_data_phys returned %08lx\n", Status); 1473c2c66affSColin Finck log_device_error(Vcb, devices[error_stripe_phys], BTRFS_DEV_STAT_WRITE_ERRORS); 1474c2c66affSColin Finck } 1475c2c66affSColin Finck } 1476c2c66affSColin Finck } 1477c2c66affSColin Finck } 1478c2c66affSColin Finck } 1479c2c66affSColin Finck 1480c2c66affSColin Finck if (!recovered) { 1481174dfab6SVincent Franchomme ERR("unrecoverable checksum error at %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift)); 1482c2c66affSColin Finck ExFreePool(sector); 1483c2c66affSColin Finck return STATUS_CRC_ERROR; 1484c2c66affSColin Finck } 1485c2c66affSColin Finck } 1486194ea909SVictor Perevertkin 1487194ea909SVictor Perevertkin if (ptr) 1488194ea909SVictor Perevertkin ptr = (uint8_t*)ptr + Vcb->csum_size; 1489c2c66affSColin Finck } 1490c2c66affSColin Finck 1491c2c66affSColin Finck ExFreePool(sector); 1492c2c66affSColin Finck } 1493c2c66affSColin Finck 1494c2c66affSColin Finck return STATUS_SUCCESS; 1495c2c66affSColin Finck } 1496c2c66affSColin Finck 1497194ea909SVictor Perevertkin NTSTATUS read_data(_In_ device_extension* Vcb, _In_ uint64_t addr, _In_ uint32_t length, _In_reads_bytes_opt_(length*sizeof(uint32_t)/Vcb->superblock.sector_size) void* csum, 1498318da0c1SPierre Schweitzer _In_ bool is_tree, _Out_writes_bytes_(length) uint8_t* buf, _In_opt_ chunk* c, _Out_opt_ chunk** pc, _In_opt_ PIRP Irp, _In_ uint64_t generation, _In_ bool file_read, 1499c2c66affSColin Finck _In_ ULONG priority) { 1500c2c66affSColin Finck CHUNK_ITEM* ci; 1501c2c66affSColin Finck CHUNK_ITEM_STRIPE* cis; 1502c2c66affSColin Finck read_data_context context; 1503318da0c1SPierre Schweitzer uint64_t type, offset, total_reading = 0; 1504c2c66affSColin Finck NTSTATUS Status; 1505c2c66affSColin Finck device** devices = NULL; 1506318da0c1SPierre Schweitzer uint16_t i, startoffstripe, allowed_missing, missing_devices = 0; 1507318da0c1SPierre Schweitzer uint8_t* dummypage = NULL; 1508c2c66affSColin Finck PMDL dummy_mdl = NULL; 1509318da0c1SPierre Schweitzer bool need_to_wait; 1510318da0c1SPierre Schweitzer uint64_t lockaddr, locklen; 1511c2c66affSColin Finck 1512c2c66affSColin Finck if (Vcb->log_to_phys_loaded) { 1513c2c66affSColin Finck if (!c) { 1514c2c66affSColin Finck c = get_chunk_from_address(Vcb, addr); 1515c2c66affSColin Finck 1516c2c66affSColin Finck if (!c) { 1517c2c66affSColin Finck ERR("get_chunk_from_address failed\n"); 1518c2c66affSColin Finck return STATUS_INTERNAL_ERROR; 1519c2c66affSColin Finck } 1520c2c66affSColin Finck } 1521c2c66affSColin Finck 1522c2c66affSColin Finck ci = c->chunk_item; 1523c2c66affSColin Finck offset = c->offset; 1524c2c66affSColin Finck devices = c->devices; 1525c2c66affSColin Finck 1526c2c66affSColin Finck if (pc) 1527c2c66affSColin Finck *pc = c; 1528c2c66affSColin Finck } else { 1529c2c66affSColin Finck LIST_ENTRY* le = Vcb->sys_chunks.Flink; 1530c2c66affSColin Finck 1531c2c66affSColin Finck ci = NULL; 1532c2c66affSColin Finck 1533c2c66affSColin Finck c = NULL; 1534c2c66affSColin Finck while (le != &Vcb->sys_chunks) { 1535c2c66affSColin Finck sys_chunk* sc = CONTAINING_RECORD(le, sys_chunk, list_entry); 1536c2c66affSColin Finck 1537c2c66affSColin Finck if (sc->key.obj_id == 0x100 && sc->key.obj_type == TYPE_CHUNK_ITEM && sc->key.offset <= addr) { 1538c2c66affSColin Finck CHUNK_ITEM* chunk_item = sc->data; 1539c2c66affSColin Finck 1540c2c66affSColin Finck if ((addr - sc->key.offset) < chunk_item->size && chunk_item->num_stripes > 0) { 1541c2c66affSColin Finck ci = chunk_item; 1542c2c66affSColin Finck offset = sc->key.offset; 1543c2c66affSColin Finck cis = (CHUNK_ITEM_STRIPE*)&chunk_item[1]; 1544c2c66affSColin Finck 1545318da0c1SPierre Schweitzer devices = ExAllocatePoolWithTag(NonPagedPool, sizeof(device*) * ci->num_stripes, ALLOC_TAG); 1546c2c66affSColin Finck if (!devices) { 1547c2c66affSColin Finck ERR("out of memory\n"); 1548c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 1549c2c66affSColin Finck } 1550c2c66affSColin Finck 1551c2c66affSColin Finck for (i = 0; i < ci->num_stripes; i++) { 1552c2c66affSColin Finck devices[i] = find_device_from_uuid(Vcb, &cis[i].dev_uuid); 1553c2c66affSColin Finck } 1554c2c66affSColin Finck 1555c2c66affSColin Finck break; 1556c2c66affSColin Finck } 1557c2c66affSColin Finck } 1558c2c66affSColin Finck 1559c2c66affSColin Finck le = le->Flink; 1560c2c66affSColin Finck } 1561c2c66affSColin Finck 1562c2c66affSColin Finck if (!ci) { 1563318da0c1SPierre Schweitzer ERR("could not find chunk for %I64x in bootstrap\n", addr); 1564c2c66affSColin Finck return STATUS_INTERNAL_ERROR; 1565c2c66affSColin Finck } 1566c2c66affSColin Finck 1567c2c66affSColin Finck if (pc) 1568c2c66affSColin Finck *pc = NULL; 1569c2c66affSColin Finck } 1570c2c66affSColin Finck 1571c2c66affSColin Finck if (ci->type & BLOCK_FLAG_DUPLICATE) { 1572c2c66affSColin Finck type = BLOCK_FLAG_DUPLICATE; 1573c2c66affSColin Finck allowed_missing = ci->num_stripes - 1; 1574c2c66affSColin Finck } else if (ci->type & BLOCK_FLAG_RAID0) { 1575c2c66affSColin Finck type = BLOCK_FLAG_RAID0; 1576c2c66affSColin Finck allowed_missing = 0; 1577c2c66affSColin Finck } else if (ci->type & BLOCK_FLAG_RAID1) { 1578c2c66affSColin Finck type = BLOCK_FLAG_DUPLICATE; 1579c2c66affSColin Finck allowed_missing = 1; 1580c2c66affSColin Finck } else if (ci->type & BLOCK_FLAG_RAID10) { 1581c2c66affSColin Finck type = BLOCK_FLAG_RAID10; 1582c2c66affSColin Finck allowed_missing = 1; 1583c2c66affSColin Finck } else if (ci->type & BLOCK_FLAG_RAID5) { 1584c2c66affSColin Finck type = BLOCK_FLAG_RAID5; 1585c2c66affSColin Finck allowed_missing = 1; 1586c2c66affSColin Finck } else if (ci->type & BLOCK_FLAG_RAID6) { 1587c2c66affSColin Finck type = BLOCK_FLAG_RAID6; 1588c2c66affSColin Finck allowed_missing = 2; 1589194ea909SVictor Perevertkin } else if (ci->type & BLOCK_FLAG_RAID1C3) { 1590194ea909SVictor Perevertkin type = BLOCK_FLAG_DUPLICATE; 1591194ea909SVictor Perevertkin allowed_missing = 2; 1592194ea909SVictor Perevertkin } else if (ci->type & BLOCK_FLAG_RAID1C4) { 1593194ea909SVictor Perevertkin type = BLOCK_FLAG_DUPLICATE; 1594194ea909SVictor Perevertkin allowed_missing = 3; 1595c2c66affSColin Finck } else { // SINGLE 1596c2c66affSColin Finck type = BLOCK_FLAG_DUPLICATE; 1597c2c66affSColin Finck allowed_missing = 0; 1598c2c66affSColin Finck } 1599c2c66affSColin Finck 1600c2c66affSColin Finck cis = (CHUNK_ITEM_STRIPE*)&ci[1]; 1601c2c66affSColin Finck 1602c2c66affSColin Finck RtlZeroMemory(&context, sizeof(read_data_context)); 1603318da0c1SPierre Schweitzer KeInitializeEvent(&context.Event, NotificationEvent, false); 1604c2c66affSColin Finck 1605c2c66affSColin Finck context.stripes = ExAllocatePoolWithTag(NonPagedPool, sizeof(read_data_stripe) * ci->num_stripes, ALLOC_TAG); 1606c2c66affSColin Finck if (!context.stripes) { 1607c2c66affSColin Finck ERR("out of memory\n"); 1608c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 1609c2c66affSColin Finck } 1610c2c66affSColin Finck 1611c2c66affSColin Finck if (c && (type == BLOCK_FLAG_RAID5 || type == BLOCK_FLAG_RAID6)) { 1612c2c66affSColin Finck get_raid56_lock_range(c, addr, length, &lockaddr, &locklen); 1613c2c66affSColin Finck chunk_lock_range(Vcb, c, lockaddr, locklen); 1614c2c66affSColin Finck } 1615c2c66affSColin Finck 1616c2c66affSColin Finck RtlZeroMemory(context.stripes, sizeof(read_data_stripe) * ci->num_stripes); 1617c2c66affSColin Finck 1618c2c66affSColin Finck context.buflen = length; 1619c2c66affSColin Finck context.num_stripes = ci->num_stripes; 1620c2c66affSColin Finck context.stripes_left = context.num_stripes; 1621c2c66affSColin Finck context.sector_size = Vcb->superblock.sector_size; 1622c2c66affSColin Finck context.csum = csum; 1623c2c66affSColin Finck context.tree = is_tree; 1624c2c66affSColin Finck context.type = type; 1625c2c66affSColin Finck 1626c2c66affSColin Finck if (type == BLOCK_FLAG_RAID0) { 1627318da0c1SPierre Schweitzer uint64_t startoff, endoff; 1628318da0c1SPierre Schweitzer uint16_t endoffstripe, stripe; 1629318da0c1SPierre Schweitzer uint32_t *stripeoff, pos; 1630c2c66affSColin Finck PMDL master_mdl; 1631c2c66affSColin Finck PFN_NUMBER* pfns; 1632c2c66affSColin Finck 1633c2c66affSColin Finck // FIXME - test this still works if page size isn't the same as sector size 1634c2c66affSColin Finck 1635c2c66affSColin Finck // This relies on the fact that MDLs are followed in memory by the page file numbers, 1636c2c66affSColin Finck // so with a bit of jiggery-pokery you can trick your disks into deinterlacing your RAID0 1637c2c66affSColin Finck // data for you without doing a memcpy yourself. 1638c2c66affSColin Finck // MDLs are officially opaque, so this might very well break in future versions of Windows. 1639c2c66affSColin Finck 1640c2c66affSColin Finck get_raid0_offset(addr - offset, ci->stripe_length, ci->num_stripes, &startoff, &startoffstripe); 1641c2c66affSColin Finck get_raid0_offset(addr + length - offset - 1, ci->stripe_length, ci->num_stripes, &endoff, &endoffstripe); 1642c2c66affSColin Finck 1643c2c66affSColin Finck if (file_read) { 1644c2c66affSColin Finck // Unfortunately we can't avoid doing at least one memcpy, as Windows can give us an MDL 1645c2c66affSColin Finck // with duplicated dummy PFNs, which confuse check_csum. Ah well. 1646c2c66affSColin Finck // See https://msdn.microsoft.com/en-us/library/windows/hardware/Dn614012.aspx if you're interested. 1647c2c66affSColin Finck 1648c2c66affSColin Finck context.va = ExAllocatePoolWithTag(NonPagedPool, length, ALLOC_TAG); 1649c2c66affSColin Finck 1650c2c66affSColin Finck if (!context.va) { 1651c2c66affSColin Finck ERR("out of memory\n"); 1652c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 1653c2c66affSColin Finck goto exit; 1654c2c66affSColin Finck } 1655c2c66affSColin Finck } else 1656c2c66affSColin Finck context.va = buf; 1657c2c66affSColin Finck 1658318da0c1SPierre Schweitzer master_mdl = IoAllocateMdl(context.va, length, false, false, NULL); 1659c2c66affSColin Finck if (!master_mdl) { 1660c2c66affSColin Finck ERR("out of memory\n"); 1661c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 1662c2c66affSColin Finck goto exit; 1663c2c66affSColin Finck } 1664c2c66affSColin Finck 1665c2c66affSColin Finck Status = STATUS_SUCCESS; 1666c2c66affSColin Finck 1667c2c66affSColin Finck _SEH2_TRY { 1668c2c66affSColin Finck MmProbeAndLockPages(master_mdl, KernelMode, IoWriteAccess); 1669c2c66affSColin Finck } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 1670c2c66affSColin Finck Status = _SEH2_GetExceptionCode(); 1671c2c66affSColin Finck } _SEH2_END; 1672c2c66affSColin Finck 1673c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 1674194ea909SVictor Perevertkin ERR("MmProbeAndLockPages threw exception %08lx\n", Status); 1675c2c66affSColin Finck IoFreeMdl(master_mdl); 1676c2c66affSColin Finck goto exit; 1677c2c66affSColin Finck } 1678c2c66affSColin Finck 1679c2c66affSColin Finck pfns = (PFN_NUMBER*)(master_mdl + 1); 1680c2c66affSColin Finck 1681c2c66affSColin Finck for (i = 0; i < ci->num_stripes; i++) { 1682c2c66affSColin Finck if (startoffstripe > i) 1683c2c66affSColin Finck context.stripes[i].stripestart = startoff - (startoff % ci->stripe_length) + ci->stripe_length; 1684c2c66affSColin Finck else if (startoffstripe == i) 1685c2c66affSColin Finck context.stripes[i].stripestart = startoff; 1686c2c66affSColin Finck else 1687c2c66affSColin Finck context.stripes[i].stripestart = startoff - (startoff % ci->stripe_length); 1688c2c66affSColin Finck 1689c2c66affSColin Finck if (endoffstripe > i) 1690c2c66affSColin Finck context.stripes[i].stripeend = endoff - (endoff % ci->stripe_length) + ci->stripe_length; 1691c2c66affSColin Finck else if (endoffstripe == i) 1692c2c66affSColin Finck context.stripes[i].stripeend = endoff + 1; 1693c2c66affSColin Finck else 1694c2c66affSColin Finck context.stripes[i].stripeend = endoff - (endoff % ci->stripe_length); 1695c2c66affSColin Finck 1696c2c66affSColin Finck if (context.stripes[i].stripestart != context.stripes[i].stripeend) { 1697318da0c1SPierre Schweitzer context.stripes[i].mdl = IoAllocateMdl(context.va, (ULONG)(context.stripes[i].stripeend - context.stripes[i].stripestart), false, false, NULL); 1698c2c66affSColin Finck 1699c2c66affSColin Finck if (!context.stripes[i].mdl) { 1700c2c66affSColin Finck ERR("IoAllocateMdl failed\n"); 1701eb7fbc25SPierre Schweitzer MmUnlockPages(master_mdl); 1702eb7fbc25SPierre Schweitzer IoFreeMdl(master_mdl); 1703c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 1704c2c66affSColin Finck goto exit; 1705c2c66affSColin Finck } 1706c2c66affSColin Finck } 1707c2c66affSColin Finck } 1708c2c66affSColin Finck 1709318da0c1SPierre Schweitzer stripeoff = ExAllocatePoolWithTag(NonPagedPool, sizeof(uint32_t) * ci->num_stripes, ALLOC_TAG); 1710c2c66affSColin Finck if (!stripeoff) { 1711c2c66affSColin Finck ERR("out of memory\n"); 1712eb7fbc25SPierre Schweitzer MmUnlockPages(master_mdl); 1713eb7fbc25SPierre Schweitzer IoFreeMdl(master_mdl); 1714c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 1715c2c66affSColin Finck goto exit; 1716c2c66affSColin Finck } 1717c2c66affSColin Finck 1718318da0c1SPierre Schweitzer RtlZeroMemory(stripeoff, sizeof(uint32_t) * ci->num_stripes); 1719c2c66affSColin Finck 1720c2c66affSColin Finck pos = 0; 1721c2c66affSColin Finck stripe = startoffstripe; 1722c2c66affSColin Finck while (pos < length) { 1723c2c66affSColin Finck PFN_NUMBER* stripe_pfns = (PFN_NUMBER*)(context.stripes[stripe].mdl + 1); 1724c2c66affSColin Finck 1725c2c66affSColin Finck if (pos == 0) { 1726318da0c1SPierre Schweitzer uint32_t readlen = (uint32_t)min(context.stripes[stripe].stripeend - context.stripes[stripe].stripestart, ci->stripe_length - (context.stripes[stripe].stripestart % ci->stripe_length)); 1727c2c66affSColin Finck 1728c2c66affSColin Finck RtlCopyMemory(stripe_pfns, pfns, readlen * sizeof(PFN_NUMBER) >> PAGE_SHIFT); 1729c2c66affSColin Finck 1730c2c66affSColin Finck stripeoff[stripe] += readlen; 1731c2c66affSColin Finck pos += readlen; 1732c2c66affSColin Finck } else if (length - pos < ci->stripe_length) { 1733c2c66affSColin Finck RtlCopyMemory(&stripe_pfns[stripeoff[stripe] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], (length - pos) * sizeof(PFN_NUMBER) >> PAGE_SHIFT); 1734c2c66affSColin Finck 1735c2c66affSColin Finck pos = length; 1736c2c66affSColin Finck } else { 1737c2c66affSColin Finck RtlCopyMemory(&stripe_pfns[stripeoff[stripe] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], (ULONG)(ci->stripe_length * sizeof(PFN_NUMBER) >> PAGE_SHIFT)); 1738c2c66affSColin Finck 1739318da0c1SPierre Schweitzer stripeoff[stripe] += (uint32_t)ci->stripe_length; 1740318da0c1SPierre Schweitzer pos += (uint32_t)ci->stripe_length; 1741c2c66affSColin Finck } 1742c2c66affSColin Finck 1743c2c66affSColin Finck stripe = (stripe + 1) % ci->num_stripes; 1744c2c66affSColin Finck } 1745c2c66affSColin Finck 1746c2c66affSColin Finck MmUnlockPages(master_mdl); 1747c2c66affSColin Finck IoFreeMdl(master_mdl); 1748c2c66affSColin Finck 1749c2c66affSColin Finck ExFreePool(stripeoff); 1750c2c66affSColin Finck } else if (type == BLOCK_FLAG_RAID10) { 1751318da0c1SPierre Schweitzer uint64_t startoff, endoff; 1752318da0c1SPierre Schweitzer uint16_t endoffstripe, j, stripe; 1753c2c66affSColin Finck ULONG orig_ls; 1754c2c66affSColin Finck PMDL master_mdl; 1755c2c66affSColin Finck PFN_NUMBER* pfns; 1756318da0c1SPierre Schweitzer uint32_t* stripeoff, pos; 1757c2c66affSColin Finck read_data_stripe** stripes; 1758c2c66affSColin Finck 1759c2c66affSColin Finck if (c) 1760c2c66affSColin Finck orig_ls = c->last_stripe; 1761c2c66affSColin Finck else 1762c2c66affSColin Finck orig_ls = 0; 1763c2c66affSColin Finck 1764c2c66affSColin Finck get_raid0_offset(addr - offset, ci->stripe_length, ci->num_stripes / ci->sub_stripes, &startoff, &startoffstripe); 1765c2c66affSColin Finck get_raid0_offset(addr + length - offset - 1, ci->stripe_length, ci->num_stripes / ci->sub_stripes, &endoff, &endoffstripe); 1766c2c66affSColin Finck 1767c2c66affSColin Finck if ((ci->num_stripes % ci->sub_stripes) != 0) { 1768318da0c1SPierre Schweitzer ERR("chunk %I64x: num_stripes %x was not a multiple of sub_stripes %x!\n", offset, ci->num_stripes, ci->sub_stripes); 1769c2c66affSColin Finck Status = STATUS_INTERNAL_ERROR; 1770c2c66affSColin Finck goto exit; 1771c2c66affSColin Finck } 1772c2c66affSColin Finck 1773c2c66affSColin Finck if (file_read) { 1774c2c66affSColin Finck context.va = ExAllocatePoolWithTag(NonPagedPool, length, ALLOC_TAG); 1775c2c66affSColin Finck 1776c2c66affSColin Finck if (!context.va) { 1777c2c66affSColin Finck ERR("out of memory\n"); 1778c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 1779c2c66affSColin Finck goto exit; 1780c2c66affSColin Finck } 1781c2c66affSColin Finck } else 1782c2c66affSColin Finck context.va = buf; 1783c2c66affSColin Finck 1784174dfab6SVincent Franchomme context.firstoff = (uint16_t)((startoff % ci->stripe_length) >> Vcb->sector_shift); 1785c2c66affSColin Finck context.startoffstripe = startoffstripe; 1786174dfab6SVincent Franchomme context.sectors_per_stripe = (uint16_t)(ci->stripe_length >> Vcb->sector_shift); 1787c2c66affSColin Finck 1788c2c66affSColin Finck startoffstripe *= ci->sub_stripes; 1789c2c66affSColin Finck endoffstripe *= ci->sub_stripes; 1790c2c66affSColin Finck 1791c2c66affSColin Finck if (c) 1792c2c66affSColin Finck c->last_stripe = (orig_ls + 1) % ci->sub_stripes; 1793c2c66affSColin Finck 1794318da0c1SPierre Schweitzer master_mdl = IoAllocateMdl(context.va, length, false, false, NULL); 1795c2c66affSColin Finck if (!master_mdl) { 1796c2c66affSColin Finck ERR("out of memory\n"); 1797c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 1798c2c66affSColin Finck goto exit; 1799c2c66affSColin Finck } 1800c2c66affSColin Finck 1801c2c66affSColin Finck Status = STATUS_SUCCESS; 1802c2c66affSColin Finck 1803c2c66affSColin Finck _SEH2_TRY { 1804c2c66affSColin Finck MmProbeAndLockPages(master_mdl, KernelMode, IoWriteAccess); 1805c2c66affSColin Finck } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 1806c2c66affSColin Finck Status = _SEH2_GetExceptionCode(); 1807c2c66affSColin Finck } _SEH2_END; 1808c2c66affSColin Finck 1809c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 1810194ea909SVictor Perevertkin ERR("MmProbeAndLockPages threw exception %08lx\n", Status); 1811c2c66affSColin Finck IoFreeMdl(master_mdl); 1812c2c66affSColin Finck goto exit; 1813c2c66affSColin Finck } 1814c2c66affSColin Finck 1815c2c66affSColin Finck pfns = (PFN_NUMBER*)(master_mdl + 1); 1816c2c66affSColin Finck 1817c2c66affSColin Finck stripes = ExAllocatePoolWithTag(NonPagedPool, sizeof(read_data_stripe*) * ci->num_stripes / ci->sub_stripes, ALLOC_TAG); 1818c2c66affSColin Finck if (!stripes) { 1819c2c66affSColin Finck ERR("out of memory\n"); 1820eb7fbc25SPierre Schweitzer MmUnlockPages(master_mdl); 1821eb7fbc25SPierre Schweitzer IoFreeMdl(master_mdl); 1822c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 1823c2c66affSColin Finck goto exit; 1824c2c66affSColin Finck } 1825c2c66affSColin Finck 1826c2c66affSColin Finck RtlZeroMemory(stripes, sizeof(read_data_stripe*) * ci->num_stripes / ci->sub_stripes); 1827c2c66affSColin Finck 1828c2c66affSColin Finck for (i = 0; i < ci->num_stripes; i += ci->sub_stripes) { 1829318da0c1SPierre Schweitzer uint64_t sstart, send; 1830318da0c1SPierre Schweitzer bool stripeset = false; 1831c2c66affSColin Finck 1832c2c66affSColin Finck if (startoffstripe > i) 1833c2c66affSColin Finck sstart = startoff - (startoff % ci->stripe_length) + ci->stripe_length; 1834c2c66affSColin Finck else if (startoffstripe == i) 1835c2c66affSColin Finck sstart = startoff; 1836c2c66affSColin Finck else 1837c2c66affSColin Finck sstart = startoff - (startoff % ci->stripe_length); 1838c2c66affSColin Finck 1839c2c66affSColin Finck if (endoffstripe > i) 1840c2c66affSColin Finck send = endoff - (endoff % ci->stripe_length) + ci->stripe_length; 1841c2c66affSColin Finck else if (endoffstripe == i) 1842c2c66affSColin Finck send = endoff + 1; 1843c2c66affSColin Finck else 1844c2c66affSColin Finck send = endoff - (endoff % ci->stripe_length); 1845c2c66affSColin Finck 1846c2c66affSColin Finck for (j = 0; j < ci->sub_stripes; j++) { 1847c2c66affSColin Finck if (j == orig_ls && devices[i+j] && devices[i+j]->devobj) { 1848c2c66affSColin Finck context.stripes[i+j].stripestart = sstart; 1849c2c66affSColin Finck context.stripes[i+j].stripeend = send; 1850c2c66affSColin Finck stripes[i / ci->sub_stripes] = &context.stripes[i+j]; 1851c2c66affSColin Finck 1852c2c66affSColin Finck if (sstart != send) { 1853318da0c1SPierre Schweitzer context.stripes[i+j].mdl = IoAllocateMdl(context.va, (ULONG)(send - sstart), false, false, NULL); 1854c2c66affSColin Finck 1855c2c66affSColin Finck if (!context.stripes[i+j].mdl) { 1856c2c66affSColin Finck ERR("IoAllocateMdl failed\n"); 1857eb7fbc25SPierre Schweitzer MmUnlockPages(master_mdl); 1858eb7fbc25SPierre Schweitzer IoFreeMdl(master_mdl); 1859c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 1860c2c66affSColin Finck goto exit; 1861c2c66affSColin Finck } 1862c2c66affSColin Finck } 1863c2c66affSColin Finck 1864318da0c1SPierre Schweitzer stripeset = true; 1865c2c66affSColin Finck } else 1866c2c66affSColin Finck context.stripes[i+j].status = ReadDataStatus_Skip; 1867c2c66affSColin Finck } 1868c2c66affSColin Finck 1869c2c66affSColin Finck if (!stripeset) { 1870c2c66affSColin Finck for (j = 0; j < ci->sub_stripes; j++) { 1871c2c66affSColin Finck if (devices[i+j] && devices[i+j]->devobj) { 1872c2c66affSColin Finck context.stripes[i+j].stripestart = sstart; 1873c2c66affSColin Finck context.stripes[i+j].stripeend = send; 1874c2c66affSColin Finck context.stripes[i+j].status = ReadDataStatus_Pending; 1875c2c66affSColin Finck stripes[i / ci->sub_stripes] = &context.stripes[i+j]; 1876c2c66affSColin Finck 1877c2c66affSColin Finck if (sstart != send) { 1878318da0c1SPierre Schweitzer context.stripes[i+j].mdl = IoAllocateMdl(context.va, (ULONG)(send - sstart), false, false, NULL); 1879c2c66affSColin Finck 1880c2c66affSColin Finck if (!context.stripes[i+j].mdl) { 1881c2c66affSColin Finck ERR("IoAllocateMdl failed\n"); 1882eb7fbc25SPierre Schweitzer MmUnlockPages(master_mdl); 1883eb7fbc25SPierre Schweitzer IoFreeMdl(master_mdl); 1884c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 1885c2c66affSColin Finck goto exit; 1886c2c66affSColin Finck } 1887c2c66affSColin Finck } 1888c2c66affSColin Finck 1889318da0c1SPierre Schweitzer stripeset = true; 1890c2c66affSColin Finck break; 1891c2c66affSColin Finck } 1892c2c66affSColin Finck } 1893c2c66affSColin Finck 1894c2c66affSColin Finck if (!stripeset) { 1895c2c66affSColin Finck ERR("could not find stripe to read\n"); 1896c2c66affSColin Finck Status = STATUS_DEVICE_NOT_READY; 1897c2c66affSColin Finck goto exit; 1898c2c66affSColin Finck } 1899c2c66affSColin Finck } 1900c2c66affSColin Finck } 1901c2c66affSColin Finck 1902318da0c1SPierre Schweitzer stripeoff = ExAllocatePoolWithTag(NonPagedPool, sizeof(uint32_t) * ci->num_stripes / ci->sub_stripes, ALLOC_TAG); 1903c2c66affSColin Finck if (!stripeoff) { 1904c2c66affSColin Finck ERR("out of memory\n"); 1905eb7fbc25SPierre Schweitzer MmUnlockPages(master_mdl); 1906eb7fbc25SPierre Schweitzer IoFreeMdl(master_mdl); 1907c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 1908c2c66affSColin Finck goto exit; 1909c2c66affSColin Finck } 1910c2c66affSColin Finck 1911318da0c1SPierre Schweitzer RtlZeroMemory(stripeoff, sizeof(uint32_t) * ci->num_stripes / ci->sub_stripes); 1912c2c66affSColin Finck 1913c2c66affSColin Finck pos = 0; 1914c2c66affSColin Finck stripe = startoffstripe / ci->sub_stripes; 1915c2c66affSColin Finck while (pos < length) { 1916c2c66affSColin Finck PFN_NUMBER* stripe_pfns = (PFN_NUMBER*)(stripes[stripe]->mdl + 1); 1917c2c66affSColin Finck 1918c2c66affSColin Finck if (pos == 0) { 1919318da0c1SPierre Schweitzer uint32_t readlen = (uint32_t)min(stripes[stripe]->stripeend - stripes[stripe]->stripestart, 1920c2c66affSColin Finck ci->stripe_length - (stripes[stripe]->stripestart % ci->stripe_length)); 1921c2c66affSColin Finck 1922c2c66affSColin Finck RtlCopyMemory(stripe_pfns, pfns, readlen * sizeof(PFN_NUMBER) >> PAGE_SHIFT); 1923c2c66affSColin Finck 1924c2c66affSColin Finck stripeoff[stripe] += readlen; 1925c2c66affSColin Finck pos += readlen; 1926c2c66affSColin Finck } else if (length - pos < ci->stripe_length) { 1927c2c66affSColin Finck RtlCopyMemory(&stripe_pfns[stripeoff[stripe] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], (length - pos) * sizeof(PFN_NUMBER) >> PAGE_SHIFT); 1928c2c66affSColin Finck 1929c2c66affSColin Finck pos = length; 1930c2c66affSColin Finck } else { 1931c2c66affSColin Finck RtlCopyMemory(&stripe_pfns[stripeoff[stripe] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], (ULONG)(ci->stripe_length * sizeof(PFN_NUMBER) >> PAGE_SHIFT)); 1932c2c66affSColin Finck 1933c2c66affSColin Finck stripeoff[stripe] += (ULONG)ci->stripe_length; 1934c2c66affSColin Finck pos += (ULONG)ci->stripe_length; 1935c2c66affSColin Finck } 1936c2c66affSColin Finck 1937c2c66affSColin Finck stripe = (stripe + 1) % (ci->num_stripes / ci->sub_stripes); 1938c2c66affSColin Finck } 1939c2c66affSColin Finck 1940c2c66affSColin Finck MmUnlockPages(master_mdl); 1941c2c66affSColin Finck IoFreeMdl(master_mdl); 1942c2c66affSColin Finck 1943c2c66affSColin Finck ExFreePool(stripeoff); 1944c2c66affSColin Finck ExFreePool(stripes); 1945c2c66affSColin Finck } else if (type == BLOCK_FLAG_DUPLICATE) { 1946318da0c1SPierre Schweitzer uint64_t orig_ls; 1947c2c66affSColin Finck 1948c2c66affSColin Finck if (c) 1949c2c66affSColin Finck orig_ls = i = c->last_stripe; 1950c2c66affSColin Finck else 1951c2c66affSColin Finck orig_ls = i = 0; 1952c2c66affSColin Finck 1953c2c66affSColin Finck while (!devices[i] || !devices[i]->devobj) { 1954c2c66affSColin Finck i = (i + 1) % ci->num_stripes; 1955c2c66affSColin Finck 1956c2c66affSColin Finck if (i == orig_ls) { 1957c2c66affSColin Finck ERR("no devices available to service request\n"); 1958c2c66affSColin Finck Status = STATUS_DEVICE_NOT_READY; 1959c2c66affSColin Finck goto exit; 1960c2c66affSColin Finck } 1961c2c66affSColin Finck } 1962c2c66affSColin Finck 1963c2c66affSColin Finck if (c) 1964c2c66affSColin Finck c->last_stripe = (i + 1) % ci->num_stripes; 1965c2c66affSColin Finck 1966c2c66affSColin Finck context.stripes[i].stripestart = addr - offset; 1967c2c66affSColin Finck context.stripes[i].stripeend = context.stripes[i].stripestart + length; 1968c2c66affSColin Finck 1969c2c66affSColin Finck if (file_read) { 1970c2c66affSColin Finck context.va = ExAllocatePoolWithTag(NonPagedPool, length, ALLOC_TAG); 1971c2c66affSColin Finck 1972c2c66affSColin Finck if (!context.va) { 1973c2c66affSColin Finck ERR("out of memory\n"); 1974c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 1975c2c66affSColin Finck goto exit; 1976c2c66affSColin Finck } 1977c2c66affSColin Finck 1978318da0c1SPierre Schweitzer context.stripes[i].mdl = IoAllocateMdl(context.va, length, false, false, NULL); 1979c2c66affSColin Finck if (!context.stripes[i].mdl) { 1980c2c66affSColin Finck ERR("IoAllocateMdl failed\n"); 1981c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 1982c2c66affSColin Finck goto exit; 1983c2c66affSColin Finck } 1984c2c66affSColin Finck 1985c2c66affSColin Finck MmBuildMdlForNonPagedPool(context.stripes[i].mdl); 1986c2c66affSColin Finck } else { 1987318da0c1SPierre Schweitzer context.stripes[i].mdl = IoAllocateMdl(buf, length, false, false, NULL); 1988c2c66affSColin Finck 1989c2c66affSColin Finck if (!context.stripes[i].mdl) { 1990c2c66affSColin Finck ERR("IoAllocateMdl failed\n"); 1991c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 1992c2c66affSColin Finck goto exit; 1993c2c66affSColin Finck } 1994c2c66affSColin Finck 1995c2c66affSColin Finck Status = STATUS_SUCCESS; 1996c2c66affSColin Finck 1997c2c66affSColin Finck _SEH2_TRY { 1998c2c66affSColin Finck MmProbeAndLockPages(context.stripes[i].mdl, KernelMode, IoWriteAccess); 1999c2c66affSColin Finck } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 2000c2c66affSColin Finck Status = _SEH2_GetExceptionCode(); 2001c2c66affSColin Finck } _SEH2_END; 2002c2c66affSColin Finck 2003c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 2004194ea909SVictor Perevertkin ERR("MmProbeAndLockPages threw exception %08lx\n", Status); 2005c2c66affSColin Finck goto exit; 2006c2c66affSColin Finck } 2007c2c66affSColin Finck } 2008c2c66affSColin Finck } else if (type == BLOCK_FLAG_RAID5) { 2009318da0c1SPierre Schweitzer uint64_t startoff, endoff; 2010318da0c1SPierre Schweitzer uint16_t endoffstripe, parity; 2011318da0c1SPierre Schweitzer uint32_t *stripeoff, pos; 2012c2c66affSColin Finck PMDL master_mdl; 2013*06042735SVincent Franchomme PFN_NUMBER *pfns, dummy = 0; 2014318da0c1SPierre Schweitzer bool need_dummy = false; 2015c2c66affSColin Finck 2016c2c66affSColin Finck get_raid0_offset(addr - offset, ci->stripe_length, ci->num_stripes - 1, &startoff, &startoffstripe); 2017c2c66affSColin Finck get_raid0_offset(addr + length - offset - 1, ci->stripe_length, ci->num_stripes - 1, &endoff, &endoffstripe); 2018c2c66affSColin Finck 2019c2c66affSColin Finck if (file_read) { 2020c2c66affSColin Finck context.va = ExAllocatePoolWithTag(NonPagedPool, length, ALLOC_TAG); 2021c2c66affSColin Finck 2022c2c66affSColin Finck if (!context.va) { 2023c2c66affSColin Finck ERR("out of memory\n"); 2024c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2025c2c66affSColin Finck goto exit; 2026c2c66affSColin Finck } 2027c2c66affSColin Finck } else 2028c2c66affSColin Finck context.va = buf; 2029c2c66affSColin Finck 2030318da0c1SPierre Schweitzer master_mdl = IoAllocateMdl(context.va, length, false, false, NULL); 2031c2c66affSColin Finck if (!master_mdl) { 2032c2c66affSColin Finck ERR("out of memory\n"); 2033c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2034c2c66affSColin Finck goto exit; 2035c2c66affSColin Finck } 2036c2c66affSColin Finck 2037c2c66affSColin Finck Status = STATUS_SUCCESS; 2038c2c66affSColin Finck 2039c2c66affSColin Finck _SEH2_TRY { 2040c2c66affSColin Finck MmProbeAndLockPages(master_mdl, KernelMode, IoWriteAccess); 2041c2c66affSColin Finck } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 2042c2c66affSColin Finck Status = _SEH2_GetExceptionCode(); 2043c2c66affSColin Finck } _SEH2_END; 2044c2c66affSColin Finck 2045c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 2046194ea909SVictor Perevertkin ERR("MmProbeAndLockPages threw exception %08lx\n", Status); 2047c2c66affSColin Finck IoFreeMdl(master_mdl); 2048c2c66affSColin Finck goto exit; 2049c2c66affSColin Finck } 2050c2c66affSColin Finck 2051c2c66affSColin Finck pfns = (PFN_NUMBER*)(master_mdl + 1); 2052c2c66affSColin Finck 2053c2c66affSColin Finck pos = 0; 2054c2c66affSColin Finck while (pos < length) { 2055c2c66affSColin Finck parity = (((addr - offset + pos) / ((ci->num_stripes - 1) * ci->stripe_length)) + ci->num_stripes - 1) % ci->num_stripes; 2056c2c66affSColin Finck 2057c2c66affSColin Finck if (pos == 0) { 2058318da0c1SPierre Schweitzer uint16_t stripe = (parity + startoffstripe + 1) % ci->num_stripes; 2059c2c66affSColin Finck ULONG skip, readlen; 2060c2c66affSColin Finck 2061c2c66affSColin Finck i = startoffstripe; 2062c2c66affSColin Finck while (stripe != parity) { 2063c2c66affSColin Finck if (i == startoffstripe) { 2064c2c66affSColin Finck readlen = min(length, (ULONG)(ci->stripe_length - (startoff % ci->stripe_length))); 2065c2c66affSColin Finck 2066c2c66affSColin Finck context.stripes[stripe].stripestart = startoff; 2067c2c66affSColin Finck context.stripes[stripe].stripeend = startoff + readlen; 2068c2c66affSColin Finck 2069c2c66affSColin Finck pos += readlen; 2070c2c66affSColin Finck 2071c2c66affSColin Finck if (pos == length) 2072c2c66affSColin Finck break; 2073c2c66affSColin Finck } else { 2074c2c66affSColin Finck readlen = min(length - pos, (ULONG)ci->stripe_length); 2075c2c66affSColin Finck 2076c2c66affSColin Finck context.stripes[stripe].stripestart = startoff - (startoff % ci->stripe_length); 2077c2c66affSColin Finck context.stripes[stripe].stripeend = context.stripes[stripe].stripestart + readlen; 2078c2c66affSColin Finck 2079c2c66affSColin Finck pos += readlen; 2080c2c66affSColin Finck 2081c2c66affSColin Finck if (pos == length) 2082c2c66affSColin Finck break; 2083c2c66affSColin Finck } 2084c2c66affSColin Finck 2085c2c66affSColin Finck i++; 2086c2c66affSColin Finck stripe = (stripe + 1) % ci->num_stripes; 2087c2c66affSColin Finck } 2088c2c66affSColin Finck 2089c2c66affSColin Finck if (pos == length) 2090c2c66affSColin Finck break; 2091c2c66affSColin Finck 2092c2c66affSColin Finck for (i = 0; i < startoffstripe; i++) { 2093318da0c1SPierre Schweitzer uint16_t stripe2 = (parity + i + 1) % ci->num_stripes; 2094c2c66affSColin Finck 2095c2c66affSColin Finck context.stripes[stripe2].stripestart = context.stripes[stripe2].stripeend = startoff - (startoff % ci->stripe_length) + ci->stripe_length; 2096c2c66affSColin Finck } 2097c2c66affSColin Finck 2098c2c66affSColin Finck context.stripes[parity].stripestart = context.stripes[parity].stripeend = startoff - (startoff % ci->stripe_length) + ci->stripe_length; 2099c2c66affSColin Finck 2100c2c66affSColin Finck if (length - pos > ci->num_stripes * (ci->num_stripes - 1) * ci->stripe_length) { 2101c2c66affSColin Finck skip = (ULONG)(((length - pos) / (ci->num_stripes * (ci->num_stripes - 1) * ci->stripe_length)) - 1); 2102c2c66affSColin Finck 2103c2c66affSColin Finck for (i = 0; i < ci->num_stripes; i++) { 2104c2c66affSColin Finck context.stripes[i].stripeend += skip * ci->num_stripes * ci->stripe_length; 2105c2c66affSColin Finck } 2106c2c66affSColin Finck 2107318da0c1SPierre Schweitzer pos += (uint32_t)(skip * (ci->num_stripes - 1) * ci->num_stripes * ci->stripe_length); 2108318da0c1SPierre Schweitzer need_dummy = true; 2109c2c66affSColin Finck } 2110c2c66affSColin Finck } else if (length - pos >= ci->stripe_length * (ci->num_stripes - 1)) { 2111c2c66affSColin Finck for (i = 0; i < ci->num_stripes; i++) { 2112c2c66affSColin Finck context.stripes[i].stripeend += ci->stripe_length; 2113c2c66affSColin Finck } 2114c2c66affSColin Finck 2115318da0c1SPierre Schweitzer pos += (uint32_t)(ci->stripe_length * (ci->num_stripes - 1)); 2116318da0c1SPierre Schweitzer need_dummy = true; 2117c2c66affSColin Finck } else { 2118318da0c1SPierre Schweitzer uint16_t stripe = (parity + 1) % ci->num_stripes; 2119c2c66affSColin Finck 2120c2c66affSColin Finck i = 0; 2121c2c66affSColin Finck while (stripe != parity) { 2122c2c66affSColin Finck if (endoffstripe == i) { 2123c2c66affSColin Finck context.stripes[stripe].stripeend = endoff + 1; 2124c2c66affSColin Finck break; 2125c2c66affSColin Finck } else if (endoffstripe > i) 2126c2c66affSColin Finck context.stripes[stripe].stripeend = endoff - (endoff % ci->stripe_length) + ci->stripe_length; 2127c2c66affSColin Finck 2128c2c66affSColin Finck i++; 2129c2c66affSColin Finck stripe = (stripe + 1) % ci->num_stripes; 2130c2c66affSColin Finck } 2131c2c66affSColin Finck 2132c2c66affSColin Finck break; 2133c2c66affSColin Finck } 2134c2c66affSColin Finck } 2135c2c66affSColin Finck 2136c2c66affSColin Finck for (i = 0; i < ci->num_stripes; i++) { 2137c2c66affSColin Finck if (context.stripes[i].stripestart != context.stripes[i].stripeend) { 2138c2c66affSColin Finck context.stripes[i].mdl = IoAllocateMdl(context.va, (ULONG)(context.stripes[i].stripeend - context.stripes[i].stripestart), 2139318da0c1SPierre Schweitzer false, false, NULL); 2140c2c66affSColin Finck 2141c2c66affSColin Finck if (!context.stripes[i].mdl) { 2142c2c66affSColin Finck ERR("IoAllocateMdl failed\n"); 2143eb7fbc25SPierre Schweitzer MmUnlockPages(master_mdl); 2144eb7fbc25SPierre Schweitzer IoFreeMdl(master_mdl); 2145c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2146c2c66affSColin Finck goto exit; 2147c2c66affSColin Finck } 2148c2c66affSColin Finck } 2149c2c66affSColin Finck } 2150c2c66affSColin Finck 2151c2c66affSColin Finck if (need_dummy) { 2152c2c66affSColin Finck dummypage = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, ALLOC_TAG); 2153c2c66affSColin Finck if (!dummypage) { 2154c2c66affSColin Finck ERR("out of memory\n"); 2155eb7fbc25SPierre Schweitzer MmUnlockPages(master_mdl); 2156eb7fbc25SPierre Schweitzer IoFreeMdl(master_mdl); 2157c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2158c2c66affSColin Finck goto exit; 2159c2c66affSColin Finck } 2160c2c66affSColin Finck 2161318da0c1SPierre Schweitzer dummy_mdl = IoAllocateMdl(dummypage, PAGE_SIZE, false, false, NULL); 2162c2c66affSColin Finck if (!dummy_mdl) { 2163c2c66affSColin Finck ERR("IoAllocateMdl failed\n"); 2164eb7fbc25SPierre Schweitzer MmUnlockPages(master_mdl); 2165eb7fbc25SPierre Schweitzer IoFreeMdl(master_mdl); 2166c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2167c2c66affSColin Finck goto exit; 2168c2c66affSColin Finck } 2169c2c66affSColin Finck 2170c2c66affSColin Finck MmBuildMdlForNonPagedPool(dummy_mdl); 2171c2c66affSColin Finck 2172c2c66affSColin Finck dummy = *(PFN_NUMBER*)(dummy_mdl + 1); 2173c2c66affSColin Finck } 2174c2c66affSColin Finck 2175318da0c1SPierre Schweitzer stripeoff = ExAllocatePoolWithTag(NonPagedPool, sizeof(uint32_t) * ci->num_stripes, ALLOC_TAG); 2176c2c66affSColin Finck if (!stripeoff) { 2177c2c66affSColin Finck ERR("out of memory\n"); 2178eb7fbc25SPierre Schweitzer MmUnlockPages(master_mdl); 2179eb7fbc25SPierre Schweitzer IoFreeMdl(master_mdl); 2180c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2181c2c66affSColin Finck goto exit; 2182c2c66affSColin Finck } 2183c2c66affSColin Finck 2184318da0c1SPierre Schweitzer RtlZeroMemory(stripeoff, sizeof(uint32_t) * ci->num_stripes); 2185c2c66affSColin Finck 2186c2c66affSColin Finck pos = 0; 2187c2c66affSColin Finck 2188c2c66affSColin Finck while (pos < length) { 2189c2c66affSColin Finck PFN_NUMBER* stripe_pfns; 2190c2c66affSColin Finck 2191c2c66affSColin Finck parity = (((addr - offset + pos) / ((ci->num_stripes - 1) * ci->stripe_length)) + ci->num_stripes - 1) % ci->num_stripes; 2192c2c66affSColin Finck 2193c2c66affSColin Finck if (pos == 0) { 2194318da0c1SPierre Schweitzer uint16_t stripe = (parity + startoffstripe + 1) % ci->num_stripes; 2195318da0c1SPierre Schweitzer uint32_t readlen = min(length - pos, (uint32_t)min(context.stripes[stripe].stripeend - context.stripes[stripe].stripestart, 2196c2c66affSColin Finck ci->stripe_length - (context.stripes[stripe].stripestart % ci->stripe_length))); 2197c2c66affSColin Finck 2198c2c66affSColin Finck stripe_pfns = (PFN_NUMBER*)(context.stripes[stripe].mdl + 1); 2199c2c66affSColin Finck 2200c2c66affSColin Finck RtlCopyMemory(stripe_pfns, pfns, readlen * sizeof(PFN_NUMBER) >> PAGE_SHIFT); 2201c2c66affSColin Finck 2202c2c66affSColin Finck stripeoff[stripe] = readlen; 2203c2c66affSColin Finck pos += readlen; 2204c2c66affSColin Finck 2205c2c66affSColin Finck stripe = (stripe + 1) % ci->num_stripes; 2206c2c66affSColin Finck 2207c2c66affSColin Finck while (stripe != parity) { 2208c2c66affSColin Finck stripe_pfns = (PFN_NUMBER*)(context.stripes[stripe].mdl + 1); 2209318da0c1SPierre Schweitzer readlen = min(length - pos, (uint32_t)min(context.stripes[stripe].stripeend - context.stripes[stripe].stripestart, ci->stripe_length)); 2210c2c66affSColin Finck 2211c2c66affSColin Finck if (readlen == 0) 2212c2c66affSColin Finck break; 2213c2c66affSColin Finck 2214c2c66affSColin Finck RtlCopyMemory(stripe_pfns, &pfns[pos >> PAGE_SHIFT], readlen * sizeof(PFN_NUMBER) >> PAGE_SHIFT); 2215c2c66affSColin Finck 2216c2c66affSColin Finck stripeoff[stripe] = readlen; 2217c2c66affSColin Finck pos += readlen; 2218c2c66affSColin Finck 2219c2c66affSColin Finck stripe = (stripe + 1) % ci->num_stripes; 2220c2c66affSColin Finck } 2221c2c66affSColin Finck } else if (length - pos >= ci->stripe_length * (ci->num_stripes - 1)) { 2222318da0c1SPierre Schweitzer uint16_t stripe = (parity + 1) % ci->num_stripes; 2223c2c66affSColin Finck ULONG k; 2224c2c66affSColin Finck 2225c2c66affSColin Finck while (stripe != parity) { 2226c2c66affSColin Finck stripe_pfns = (PFN_NUMBER*)(context.stripes[stripe].mdl + 1); 2227c2c66affSColin Finck 2228c2c66affSColin Finck RtlCopyMemory(&stripe_pfns[stripeoff[stripe] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], (ULONG)(ci->stripe_length * sizeof(PFN_NUMBER) >> PAGE_SHIFT)); 2229c2c66affSColin Finck 2230318da0c1SPierre Schweitzer stripeoff[stripe] += (uint32_t)ci->stripe_length; 2231318da0c1SPierre Schweitzer pos += (uint32_t)ci->stripe_length; 2232c2c66affSColin Finck 2233c2c66affSColin Finck stripe = (stripe + 1) % ci->num_stripes; 2234c2c66affSColin Finck } 2235c2c66affSColin Finck 2236c2c66affSColin Finck stripe_pfns = (PFN_NUMBER*)(context.stripes[parity].mdl + 1); 2237c2c66affSColin Finck 2238c2c66affSColin Finck for (k = 0; k < ci->stripe_length >> PAGE_SHIFT; k++) { 2239c2c66affSColin Finck stripe_pfns[stripeoff[parity] >> PAGE_SHIFT] = dummy; 2240c2c66affSColin Finck stripeoff[parity] += PAGE_SIZE; 2241c2c66affSColin Finck } 2242c2c66affSColin Finck } else { 2243318da0c1SPierre Schweitzer uint16_t stripe = (parity + 1) % ci->num_stripes; 2244318da0c1SPierre Schweitzer uint32_t readlen; 2245c2c66affSColin Finck 2246c2c66affSColin Finck while (pos < length) { 2247c2c66affSColin Finck stripe_pfns = (PFN_NUMBER*)(context.stripes[stripe].mdl + 1); 2248c2c66affSColin Finck readlen = min(length - pos, (ULONG)min(context.stripes[stripe].stripeend - context.stripes[stripe].stripestart, ci->stripe_length)); 2249c2c66affSColin Finck 2250c2c66affSColin Finck if (readlen == 0) 2251c2c66affSColin Finck break; 2252c2c66affSColin Finck 2253c2c66affSColin Finck RtlCopyMemory(&stripe_pfns[stripeoff[stripe] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], readlen * sizeof(PFN_NUMBER) >> PAGE_SHIFT); 2254c2c66affSColin Finck 2255c2c66affSColin Finck stripeoff[stripe] += readlen; 2256c2c66affSColin Finck pos += readlen; 2257c2c66affSColin Finck 2258c2c66affSColin Finck stripe = (stripe + 1) % ci->num_stripes; 2259c2c66affSColin Finck } 2260c2c66affSColin Finck } 2261c2c66affSColin Finck } 2262c2c66affSColin Finck 2263c2c66affSColin Finck MmUnlockPages(master_mdl); 2264c2c66affSColin Finck IoFreeMdl(master_mdl); 2265c2c66affSColin Finck 2266c2c66affSColin Finck ExFreePool(stripeoff); 2267c2c66affSColin Finck } else if (type == BLOCK_FLAG_RAID6) { 2268318da0c1SPierre Schweitzer uint64_t startoff, endoff; 2269318da0c1SPierre Schweitzer uint16_t endoffstripe, parity1; 2270318da0c1SPierre Schweitzer uint32_t *stripeoff, pos; 2271c2c66affSColin Finck PMDL master_mdl; 2272*06042735SVincent Franchomme PFN_NUMBER *pfns, dummy = 0; 2273318da0c1SPierre Schweitzer bool need_dummy = false; 2274c2c66affSColin Finck 2275c2c66affSColin Finck get_raid0_offset(addr - offset, ci->stripe_length, ci->num_stripes - 2, &startoff, &startoffstripe); 2276c2c66affSColin Finck get_raid0_offset(addr + length - offset - 1, ci->stripe_length, ci->num_stripes - 2, &endoff, &endoffstripe); 2277c2c66affSColin Finck 2278c2c66affSColin Finck if (file_read) { 2279c2c66affSColin Finck context.va = ExAllocatePoolWithTag(NonPagedPool, length, ALLOC_TAG); 2280c2c66affSColin Finck 2281c2c66affSColin Finck if (!context.va) { 2282c2c66affSColin Finck ERR("out of memory\n"); 2283c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2284c2c66affSColin Finck goto exit; 2285c2c66affSColin Finck } 2286c2c66affSColin Finck } else 2287c2c66affSColin Finck context.va = buf; 2288c2c66affSColin Finck 2289318da0c1SPierre Schweitzer master_mdl = IoAllocateMdl(context.va, length, false, false, NULL); 2290c2c66affSColin Finck if (!master_mdl) { 2291c2c66affSColin Finck ERR("out of memory\n"); 2292c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2293c2c66affSColin Finck goto exit; 2294c2c66affSColin Finck } 2295c2c66affSColin Finck 2296c2c66affSColin Finck Status = STATUS_SUCCESS; 2297c2c66affSColin Finck 2298c2c66affSColin Finck _SEH2_TRY { 2299c2c66affSColin Finck MmProbeAndLockPages(master_mdl, KernelMode, IoWriteAccess); 2300c2c66affSColin Finck } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 2301c2c66affSColin Finck Status = _SEH2_GetExceptionCode(); 2302c2c66affSColin Finck } _SEH2_END; 2303c2c66affSColin Finck 2304c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 2305194ea909SVictor Perevertkin ERR("MmProbeAndLockPages threw exception %08lx\n", Status); 2306c2c66affSColin Finck IoFreeMdl(master_mdl); 2307c2c66affSColin Finck goto exit; 2308c2c66affSColin Finck } 2309c2c66affSColin Finck 2310c2c66affSColin Finck pfns = (PFN_NUMBER*)(master_mdl + 1); 2311c2c66affSColin Finck 2312c2c66affSColin Finck pos = 0; 2313c2c66affSColin Finck while (pos < length) { 2314c2c66affSColin Finck parity1 = (((addr - offset + pos) / ((ci->num_stripes - 2) * ci->stripe_length)) + ci->num_stripes - 2) % ci->num_stripes; 2315c2c66affSColin Finck 2316c2c66affSColin Finck if (pos == 0) { 2317318da0c1SPierre Schweitzer uint16_t stripe = (parity1 + startoffstripe + 2) % ci->num_stripes, parity2; 2318c2c66affSColin Finck ULONG skip, readlen; 2319c2c66affSColin Finck 2320c2c66affSColin Finck i = startoffstripe; 2321c2c66affSColin Finck while (stripe != parity1) { 2322c2c66affSColin Finck if (i == startoffstripe) { 2323c2c66affSColin Finck readlen = (ULONG)min(length, ci->stripe_length - (startoff % ci->stripe_length)); 2324c2c66affSColin Finck 2325c2c66affSColin Finck context.stripes[stripe].stripestart = startoff; 2326c2c66affSColin Finck context.stripes[stripe].stripeend = startoff + readlen; 2327c2c66affSColin Finck 2328c2c66affSColin Finck pos += readlen; 2329c2c66affSColin Finck 2330c2c66affSColin Finck if (pos == length) 2331c2c66affSColin Finck break; 2332c2c66affSColin Finck } else { 2333c2c66affSColin Finck readlen = min(length - pos, (ULONG)ci->stripe_length); 2334c2c66affSColin Finck 2335c2c66affSColin Finck context.stripes[stripe].stripestart = startoff - (startoff % ci->stripe_length); 2336c2c66affSColin Finck context.stripes[stripe].stripeend = context.stripes[stripe].stripestart + readlen; 2337c2c66affSColin Finck 2338c2c66affSColin Finck pos += readlen; 2339c2c66affSColin Finck 2340c2c66affSColin Finck if (pos == length) 2341c2c66affSColin Finck break; 2342c2c66affSColin Finck } 2343c2c66affSColin Finck 2344c2c66affSColin Finck i++; 2345c2c66affSColin Finck stripe = (stripe + 1) % ci->num_stripes; 2346c2c66affSColin Finck } 2347c2c66affSColin Finck 2348c2c66affSColin Finck if (pos == length) 2349c2c66affSColin Finck break; 2350c2c66affSColin Finck 2351c2c66affSColin Finck for (i = 0; i < startoffstripe; i++) { 2352318da0c1SPierre Schweitzer uint16_t stripe2 = (parity1 + i + 2) % ci->num_stripes; 2353c2c66affSColin Finck 2354c2c66affSColin Finck context.stripes[stripe2].stripestart = context.stripes[stripe2].stripeend = startoff - (startoff % ci->stripe_length) + ci->stripe_length; 2355c2c66affSColin Finck } 2356c2c66affSColin Finck 2357c2c66affSColin Finck context.stripes[parity1].stripestart = context.stripes[parity1].stripeend = startoff - (startoff % ci->stripe_length) + ci->stripe_length; 2358c2c66affSColin Finck 2359c2c66affSColin Finck parity2 = (parity1 + 1) % ci->num_stripes; 2360c2c66affSColin Finck context.stripes[parity2].stripestart = context.stripes[parity2].stripeend = startoff - (startoff % ci->stripe_length) + ci->stripe_length; 2361c2c66affSColin Finck 2362c2c66affSColin Finck if (length - pos > ci->num_stripes * (ci->num_stripes - 2) * ci->stripe_length) { 2363c2c66affSColin Finck skip = (ULONG)(((length - pos) / (ci->num_stripes * (ci->num_stripes - 2) * ci->stripe_length)) - 1); 2364c2c66affSColin Finck 2365c2c66affSColin Finck for (i = 0; i < ci->num_stripes; i++) { 2366c2c66affSColin Finck context.stripes[i].stripeend += skip * ci->num_stripes * ci->stripe_length; 2367c2c66affSColin Finck } 2368c2c66affSColin Finck 2369318da0c1SPierre Schweitzer pos += (uint32_t)(skip * (ci->num_stripes - 2) * ci->num_stripes * ci->stripe_length); 2370318da0c1SPierre Schweitzer need_dummy = true; 2371c2c66affSColin Finck } 2372c2c66affSColin Finck } else if (length - pos >= ci->stripe_length * (ci->num_stripes - 2)) { 2373c2c66affSColin Finck for (i = 0; i < ci->num_stripes; i++) { 2374c2c66affSColin Finck context.stripes[i].stripeend += ci->stripe_length; 2375c2c66affSColin Finck } 2376c2c66affSColin Finck 2377318da0c1SPierre Schweitzer pos += (uint32_t)(ci->stripe_length * (ci->num_stripes - 2)); 2378318da0c1SPierre Schweitzer need_dummy = true; 2379c2c66affSColin Finck } else { 2380318da0c1SPierre Schweitzer uint16_t stripe = (parity1 + 2) % ci->num_stripes; 2381c2c66affSColin Finck 2382c2c66affSColin Finck i = 0; 2383c2c66affSColin Finck while (stripe != parity1) { 2384c2c66affSColin Finck if (endoffstripe == i) { 2385c2c66affSColin Finck context.stripes[stripe].stripeend = endoff + 1; 2386c2c66affSColin Finck break; 2387c2c66affSColin Finck } else if (endoffstripe > i) 2388c2c66affSColin Finck context.stripes[stripe].stripeend = endoff - (endoff % ci->stripe_length) + ci->stripe_length; 2389c2c66affSColin Finck 2390c2c66affSColin Finck i++; 2391c2c66affSColin Finck stripe = (stripe + 1) % ci->num_stripes; 2392c2c66affSColin Finck } 2393c2c66affSColin Finck 2394c2c66affSColin Finck break; 2395c2c66affSColin Finck } 2396c2c66affSColin Finck } 2397c2c66affSColin Finck 2398c2c66affSColin Finck for (i = 0; i < ci->num_stripes; i++) { 2399c2c66affSColin Finck if (context.stripes[i].stripestart != context.stripes[i].stripeend) { 2400318da0c1SPierre Schweitzer context.stripes[i].mdl = IoAllocateMdl(context.va, (ULONG)(context.stripes[i].stripeend - context.stripes[i].stripestart), false, false, NULL); 2401c2c66affSColin Finck 2402c2c66affSColin Finck if (!context.stripes[i].mdl) { 2403c2c66affSColin Finck ERR("IoAllocateMdl failed\n"); 2404eb7fbc25SPierre Schweitzer MmUnlockPages(master_mdl); 2405eb7fbc25SPierre Schweitzer IoFreeMdl(master_mdl); 2406c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2407c2c66affSColin Finck goto exit; 2408c2c66affSColin Finck } 2409c2c66affSColin Finck } 2410c2c66affSColin Finck } 2411c2c66affSColin Finck 2412c2c66affSColin Finck if (need_dummy) { 2413c2c66affSColin Finck dummypage = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, ALLOC_TAG); 2414c2c66affSColin Finck if (!dummypage) { 2415c2c66affSColin Finck ERR("out of memory\n"); 2416eb7fbc25SPierre Schweitzer MmUnlockPages(master_mdl); 2417eb7fbc25SPierre Schweitzer IoFreeMdl(master_mdl); 2418c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2419c2c66affSColin Finck goto exit; 2420c2c66affSColin Finck } 2421c2c66affSColin Finck 2422318da0c1SPierre Schweitzer dummy_mdl = IoAllocateMdl(dummypage, PAGE_SIZE, false, false, NULL); 2423c2c66affSColin Finck if (!dummy_mdl) { 2424c2c66affSColin Finck ERR("IoAllocateMdl failed\n"); 2425eb7fbc25SPierre Schweitzer MmUnlockPages(master_mdl); 2426eb7fbc25SPierre Schweitzer IoFreeMdl(master_mdl); 2427c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2428c2c66affSColin Finck goto exit; 2429c2c66affSColin Finck } 2430c2c66affSColin Finck 2431c2c66affSColin Finck MmBuildMdlForNonPagedPool(dummy_mdl); 2432c2c66affSColin Finck 2433c2c66affSColin Finck dummy = *(PFN_NUMBER*)(dummy_mdl + 1); 2434c2c66affSColin Finck } 2435c2c66affSColin Finck 2436318da0c1SPierre Schweitzer stripeoff = ExAllocatePoolWithTag(NonPagedPool, sizeof(uint32_t) * ci->num_stripes, ALLOC_TAG); 2437c2c66affSColin Finck if (!stripeoff) { 2438c2c66affSColin Finck ERR("out of memory\n"); 2439eb7fbc25SPierre Schweitzer MmUnlockPages(master_mdl); 2440eb7fbc25SPierre Schweitzer IoFreeMdl(master_mdl); 2441c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2442c2c66affSColin Finck goto exit; 2443c2c66affSColin Finck } 2444c2c66affSColin Finck 2445318da0c1SPierre Schweitzer RtlZeroMemory(stripeoff, sizeof(uint32_t) * ci->num_stripes); 2446c2c66affSColin Finck 2447c2c66affSColin Finck pos = 0; 2448c2c66affSColin Finck 2449c2c66affSColin Finck while (pos < length) { 2450c2c66affSColin Finck PFN_NUMBER* stripe_pfns; 2451c2c66affSColin Finck 2452c2c66affSColin Finck parity1 = (((addr - offset + pos) / ((ci->num_stripes - 2) * ci->stripe_length)) + ci->num_stripes - 2) % ci->num_stripes; 2453c2c66affSColin Finck 2454c2c66affSColin Finck if (pos == 0) { 2455318da0c1SPierre Schweitzer uint16_t stripe = (parity1 + startoffstripe + 2) % ci->num_stripes; 2456318da0c1SPierre Schweitzer uint32_t readlen = min(length - pos, (uint32_t)min(context.stripes[stripe].stripeend - context.stripes[stripe].stripestart, 2457c2c66affSColin Finck ci->stripe_length - (context.stripes[stripe].stripestart % ci->stripe_length))); 2458c2c66affSColin Finck 2459c2c66affSColin Finck stripe_pfns = (PFN_NUMBER*)(context.stripes[stripe].mdl + 1); 2460c2c66affSColin Finck 2461c2c66affSColin Finck RtlCopyMemory(stripe_pfns, pfns, readlen * sizeof(PFN_NUMBER) >> PAGE_SHIFT); 2462c2c66affSColin Finck 2463c2c66affSColin Finck stripeoff[stripe] = readlen; 2464c2c66affSColin Finck pos += readlen; 2465c2c66affSColin Finck 2466c2c66affSColin Finck stripe = (stripe + 1) % ci->num_stripes; 2467c2c66affSColin Finck 2468c2c66affSColin Finck while (stripe != parity1) { 2469c2c66affSColin Finck stripe_pfns = (PFN_NUMBER*)(context.stripes[stripe].mdl + 1); 2470318da0c1SPierre Schweitzer readlen = (uint32_t)min(length - pos, min(context.stripes[stripe].stripeend - context.stripes[stripe].stripestart, ci->stripe_length)); 2471c2c66affSColin Finck 2472c2c66affSColin Finck if (readlen == 0) 2473c2c66affSColin Finck break; 2474c2c66affSColin Finck 2475c2c66affSColin Finck RtlCopyMemory(stripe_pfns, &pfns[pos >> PAGE_SHIFT], readlen * sizeof(PFN_NUMBER) >> PAGE_SHIFT); 2476c2c66affSColin Finck 2477c2c66affSColin Finck stripeoff[stripe] = readlen; 2478c2c66affSColin Finck pos += readlen; 2479c2c66affSColin Finck 2480c2c66affSColin Finck stripe = (stripe + 1) % ci->num_stripes; 2481c2c66affSColin Finck } 2482c2c66affSColin Finck } else if (length - pos >= ci->stripe_length * (ci->num_stripes - 2)) { 2483318da0c1SPierre Schweitzer uint16_t stripe = (parity1 + 2) % ci->num_stripes; 2484318da0c1SPierre Schweitzer uint16_t parity2 = (parity1 + 1) % ci->num_stripes; 2485c2c66affSColin Finck ULONG k; 2486c2c66affSColin Finck 2487c2c66affSColin Finck while (stripe != parity1) { 2488c2c66affSColin Finck stripe_pfns = (PFN_NUMBER*)(context.stripes[stripe].mdl + 1); 2489c2c66affSColin Finck 2490c2c66affSColin Finck RtlCopyMemory(&stripe_pfns[stripeoff[stripe] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], (ULONG)(ci->stripe_length * sizeof(PFN_NUMBER) >> PAGE_SHIFT)); 2491c2c66affSColin Finck 2492318da0c1SPierre Schweitzer stripeoff[stripe] += (uint32_t)ci->stripe_length; 2493318da0c1SPierre Schweitzer pos += (uint32_t)ci->stripe_length; 2494c2c66affSColin Finck 2495c2c66affSColin Finck stripe = (stripe + 1) % ci->num_stripes; 2496c2c66affSColin Finck } 2497c2c66affSColin Finck 2498c2c66affSColin Finck stripe_pfns = (PFN_NUMBER*)(context.stripes[parity1].mdl + 1); 2499c2c66affSColin Finck 2500c2c66affSColin Finck for (k = 0; k < ci->stripe_length >> PAGE_SHIFT; k++) { 2501c2c66affSColin Finck stripe_pfns[stripeoff[parity1] >> PAGE_SHIFT] = dummy; 2502c2c66affSColin Finck stripeoff[parity1] += PAGE_SIZE; 2503c2c66affSColin Finck } 2504c2c66affSColin Finck 2505c2c66affSColin Finck stripe_pfns = (PFN_NUMBER*)(context.stripes[parity2].mdl + 1); 2506c2c66affSColin Finck 2507c2c66affSColin Finck for (k = 0; k < ci->stripe_length >> PAGE_SHIFT; k++) { 2508c2c66affSColin Finck stripe_pfns[stripeoff[parity2] >> PAGE_SHIFT] = dummy; 2509c2c66affSColin Finck stripeoff[parity2] += PAGE_SIZE; 2510c2c66affSColin Finck } 2511c2c66affSColin Finck } else { 2512318da0c1SPierre Schweitzer uint16_t stripe = (parity1 + 2) % ci->num_stripes; 2513318da0c1SPierre Schweitzer uint32_t readlen; 2514c2c66affSColin Finck 2515c2c66affSColin Finck while (pos < length) { 2516c2c66affSColin Finck stripe_pfns = (PFN_NUMBER*)(context.stripes[stripe].mdl + 1); 2517318da0c1SPierre Schweitzer readlen = (uint32_t)min(length - pos, min(context.stripes[stripe].stripeend - context.stripes[stripe].stripestart, ci->stripe_length)); 2518c2c66affSColin Finck 2519c2c66affSColin Finck if (readlen == 0) 2520c2c66affSColin Finck break; 2521c2c66affSColin Finck 2522c2c66affSColin Finck RtlCopyMemory(&stripe_pfns[stripeoff[stripe] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], readlen * sizeof(PFN_NUMBER) >> PAGE_SHIFT); 2523c2c66affSColin Finck 2524c2c66affSColin Finck stripeoff[stripe] += readlen; 2525c2c66affSColin Finck pos += readlen; 2526c2c66affSColin Finck 2527c2c66affSColin Finck stripe = (stripe + 1) % ci->num_stripes; 2528c2c66affSColin Finck } 2529c2c66affSColin Finck } 2530c2c66affSColin Finck } 2531c2c66affSColin Finck 2532c2c66affSColin Finck MmUnlockPages(master_mdl); 2533c2c66affSColin Finck IoFreeMdl(master_mdl); 2534c2c66affSColin Finck 2535c2c66affSColin Finck ExFreePool(stripeoff); 2536c2c66affSColin Finck } 2537c2c66affSColin Finck 2538c2c66affSColin Finck context.address = addr; 2539c2c66affSColin Finck 2540c2c66affSColin Finck for (i = 0; i < ci->num_stripes; i++) { 2541c2c66affSColin Finck if (!devices[i] || !devices[i]->devobj || context.stripes[i].stripestart == context.stripes[i].stripeend) { 2542c2c66affSColin Finck context.stripes[i].status = ReadDataStatus_MissingDevice; 2543c2c66affSColin Finck context.stripes_left--; 2544c2c66affSColin Finck 2545c2c66affSColin Finck if (!devices[i] || !devices[i]->devobj) 2546c2c66affSColin Finck missing_devices++; 2547c2c66affSColin Finck } 2548c2c66affSColin Finck } 2549c2c66affSColin Finck 2550c2c66affSColin Finck if (missing_devices > allowed_missing) { 2551c2c66affSColin Finck ERR("not enough devices to service request (%u missing)\n", missing_devices); 2552c2c66affSColin Finck Status = STATUS_UNEXPECTED_IO_ERROR; 2553c2c66affSColin Finck goto exit; 2554c2c66affSColin Finck } 2555c2c66affSColin Finck 2556c2c66affSColin Finck for (i = 0; i < ci->num_stripes; i++) { 2557c2c66affSColin Finck PIO_STACK_LOCATION IrpSp; 2558c2c66affSColin Finck 2559c2c66affSColin Finck if (devices[i] && devices[i]->devobj && context.stripes[i].stripestart != context.stripes[i].stripeend && context.stripes[i].status != ReadDataStatus_Skip) { 2560c2c66affSColin Finck context.stripes[i].context = (struct read_data_context*)&context; 2561c2c66affSColin Finck 2562c2c66affSColin Finck if (type == BLOCK_FLAG_RAID10) { 2563c2c66affSColin Finck context.stripes[i].stripenum = i / ci->sub_stripes; 2564c2c66affSColin Finck } 2565c2c66affSColin Finck 2566c2c66affSColin Finck if (!Irp) { 2567318da0c1SPierre Schweitzer context.stripes[i].Irp = IoAllocateIrp(devices[i]->devobj->StackSize, false); 2568c2c66affSColin Finck 2569c2c66affSColin Finck if (!context.stripes[i].Irp) { 2570c2c66affSColin Finck ERR("IoAllocateIrp failed\n"); 2571c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2572c2c66affSColin Finck goto exit; 2573c2c66affSColin Finck } 2574c2c66affSColin Finck } else { 2575c2c66affSColin Finck context.stripes[i].Irp = IoMakeAssociatedIrp(Irp, devices[i]->devobj->StackSize); 2576c2c66affSColin Finck 2577c2c66affSColin Finck if (!context.stripes[i].Irp) { 2578c2c66affSColin Finck ERR("IoMakeAssociatedIrp failed\n"); 2579c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2580c2c66affSColin Finck goto exit; 2581c2c66affSColin Finck } 2582c2c66affSColin Finck } 2583c2c66affSColin Finck 2584c2c66affSColin Finck IrpSp = IoGetNextIrpStackLocation(context.stripes[i].Irp); 2585c2c66affSColin Finck IrpSp->MajorFunction = IRP_MJ_READ; 2586318da0c1SPierre Schweitzer IrpSp->MinorFunction = IRP_MN_NORMAL; 2587318da0c1SPierre Schweitzer IrpSp->FileObject = devices[i]->fileobj; 2588c2c66affSColin Finck 2589c2c66affSColin Finck if (devices[i]->devobj->Flags & DO_BUFFERED_IO) { 2590c2c66affSColin Finck context.stripes[i].Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, (ULONG)(context.stripes[i].stripeend - context.stripes[i].stripestart), ALLOC_TAG); 2591c2c66affSColin Finck if (!context.stripes[i].Irp->AssociatedIrp.SystemBuffer) { 2592c2c66affSColin Finck ERR("out of memory\n"); 2593c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2594c2c66affSColin Finck goto exit; 2595c2c66affSColin Finck } 2596c2c66affSColin Finck 2597c2c66affSColin Finck context.stripes[i].Irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION; 2598c2c66affSColin Finck 2599c2c66affSColin Finck context.stripes[i].Irp->UserBuffer = MmGetSystemAddressForMdlSafe(context.stripes[i].mdl, priority); 2600c2c66affSColin Finck } else if (devices[i]->devobj->Flags & DO_DIRECT_IO) 2601c2c66affSColin Finck context.stripes[i].Irp->MdlAddress = context.stripes[i].mdl; 2602c2c66affSColin Finck else 2603c2c66affSColin Finck context.stripes[i].Irp->UserBuffer = MmGetSystemAddressForMdlSafe(context.stripes[i].mdl, priority); 2604c2c66affSColin Finck 2605c2c66affSColin Finck IrpSp->Parameters.Read.Length = (ULONG)(context.stripes[i].stripeend - context.stripes[i].stripestart); 2606c2c66affSColin Finck IrpSp->Parameters.Read.ByteOffset.QuadPart = context.stripes[i].stripestart + cis[i].offset; 2607c2c66affSColin Finck 2608c2c66affSColin Finck total_reading += IrpSp->Parameters.Read.Length; 2609c2c66affSColin Finck 2610c2c66affSColin Finck context.stripes[i].Irp->UserIosb = &context.stripes[i].iosb; 2611c2c66affSColin Finck 2612318da0c1SPierre Schweitzer IoSetCompletionRoutine(context.stripes[i].Irp, read_data_completion, &context.stripes[i], true, true, true); 2613c2c66affSColin Finck 2614c2c66affSColin Finck context.stripes[i].status = ReadDataStatus_Pending; 2615c2c66affSColin Finck } 2616c2c66affSColin Finck } 2617c2c66affSColin Finck 2618318da0c1SPierre Schweitzer need_to_wait = false; 2619c2c66affSColin Finck for (i = 0; i < ci->num_stripes; i++) { 2620c2c66affSColin Finck if (context.stripes[i].status != ReadDataStatus_MissingDevice && context.stripes[i].status != ReadDataStatus_Skip) { 2621c2c66affSColin Finck IoCallDriver(devices[i]->devobj, context.stripes[i].Irp); 2622318da0c1SPierre Schweitzer need_to_wait = true; 2623c2c66affSColin Finck } 2624c2c66affSColin Finck } 2625c2c66affSColin Finck 2626c2c66affSColin Finck if (need_to_wait) 2627318da0c1SPierre Schweitzer KeWaitForSingleObject(&context.Event, Executive, KernelMode, false, NULL); 2628c2c66affSColin Finck 2629c2c66affSColin Finck if (diskacc) 2630c2c66affSColin Finck fFsRtlUpdateDiskCounters(total_reading, 0); 2631c2c66affSColin Finck 2632c2c66affSColin Finck // check if any of the devices return a "user-induced" error 2633c2c66affSColin Finck 2634c2c66affSColin Finck for (i = 0; i < ci->num_stripes; i++) { 2635c2c66affSColin Finck if (context.stripes[i].status == ReadDataStatus_Error && IoIsErrorUserInduced(context.stripes[i].iosb.Status)) { 2636c2c66affSColin Finck Status = context.stripes[i].iosb.Status; 2637c2c66affSColin Finck goto exit; 2638c2c66affSColin Finck } 2639c2c66affSColin Finck } 2640c2c66affSColin Finck 2641c2c66affSColin Finck if (type == BLOCK_FLAG_RAID0) { 2642c2c66affSColin Finck Status = read_data_raid0(Vcb, file_read ? context.va : buf, addr, length, &context, ci, devices, generation, offset); 2643c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 2644194ea909SVictor Perevertkin ERR("read_data_raid0 returned %08lx\n", Status); 2645c2c66affSColin Finck 2646c2c66affSColin Finck if (file_read) 2647c2c66affSColin Finck ExFreePool(context.va); 2648c2c66affSColin Finck 2649c2c66affSColin Finck goto exit; 2650c2c66affSColin Finck } 2651c2c66affSColin Finck 2652c2c66affSColin Finck if (file_read) { 2653c2c66affSColin Finck RtlCopyMemory(buf, context.va, length); 2654c2c66affSColin Finck ExFreePool(context.va); 2655c2c66affSColin Finck } 2656c2c66affSColin Finck } else if (type == BLOCK_FLAG_RAID10) { 2657c2c66affSColin Finck Status = read_data_raid10(Vcb, file_read ? context.va : buf, addr, length, &context, ci, devices, generation, offset); 2658c2c66affSColin Finck 2659c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 2660194ea909SVictor Perevertkin ERR("read_data_raid10 returned %08lx\n", Status); 2661c2c66affSColin Finck 2662c2c66affSColin Finck if (file_read) 2663c2c66affSColin Finck ExFreePool(context.va); 2664c2c66affSColin Finck 2665c2c66affSColin Finck goto exit; 2666c2c66affSColin Finck } 2667c2c66affSColin Finck 2668c2c66affSColin Finck if (file_read) { 2669c2c66affSColin Finck RtlCopyMemory(buf, context.va, length); 2670c2c66affSColin Finck ExFreePool(context.va); 2671c2c66affSColin Finck } 2672c2c66affSColin Finck } else if (type == BLOCK_FLAG_DUPLICATE) { 2673c2c66affSColin Finck Status = read_data_dup(Vcb, file_read ? context.va : buf, addr, &context, ci, devices, generation); 2674c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 2675194ea909SVictor Perevertkin ERR("read_data_dup returned %08lx\n", Status); 2676c2c66affSColin Finck 2677c2c66affSColin Finck if (file_read) 2678c2c66affSColin Finck ExFreePool(context.va); 2679c2c66affSColin Finck 2680c2c66affSColin Finck goto exit; 2681c2c66affSColin Finck } 2682c2c66affSColin Finck 2683c2c66affSColin Finck if (file_read) { 2684c2c66affSColin Finck RtlCopyMemory(buf, context.va, length); 2685c2c66affSColin Finck ExFreePool(context.va); 2686c2c66affSColin Finck } 2687c2c66affSColin Finck } else if (type == BLOCK_FLAG_RAID5) { 2688318da0c1SPierre Schweitzer Status = read_data_raid5(Vcb, file_read ? context.va : buf, addr, length, &context, ci, devices, offset, generation, c, missing_devices > 0 ? true : false); 2689c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 2690194ea909SVictor Perevertkin ERR("read_data_raid5 returned %08lx\n", Status); 2691c2c66affSColin Finck 2692c2c66affSColin Finck if (file_read) 2693c2c66affSColin Finck ExFreePool(context.va); 2694c2c66affSColin Finck 2695c2c66affSColin Finck goto exit; 2696c2c66affSColin Finck } 2697c2c66affSColin Finck 2698c2c66affSColin Finck if (file_read) { 2699c2c66affSColin Finck RtlCopyMemory(buf, context.va, length); 2700c2c66affSColin Finck ExFreePool(context.va); 2701c2c66affSColin Finck } 2702c2c66affSColin Finck } else if (type == BLOCK_FLAG_RAID6) { 2703318da0c1SPierre Schweitzer Status = read_data_raid6(Vcb, file_read ? context.va : buf, addr, length, &context, ci, devices, offset, generation, c, missing_devices > 0 ? true : false); 2704c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 2705194ea909SVictor Perevertkin ERR("read_data_raid6 returned %08lx\n", Status); 2706c2c66affSColin Finck 2707c2c66affSColin Finck if (file_read) 2708c2c66affSColin Finck ExFreePool(context.va); 2709c2c66affSColin Finck 2710c2c66affSColin Finck goto exit; 2711c2c66affSColin Finck } 2712c2c66affSColin Finck 2713c2c66affSColin Finck if (file_read) { 2714c2c66affSColin Finck RtlCopyMemory(buf, context.va, length); 2715c2c66affSColin Finck ExFreePool(context.va); 2716c2c66affSColin Finck } 2717c2c66affSColin Finck } 2718c2c66affSColin Finck 2719c2c66affSColin Finck exit: 2720c2c66affSColin Finck if (c && (type == BLOCK_FLAG_RAID5 || type == BLOCK_FLAG_RAID6)) 2721c2c66affSColin Finck chunk_unlock_range(Vcb, c, lockaddr, locklen); 2722c2c66affSColin Finck 2723c2c66affSColin Finck if (dummy_mdl) 2724c2c66affSColin Finck IoFreeMdl(dummy_mdl); 2725c2c66affSColin Finck 2726c2c66affSColin Finck if (dummypage) 2727c2c66affSColin Finck ExFreePool(dummypage); 2728c2c66affSColin Finck 2729c2c66affSColin Finck for (i = 0; i < ci->num_stripes; i++) { 2730c2c66affSColin Finck if (context.stripes[i].mdl) { 2731c2c66affSColin Finck if (context.stripes[i].mdl->MdlFlags & MDL_PAGES_LOCKED) 2732c2c66affSColin Finck MmUnlockPages(context.stripes[i].mdl); 2733c2c66affSColin Finck 2734c2c66affSColin Finck IoFreeMdl(context.stripes[i].mdl); 2735c2c66affSColin Finck } 2736c2c66affSColin Finck 2737c2c66affSColin Finck if (context.stripes[i].Irp) 2738c2c66affSColin Finck IoFreeIrp(context.stripes[i].Irp); 2739c2c66affSColin Finck } 2740c2c66affSColin Finck 2741c2c66affSColin Finck ExFreePool(context.stripes); 2742c2c66affSColin Finck 2743c2c66affSColin Finck if (!Vcb->log_to_phys_loaded) 2744c2c66affSColin Finck ExFreePool(devices); 2745c2c66affSColin Finck 2746c2c66affSColin Finck return Status; 2747c2c66affSColin Finck } 2748c2c66affSColin Finck 2749174dfab6SVincent Franchomme __attribute__((nonnull(1, 2))) 2750318da0c1SPierre Schweitzer NTSTATUS read_stream(fcb* fcb, uint8_t* data, uint64_t start, ULONG length, ULONG* pbr) { 2751c2c66affSColin Finck ULONG readlen; 2752c2c66affSColin Finck 2753194ea909SVictor Perevertkin TRACE("(%p, %p, %I64x, %lx, %p)\n", fcb, data, start, length, pbr); 2754c2c66affSColin Finck 2755c2c66affSColin Finck if (pbr) *pbr = 0; 2756c2c66affSColin Finck 2757c2c66affSColin Finck if (start >= fcb->adsdata.Length) { 2758c2c66affSColin Finck TRACE("tried to read beyond end of stream\n"); 2759c2c66affSColin Finck return STATUS_END_OF_FILE; 2760c2c66affSColin Finck } 2761c2c66affSColin Finck 2762c2c66affSColin Finck if (length == 0) { 2763c2c66affSColin Finck WARN("tried to read zero bytes\n"); 2764c2c66affSColin Finck return STATUS_SUCCESS; 2765c2c66affSColin Finck } 2766c2c66affSColin Finck 2767c2c66affSColin Finck if (start + length < fcb->adsdata.Length) 2768c2c66affSColin Finck readlen = length; 2769c2c66affSColin Finck else 2770c2c66affSColin Finck readlen = fcb->adsdata.Length - (ULONG)start; 2771c2c66affSColin Finck 2772c2c66affSColin Finck if (readlen > 0) 2773194ea909SVictor Perevertkin RtlCopyMemory(data, fcb->adsdata.Buffer + start, readlen); 2774c2c66affSColin Finck 2775c2c66affSColin Finck if (pbr) *pbr = readlen; 2776c2c66affSColin Finck 2777c2c66affSColin Finck return STATUS_SUCCESS; 2778c2c66affSColin Finck } 2779c2c66affSColin Finck 2780194ea909SVictor Perevertkin typedef struct { 2781194ea909SVictor Perevertkin uint64_t off; 2782194ea909SVictor Perevertkin uint64_t ed_size; 2783194ea909SVictor Perevertkin uint64_t ed_offset; 2784194ea909SVictor Perevertkin uint64_t ed_num_bytes; 2785194ea909SVictor Perevertkin } read_part_extent; 2786194ea909SVictor Perevertkin 2787194ea909SVictor Perevertkin typedef struct { 2788194ea909SVictor Perevertkin LIST_ENTRY list_entry; 2789194ea909SVictor Perevertkin uint64_t addr; 2790194ea909SVictor Perevertkin chunk* c; 2791194ea909SVictor Perevertkin uint32_t read; 2792194ea909SVictor Perevertkin uint32_t to_read; 2793194ea909SVictor Perevertkin void* csum; 2794194ea909SVictor Perevertkin bool csum_free; 2795194ea909SVictor Perevertkin uint8_t* buf; 2796194ea909SVictor Perevertkin bool buf_free; 2797194ea909SVictor Perevertkin uint32_t bumpoff; 2798194ea909SVictor Perevertkin bool mdl; 2799194ea909SVictor Perevertkin void* data; 2800194ea909SVictor Perevertkin uint8_t compression; 2801194ea909SVictor Perevertkin unsigned int num_extents; 2802194ea909SVictor Perevertkin read_part_extent extents[1]; 2803194ea909SVictor Perevertkin } read_part; 2804194ea909SVictor Perevertkin 2805194ea909SVictor Perevertkin typedef struct { 2806194ea909SVictor Perevertkin LIST_ENTRY list_entry; 2807194ea909SVictor Perevertkin calc_job* cj; 2808194ea909SVictor Perevertkin void* decomp; 2809194ea909SVictor Perevertkin void* data; 2810194ea909SVictor Perevertkin unsigned int offset; 2811194ea909SVictor Perevertkin size_t length; 2812194ea909SVictor Perevertkin } comp_calc_job; 2813194ea909SVictor Perevertkin 2814174dfab6SVincent Franchomme __attribute__((nonnull(1, 2))) 2815318da0c1SPierre Schweitzer NTSTATUS read_file(fcb* fcb, uint8_t* data, uint64_t start, uint64_t length, ULONG* pbr, PIRP Irp) { 2816c2c66affSColin Finck NTSTATUS Status; 2817318da0c1SPierre Schweitzer uint32_t bytes_read = 0; 2818318da0c1SPierre Schweitzer uint64_t last_end; 2819c2c66affSColin Finck LIST_ENTRY* le; 2820318da0c1SPierre Schweitzer POOL_TYPE pool_type; 2821194ea909SVictor Perevertkin LIST_ENTRY read_parts, calc_jobs; 2822c2c66affSColin Finck 2823318da0c1SPierre Schweitzer TRACE("(%p, %p, %I64x, %I64x, %p)\n", fcb, data, start, length, pbr); 2824c2c66affSColin Finck 2825c2c66affSColin Finck if (pbr) 2826c2c66affSColin Finck *pbr = 0; 2827c2c66affSColin Finck 2828c2c66affSColin Finck if (start >= fcb->inode_item.st_size) { 2829c2c66affSColin Finck WARN("Tried to read beyond end of file\n"); 2830194ea909SVictor Perevertkin return STATUS_END_OF_FILE; 2831c2c66affSColin Finck } 2832c2c66affSColin Finck 2833194ea909SVictor Perevertkin InitializeListHead(&read_parts); 2834194ea909SVictor Perevertkin InitializeListHead(&calc_jobs); 2835194ea909SVictor Perevertkin 2836318da0c1SPierre Schweitzer pool_type = fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE ? NonPagedPool : PagedPool; 2837c2c66affSColin Finck 2838c2c66affSColin Finck le = fcb->extents.Flink; 2839c2c66affSColin Finck 2840c2c66affSColin Finck last_end = start; 2841c2c66affSColin Finck 2842c2c66affSColin Finck while (le != &fcb->extents) { 2843c2c66affSColin Finck extent* ext = CONTAINING_RECORD(le, extent, list_entry); 2844c2c66affSColin Finck 2845c2c66affSColin Finck if (!ext->ignore) { 2846194ea909SVictor Perevertkin EXTENT_DATA* ed = &ext->extent_data; 2847174dfab6SVincent Franchomme uint64_t len; 2848c2c66affSColin Finck 2849174dfab6SVincent Franchomme if (ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) 2850174dfab6SVincent Franchomme len = ((EXTENT_DATA2*)ed->data)->num_bytes; 2851174dfab6SVincent Franchomme else 2852174dfab6SVincent Franchomme len = ed->decoded_size; 2853c2c66affSColin Finck 2854c2c66affSColin Finck if (ext->offset + len <= start) { 2855c2c66affSColin Finck last_end = ext->offset + len; 2856c2c66affSColin Finck goto nextitem; 2857c2c66affSColin Finck } 2858c2c66affSColin Finck 2859c2c66affSColin Finck if (ext->offset > last_end && ext->offset > start + bytes_read) { 2860318da0c1SPierre Schweitzer uint32_t read = (uint32_t)min(length, ext->offset - max(start, last_end)); 2861c2c66affSColin Finck 2862c2c66affSColin Finck RtlZeroMemory(data + bytes_read, read); 2863c2c66affSColin Finck bytes_read += read; 2864c2c66affSColin Finck length -= read; 2865c2c66affSColin Finck } 2866c2c66affSColin Finck 2867c2c66affSColin Finck if (length == 0 || ext->offset > start + bytes_read + length) 2868c2c66affSColin Finck break; 2869c2c66affSColin Finck 2870c2c66affSColin Finck if (ed->encryption != BTRFS_ENCRYPTION_NONE) { 2871c2c66affSColin Finck WARN("Encryption not supported\n"); 2872c2c66affSColin Finck Status = STATUS_NOT_IMPLEMENTED; 2873c2c66affSColin Finck goto exit; 2874c2c66affSColin Finck } 2875c2c66affSColin Finck 2876c2c66affSColin Finck if (ed->encoding != BTRFS_ENCODING_NONE) { 2877c2c66affSColin Finck WARN("Other encodings not supported\n"); 2878c2c66affSColin Finck Status = STATUS_NOT_IMPLEMENTED; 2879c2c66affSColin Finck goto exit; 2880c2c66affSColin Finck } 2881c2c66affSColin Finck 2882c2c66affSColin Finck switch (ed->type) { 2883c2c66affSColin Finck case EXTENT_TYPE_INLINE: 2884c2c66affSColin Finck { 2885318da0c1SPierre Schweitzer uint64_t off = start + bytes_read - ext->offset; 2886318da0c1SPierre Schweitzer uint32_t read; 2887c2c66affSColin Finck 2888c2c66affSColin Finck if (ed->compression == BTRFS_COMPRESSION_NONE) { 2889318da0c1SPierre Schweitzer read = (uint32_t)min(min(len, ext->datalen) - off, length); 2890c2c66affSColin Finck 2891c2c66affSColin Finck RtlCopyMemory(data + bytes_read, &ed->data[off], read); 2892eb7fbc25SPierre Schweitzer } else if (ed->compression == BTRFS_COMPRESSION_ZLIB || ed->compression == BTRFS_COMPRESSION_LZO || ed->compression == BTRFS_COMPRESSION_ZSTD) { 2893318da0c1SPierre Schweitzer uint8_t* decomp; 2894318da0c1SPierre Schweitzer bool decomp_alloc; 2895318da0c1SPierre Schweitzer uint16_t inlen = ext->datalen - (uint16_t)offsetof(EXTENT_DATA, data[0]); 2896c2c66affSColin Finck 2897c2c66affSColin Finck if (ed->decoded_size == 0 || ed->decoded_size > 0xffffffff) { 2898318da0c1SPierre Schweitzer ERR("ed->decoded_size was invalid (%I64x)\n", ed->decoded_size); 2899c2c66affSColin Finck Status = STATUS_INTERNAL_ERROR; 2900c2c66affSColin Finck goto exit; 2901c2c66affSColin Finck } 2902c2c66affSColin Finck 2903318da0c1SPierre Schweitzer read = (uint32_t)min(ed->decoded_size - off, length); 2904c2c66affSColin Finck 2905c2c66affSColin Finck if (off > 0) { 2906318da0c1SPierre Schweitzer decomp = ExAllocatePoolWithTag(NonPagedPool, (uint32_t)ed->decoded_size, ALLOC_TAG); 2907c2c66affSColin Finck if (!decomp) { 2908c2c66affSColin Finck ERR("out of memory\n"); 2909c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2910c2c66affSColin Finck goto exit; 2911c2c66affSColin Finck } 2912c2c66affSColin Finck 2913318da0c1SPierre Schweitzer decomp_alloc = true; 2914c2c66affSColin Finck } else { 2915c2c66affSColin Finck decomp = data + bytes_read; 2916318da0c1SPierre Schweitzer decomp_alloc = false; 2917c2c66affSColin Finck } 2918c2c66affSColin Finck 2919c2c66affSColin Finck if (ed->compression == BTRFS_COMPRESSION_ZLIB) { 2920318da0c1SPierre Schweitzer Status = zlib_decompress(ed->data, inlen, decomp, (uint32_t)(read + off)); 2921c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 2922194ea909SVictor Perevertkin ERR("zlib_decompress returned %08lx\n", Status); 2923c2c66affSColin Finck if (decomp_alloc) ExFreePool(decomp); 2924c2c66affSColin Finck goto exit; 2925c2c66affSColin Finck } 2926c2c66affSColin Finck } else if (ed->compression == BTRFS_COMPRESSION_LZO) { 2927318da0c1SPierre Schweitzer if (inlen < sizeof(uint32_t)) { 2928c2c66affSColin Finck ERR("extent data was truncated\n"); 2929c2c66affSColin Finck Status = STATUS_INTERNAL_ERROR; 2930c2c66affSColin Finck if (decomp_alloc) ExFreePool(decomp); 2931c2c66affSColin Finck goto exit; 2932c2c66affSColin Finck } else 2933318da0c1SPierre Schweitzer inlen -= sizeof(uint32_t); 2934c2c66affSColin Finck 2935318da0c1SPierre Schweitzer Status = lzo_decompress(ed->data + sizeof(uint32_t), inlen, decomp, (uint32_t)(read + off), sizeof(uint32_t)); 2936c2c66affSColin Finck if (!NT_SUCCESS(Status)) { 2937194ea909SVictor Perevertkin ERR("lzo_decompress returned %08lx\n", Status); 2938c2c66affSColin Finck if (decomp_alloc) ExFreePool(decomp); 2939c2c66affSColin Finck goto exit; 2940c2c66affSColin Finck } 2941eb7fbc25SPierre Schweitzer } else if (ed->compression == BTRFS_COMPRESSION_ZSTD) { 2942318da0c1SPierre Schweitzer Status = zstd_decompress(ed->data, inlen, decomp, (uint32_t)(read + off)); 2943eb7fbc25SPierre Schweitzer if (!NT_SUCCESS(Status)) { 2944194ea909SVictor Perevertkin ERR("zstd_decompress returned %08lx\n", Status); 2945eb7fbc25SPierre Schweitzer if (decomp_alloc) ExFreePool(decomp); 2946eb7fbc25SPierre Schweitzer goto exit; 2947eb7fbc25SPierre Schweitzer } 2948c2c66affSColin Finck } 2949c2c66affSColin Finck 2950c2c66affSColin Finck if (decomp_alloc) { 2951c2c66affSColin Finck RtlCopyMemory(data + bytes_read, decomp + off, read); 2952c2c66affSColin Finck ExFreePool(decomp); 2953c2c66affSColin Finck } 2954c2c66affSColin Finck } else { 2955c2c66affSColin Finck ERR("unhandled compression type %x\n", ed->compression); 2956c2c66affSColin Finck Status = STATUS_NOT_IMPLEMENTED; 2957c2c66affSColin Finck goto exit; 2958c2c66affSColin Finck } 2959c2c66affSColin Finck 2960c2c66affSColin Finck bytes_read += read; 2961c2c66affSColin Finck length -= read; 2962c2c66affSColin Finck 2963c2c66affSColin Finck break; 2964c2c66affSColin Finck } 2965c2c66affSColin Finck 2966c2c66affSColin Finck case EXTENT_TYPE_REGULAR: 2967c2c66affSColin Finck { 2968174dfab6SVincent Franchomme EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data; 2969194ea909SVictor Perevertkin read_part* rp; 2970c2c66affSColin Finck 2971194ea909SVictor Perevertkin rp = ExAllocatePoolWithTag(pool_type, sizeof(read_part), ALLOC_TAG); 2972194ea909SVictor Perevertkin if (!rp) { 2973c2c66affSColin Finck ERR("out of memory\n"); 2974c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 2975c2c66affSColin Finck goto exit; 2976c2c66affSColin Finck } 2977c2c66affSColin Finck 2978194ea909SVictor Perevertkin rp->mdl = (Irp && Irp->MdlAddress) ? true : false; 2979194ea909SVictor Perevertkin rp->extents[0].off = start + bytes_read - ext->offset; 2980194ea909SVictor Perevertkin rp->bumpoff = 0; 2981194ea909SVictor Perevertkin rp->num_extents = 1; 2982194ea909SVictor Perevertkin rp->csum_free = false; 2983194ea909SVictor Perevertkin 2984194ea909SVictor Perevertkin rp->read = (uint32_t)(len - rp->extents[0].off); 2985194ea909SVictor Perevertkin if (rp->read > length) rp->read = (uint32_t)length; 2986194ea909SVictor Perevertkin 2987194ea909SVictor Perevertkin if (ed->compression == BTRFS_COMPRESSION_NONE) { 2988194ea909SVictor Perevertkin rp->addr = ed2->address + ed2->offset + rp->extents[0].off; 2989194ea909SVictor Perevertkin rp->to_read = (uint32_t)sector_align(rp->read, fcb->Vcb->superblock.sector_size); 2990194ea909SVictor Perevertkin 2991174dfab6SVincent Franchomme if (rp->addr & (fcb->Vcb->superblock.sector_size - 1)) { 2992174dfab6SVincent Franchomme rp->bumpoff = rp->addr & (fcb->Vcb->superblock.sector_size - 1); 2993194ea909SVictor Perevertkin rp->addr -= rp->bumpoff; 2994194ea909SVictor Perevertkin rp->to_read = (uint32_t)sector_align(rp->read + rp->bumpoff, fcb->Vcb->superblock.sector_size); 2995194ea909SVictor Perevertkin } 2996194ea909SVictor Perevertkin } else { 2997194ea909SVictor Perevertkin rp->addr = ed2->address; 2998194ea909SVictor Perevertkin rp->to_read = (uint32_t)sector_align(ed2->size, fcb->Vcb->superblock.sector_size); 2999c2c66affSColin Finck } 3000c2c66affSColin Finck 3001174dfab6SVincent Franchomme if (ed->compression == BTRFS_COMPRESSION_NONE && (start & (fcb->Vcb->superblock.sector_size - 1)) == 0 && 3002174dfab6SVincent Franchomme (length & (fcb->Vcb->superblock.sector_size - 1)) == 0) { 3003194ea909SVictor Perevertkin rp->buf = data + bytes_read; 3004194ea909SVictor Perevertkin rp->buf_free = false; 3005194ea909SVictor Perevertkin } else { 3006194ea909SVictor Perevertkin rp->buf = ExAllocatePoolWithTag(pool_type, rp->to_read, ALLOC_TAG); 3007194ea909SVictor Perevertkin rp->buf_free = true; 3008c2c66affSColin Finck 3009194ea909SVictor Perevertkin if (!rp->buf) { 3010194ea909SVictor Perevertkin ERR("out of memory\n"); 3011194ea909SVictor Perevertkin Status = STATUS_INSUFFICIENT_RESOURCES; 3012194ea909SVictor Perevertkin ExFreePool(rp); 3013194ea909SVictor Perevertkin goto exit; 3014194ea909SVictor Perevertkin } 3015c2c66affSColin Finck 3016194ea909SVictor Perevertkin rp->mdl = false; 3017194ea909SVictor Perevertkin } 3018194ea909SVictor Perevertkin 3019194ea909SVictor Perevertkin rp->c = get_chunk_from_address(fcb->Vcb, rp->addr); 3020194ea909SVictor Perevertkin 3021194ea909SVictor Perevertkin if (!rp->c) { 3022194ea909SVictor Perevertkin ERR("get_chunk_from_address(%I64x) failed\n", rp->addr); 3023194ea909SVictor Perevertkin 3024194ea909SVictor Perevertkin if (rp->buf_free) 3025194ea909SVictor Perevertkin ExFreePool(rp->buf); 3026194ea909SVictor Perevertkin 3027194ea909SVictor Perevertkin ExFreePool(rp); 3028c2c66affSColin Finck 3029174dfab6SVincent Franchomme Status = STATUS_INTERNAL_ERROR; 3030c2c66affSColin Finck goto exit; 3031c2c66affSColin Finck } 3032c2c66affSColin Finck 3033c2c66affSColin Finck if (ext->csum) { 3034c2c66affSColin Finck if (ed->compression == BTRFS_COMPRESSION_NONE) { 3035174dfab6SVincent Franchomme rp->csum = (uint8_t*)ext->csum + (fcb->Vcb->csum_size * (rp->extents[0].off >> fcb->Vcb->sector_shift)); 3036c2c66affSColin Finck } else 3037194ea909SVictor Perevertkin rp->csum = ext->csum; 3038c2c66affSColin Finck } else 3039194ea909SVictor Perevertkin rp->csum = NULL; 3040c2c66affSColin Finck 3041194ea909SVictor Perevertkin rp->data = data + bytes_read; 3042194ea909SVictor Perevertkin rp->compression = ed->compression; 3043194ea909SVictor Perevertkin rp->extents[0].ed_offset = ed2->offset; 3044194ea909SVictor Perevertkin rp->extents[0].ed_size = ed2->size; 3045194ea909SVictor Perevertkin rp->extents[0].ed_num_bytes = ed2->num_bytes; 3046c2c66affSColin Finck 3047194ea909SVictor Perevertkin InsertTailList(&read_parts, &rp->list_entry); 3048c2c66affSColin Finck 3049194ea909SVictor Perevertkin bytes_read += rp->read; 3050194ea909SVictor Perevertkin length -= rp->read; 3051c2c66affSColin Finck 3052c2c66affSColin Finck break; 3053c2c66affSColin Finck } 3054c2c66affSColin Finck 3055c2c66affSColin Finck case EXTENT_TYPE_PREALLOC: 3056c2c66affSColin Finck { 3057318da0c1SPierre Schweitzer uint64_t off = start + bytes_read - ext->offset; 3058318da0c1SPierre Schweitzer uint32_t read = (uint32_t)(len - off); 3059c2c66affSColin Finck 3060318da0c1SPierre Schweitzer if (read > length) read = (uint32_t)length; 3061c2c66affSColin Finck 3062c2c66affSColin Finck RtlZeroMemory(data + bytes_read, read); 3063c2c66affSColin Finck 3064c2c66affSColin Finck bytes_read += read; 3065c2c66affSColin Finck length -= read; 3066c2c66affSColin Finck 3067c2c66affSColin Finck break; 3068c2c66affSColin Finck } 3069c2c66affSColin Finck 3070c2c66affSColin Finck default: 3071c2c66affSColin Finck WARN("Unsupported extent data type %u\n", ed->type); 3072c2c66affSColin Finck Status = STATUS_NOT_IMPLEMENTED; 3073c2c66affSColin Finck goto exit; 3074c2c66affSColin Finck } 3075c2c66affSColin Finck 3076c2c66affSColin Finck last_end = ext->offset + len; 3077c2c66affSColin Finck 3078c2c66affSColin Finck if (length == 0) 3079c2c66affSColin Finck break; 3080c2c66affSColin Finck } 3081c2c66affSColin Finck 3082c2c66affSColin Finck nextitem: 3083c2c66affSColin Finck le = le->Flink; 3084c2c66affSColin Finck } 3085c2c66affSColin Finck 3086194ea909SVictor Perevertkin if (!IsListEmpty(&read_parts) && read_parts.Flink->Flink != &read_parts) { // at least two entries in list 3087194ea909SVictor Perevertkin read_part* last_rp = CONTAINING_RECORD(read_parts.Flink, read_part, list_entry); 3088194ea909SVictor Perevertkin 3089194ea909SVictor Perevertkin le = read_parts.Flink->Flink; 3090194ea909SVictor Perevertkin while (le != &read_parts) { 3091194ea909SVictor Perevertkin LIST_ENTRY* le2 = le->Flink; 3092194ea909SVictor Perevertkin read_part* rp = CONTAINING_RECORD(le, read_part, list_entry); 3093194ea909SVictor Perevertkin 3094194ea909SVictor Perevertkin // merge together runs 3095194ea909SVictor Perevertkin if (rp->compression != BTRFS_COMPRESSION_NONE && rp->compression == last_rp->compression && rp->addr == last_rp->addr + last_rp->to_read && 3096194ea909SVictor Perevertkin rp->data == (uint8_t*)last_rp->data + last_rp->read && rp->c == last_rp->c && ((rp->csum && last_rp->csum) || (!rp->csum && !last_rp->csum))) { 3097194ea909SVictor Perevertkin read_part* rp2; 3098194ea909SVictor Perevertkin 3099194ea909SVictor Perevertkin rp2 = ExAllocatePoolWithTag(pool_type, offsetof(read_part, extents) + (sizeof(read_part_extent) * (last_rp->num_extents + 1)), ALLOC_TAG); 3100194ea909SVictor Perevertkin 3101194ea909SVictor Perevertkin rp2->addr = last_rp->addr; 3102194ea909SVictor Perevertkin rp2->c = last_rp->c; 3103194ea909SVictor Perevertkin rp2->read = last_rp->read + rp->read; 3104194ea909SVictor Perevertkin rp2->to_read = last_rp->to_read + rp->to_read; 3105194ea909SVictor Perevertkin rp2->csum_free = false; 3106194ea909SVictor Perevertkin 3107194ea909SVictor Perevertkin if (last_rp->csum) { 3108174dfab6SVincent Franchomme uint32_t sectors = (last_rp->to_read + rp->to_read) >> fcb->Vcb->sector_shift; 3109194ea909SVictor Perevertkin 3110194ea909SVictor Perevertkin rp2->csum = ExAllocatePoolWithTag(pool_type, sectors * fcb->Vcb->csum_size, ALLOC_TAG); 3111194ea909SVictor Perevertkin if (!rp2->csum) { 3112194ea909SVictor Perevertkin ERR("out of memory\n"); 3113194ea909SVictor Perevertkin ExFreePool(rp2); 3114194ea909SVictor Perevertkin Status = STATUS_INSUFFICIENT_RESOURCES; 3115194ea909SVictor Perevertkin goto exit; 3116194ea909SVictor Perevertkin } 3117194ea909SVictor Perevertkin 3118174dfab6SVincent Franchomme RtlCopyMemory(rp2->csum, last_rp->csum, (last_rp->to_read * fcb->Vcb->csum_size) >> fcb->Vcb->sector_shift); 3119174dfab6SVincent Franchomme RtlCopyMemory((uint8_t*)rp2->csum + ((last_rp->to_read * fcb->Vcb->csum_size) >> fcb->Vcb->sector_shift), rp->csum, 3120174dfab6SVincent Franchomme (rp->to_read * fcb->Vcb->csum_size) >> fcb->Vcb->sector_shift); 3121194ea909SVictor Perevertkin 3122194ea909SVictor Perevertkin rp2->csum_free = true; 3123194ea909SVictor Perevertkin } else 3124194ea909SVictor Perevertkin rp2->csum = NULL; 3125194ea909SVictor Perevertkin 3126194ea909SVictor Perevertkin rp2->buf = ExAllocatePoolWithTag(pool_type, rp2->to_read, ALLOC_TAG); 3127194ea909SVictor Perevertkin if (!rp2->buf) { 3128194ea909SVictor Perevertkin ERR("out of memory\n"); 3129194ea909SVictor Perevertkin 3130194ea909SVictor Perevertkin if (rp2->csum) 3131194ea909SVictor Perevertkin ExFreePool(rp2->csum); 3132194ea909SVictor Perevertkin 3133194ea909SVictor Perevertkin ExFreePool(rp2); 3134194ea909SVictor Perevertkin Status = STATUS_INSUFFICIENT_RESOURCES; 3135194ea909SVictor Perevertkin goto exit; 3136194ea909SVictor Perevertkin } 3137194ea909SVictor Perevertkin 3138194ea909SVictor Perevertkin rp2->buf_free = true; 3139194ea909SVictor Perevertkin rp2->bumpoff = 0; 3140194ea909SVictor Perevertkin rp2->mdl = false; 3141194ea909SVictor Perevertkin rp2->data = last_rp->data; 3142194ea909SVictor Perevertkin rp2->compression = last_rp->compression; 3143194ea909SVictor Perevertkin rp2->num_extents = last_rp->num_extents + 1; 3144194ea909SVictor Perevertkin 3145194ea909SVictor Perevertkin RtlCopyMemory(rp2->extents, last_rp->extents, last_rp->num_extents * sizeof(read_part_extent)); 3146194ea909SVictor Perevertkin RtlCopyMemory(&rp2->extents[last_rp->num_extents], rp->extents, sizeof(read_part_extent)); 3147194ea909SVictor Perevertkin 3148194ea909SVictor Perevertkin InsertHeadList(le->Blink, &rp2->list_entry); 3149194ea909SVictor Perevertkin 3150194ea909SVictor Perevertkin if (rp->buf_free) 3151194ea909SVictor Perevertkin ExFreePool(rp->buf); 3152194ea909SVictor Perevertkin 3153194ea909SVictor Perevertkin if (rp->csum_free) 3154194ea909SVictor Perevertkin ExFreePool(rp->csum); 3155194ea909SVictor Perevertkin 3156194ea909SVictor Perevertkin RemoveEntryList(&rp->list_entry); 3157194ea909SVictor Perevertkin 3158194ea909SVictor Perevertkin ExFreePool(rp); 3159194ea909SVictor Perevertkin 3160194ea909SVictor Perevertkin if (last_rp->buf_free) 3161194ea909SVictor Perevertkin ExFreePool(last_rp->buf); 3162194ea909SVictor Perevertkin 3163194ea909SVictor Perevertkin if (last_rp->csum_free) 3164194ea909SVictor Perevertkin ExFreePool(last_rp->csum); 3165194ea909SVictor Perevertkin 3166194ea909SVictor Perevertkin RemoveEntryList(&last_rp->list_entry); 3167194ea909SVictor Perevertkin 3168194ea909SVictor Perevertkin ExFreePool(last_rp); 3169194ea909SVictor Perevertkin 3170194ea909SVictor Perevertkin last_rp = rp2; 3171194ea909SVictor Perevertkin } else 3172194ea909SVictor Perevertkin last_rp = rp; 3173194ea909SVictor Perevertkin 3174194ea909SVictor Perevertkin le = le2; 3175194ea909SVictor Perevertkin } 3176194ea909SVictor Perevertkin } 3177194ea909SVictor Perevertkin 3178194ea909SVictor Perevertkin le = read_parts.Flink; 3179194ea909SVictor Perevertkin while (le != &read_parts) { 3180194ea909SVictor Perevertkin read_part* rp = CONTAINING_RECORD(le, read_part, list_entry); 3181194ea909SVictor Perevertkin 3182194ea909SVictor Perevertkin Status = read_data(fcb->Vcb, rp->addr, rp->to_read, rp->csum, false, rp->buf, rp->c, NULL, Irp, 0, rp->mdl, 3183174dfab6SVincent Franchomme fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE ? HighPagePriority : NormalPagePriority); 3184194ea909SVictor Perevertkin if (!NT_SUCCESS(Status)) { 3185194ea909SVictor Perevertkin ERR("read_data returned %08lx\n", Status); 3186194ea909SVictor Perevertkin goto exit; 3187194ea909SVictor Perevertkin } 3188194ea909SVictor Perevertkin 3189194ea909SVictor Perevertkin if (rp->compression == BTRFS_COMPRESSION_NONE) { 3190194ea909SVictor Perevertkin if (rp->buf_free) 3191194ea909SVictor Perevertkin RtlCopyMemory(rp->data, rp->buf + rp->bumpoff, rp->read); 3192194ea909SVictor Perevertkin } else { 3193194ea909SVictor Perevertkin uint8_t* buf = rp->buf; 3194194ea909SVictor Perevertkin #ifdef __REACTOS__ 3195194ea909SVictor Perevertkin unsigned int i; 3196194ea909SVictor Perevertkin for (i = 0; i < rp->num_extents; i++) { 3197194ea909SVictor Perevertkin #else 3198194ea909SVictor Perevertkin for (unsigned int i = 0; i < rp->num_extents; i++) { 3199194ea909SVictor Perevertkin #endif // __REACTOS__ 3200194ea909SVictor Perevertkin uint8_t *decomp = NULL, *buf2; 3201194ea909SVictor Perevertkin ULONG outlen, inlen, off2; 3202194ea909SVictor Perevertkin uint32_t inpageoff = 0; 3203194ea909SVictor Perevertkin comp_calc_job* ccj; 3204194ea909SVictor Perevertkin 3205194ea909SVictor Perevertkin off2 = (ULONG)(rp->extents[i].ed_offset + rp->extents[i].off); 3206194ea909SVictor Perevertkin buf2 = buf; 3207194ea909SVictor Perevertkin inlen = (ULONG)rp->extents[i].ed_size; 3208194ea909SVictor Perevertkin 3209194ea909SVictor Perevertkin if (rp->compression == BTRFS_COMPRESSION_LZO) { 3210194ea909SVictor Perevertkin ULONG inoff = sizeof(uint32_t); 3211194ea909SVictor Perevertkin 3212194ea909SVictor Perevertkin inlen -= sizeof(uint32_t); 3213194ea909SVictor Perevertkin 3214194ea909SVictor Perevertkin // If reading a few sectors in, skip to the interesting bit 3215194ea909SVictor Perevertkin while (off2 > LZO_PAGE_SIZE) { 3216194ea909SVictor Perevertkin uint32_t partlen; 3217194ea909SVictor Perevertkin 3218194ea909SVictor Perevertkin if (inlen < sizeof(uint32_t)) 3219194ea909SVictor Perevertkin break; 3220194ea909SVictor Perevertkin 3221194ea909SVictor Perevertkin partlen = *(uint32_t*)(buf2 + inoff); 3222194ea909SVictor Perevertkin 3223194ea909SVictor Perevertkin if (partlen < inlen) { 3224194ea909SVictor Perevertkin off2 -= LZO_PAGE_SIZE; 3225194ea909SVictor Perevertkin inoff += partlen + sizeof(uint32_t); 3226194ea909SVictor Perevertkin inlen -= partlen + sizeof(uint32_t); 3227194ea909SVictor Perevertkin 3228194ea909SVictor Perevertkin if (LZO_PAGE_SIZE - (inoff % LZO_PAGE_SIZE) < sizeof(uint32_t)) 3229194ea909SVictor Perevertkin inoff = ((inoff / LZO_PAGE_SIZE) + 1) * LZO_PAGE_SIZE; 3230194ea909SVictor Perevertkin } else 3231194ea909SVictor Perevertkin break; 3232194ea909SVictor Perevertkin } 3233194ea909SVictor Perevertkin 3234194ea909SVictor Perevertkin buf2 = &buf2[inoff]; 3235194ea909SVictor Perevertkin inpageoff = inoff % LZO_PAGE_SIZE; 3236194ea909SVictor Perevertkin } 3237194ea909SVictor Perevertkin 3238*06042735SVincent Franchomme /* Previous versions of this code decompressed directly into the destination buffer, 3239*06042735SVincent Franchomme * but unfortunately that can't be relied on - Windows likes to use dummy pages sometimes 3240*06042735SVincent Franchomme * when mmap-ing, which breaks the backtracking used by e.g. zstd. */ 3241*06042735SVincent Franchomme 3242*06042735SVincent Franchomme if (off2 != 0) 3243194ea909SVictor Perevertkin outlen = off2 + min(rp->read, (uint32_t)(rp->extents[i].ed_num_bytes - rp->extents[i].off)); 3244*06042735SVincent Franchomme else 3245*06042735SVincent Franchomme outlen = min(rp->read, (uint32_t)(rp->extents[i].ed_num_bytes - rp->extents[i].off)); 3246194ea909SVictor Perevertkin 3247194ea909SVictor Perevertkin decomp = ExAllocatePoolWithTag(pool_type, outlen, ALLOC_TAG); 3248194ea909SVictor Perevertkin if (!decomp) { 3249194ea909SVictor Perevertkin ERR("out of memory\n"); 3250194ea909SVictor Perevertkin Status = STATUS_INSUFFICIENT_RESOURCES; 3251194ea909SVictor Perevertkin goto exit; 3252194ea909SVictor Perevertkin } 3253194ea909SVictor Perevertkin 3254194ea909SVictor Perevertkin ccj = (comp_calc_job*)ExAllocatePoolWithTag(pool_type, sizeof(comp_calc_job), ALLOC_TAG); 3255194ea909SVictor Perevertkin if (!ccj) { 3256194ea909SVictor Perevertkin ERR("out of memory\n"); 3257194ea909SVictor Perevertkin 3258194ea909SVictor Perevertkin ExFreePool(decomp); 3259194ea909SVictor Perevertkin 3260194ea909SVictor Perevertkin Status = STATUS_INSUFFICIENT_RESOURCES; 3261194ea909SVictor Perevertkin goto exit; 3262194ea909SVictor Perevertkin } 3263194ea909SVictor Perevertkin 3264194ea909SVictor Perevertkin ccj->data = rp->data; 3265194ea909SVictor Perevertkin ccj->decomp = decomp; 3266194ea909SVictor Perevertkin 3267194ea909SVictor Perevertkin ccj->offset = off2; 3268194ea909SVictor Perevertkin ccj->length = (size_t)min(rp->read, rp->extents[i].ed_num_bytes - rp->extents[i].off); 3269194ea909SVictor Perevertkin 3270*06042735SVincent Franchomme Status = add_calc_job_decomp(fcb->Vcb, rp->compression, buf2, inlen, decomp, outlen, 3271*06042735SVincent Franchomme inpageoff, &ccj->cj); 3272*06042735SVincent Franchomme if (!NT_SUCCESS(Status)) { 3273*06042735SVincent Franchomme ERR("add_calc_job_decomp returned %08lx\n", Status); 3274*06042735SVincent Franchomme 3275*06042735SVincent Franchomme ExFreePool(decomp); 3276*06042735SVincent Franchomme ExFreePool(ccj); 3277*06042735SVincent Franchomme 3278*06042735SVincent Franchomme goto exit; 3279*06042735SVincent Franchomme } 3280*06042735SVincent Franchomme 3281194ea909SVictor Perevertkin InsertTailList(&calc_jobs, &ccj->list_entry); 3282194ea909SVictor Perevertkin 3283194ea909SVictor Perevertkin buf += rp->extents[i].ed_size; 3284194ea909SVictor Perevertkin rp->data = (uint8_t*)rp->data + rp->extents[i].ed_num_bytes - rp->extents[i].off; 3285194ea909SVictor Perevertkin rp->read -= (uint32_t)(rp->extents[i].ed_num_bytes - rp->extents[i].off); 3286194ea909SVictor Perevertkin } 3287194ea909SVictor Perevertkin } 3288194ea909SVictor Perevertkin 3289194ea909SVictor Perevertkin le = le->Flink; 3290194ea909SVictor Perevertkin } 3291194ea909SVictor Perevertkin 3292c2c66affSColin Finck if (length > 0 && start + bytes_read < fcb->inode_item.st_size) { 3293318da0c1SPierre Schweitzer uint32_t read = (uint32_t)min(fcb->inode_item.st_size - start - bytes_read, length); 3294c2c66affSColin Finck 3295c2c66affSColin Finck RtlZeroMemory(data + bytes_read, read); 3296c2c66affSColin Finck 3297c2c66affSColin Finck bytes_read += read; 3298c2c66affSColin Finck length -= read; 3299c2c66affSColin Finck } 3300c2c66affSColin Finck 3301c2c66affSColin Finck Status = STATUS_SUCCESS; 3302194ea909SVictor Perevertkin 3303194ea909SVictor Perevertkin while (!IsListEmpty(&calc_jobs)) { 3304194ea909SVictor Perevertkin comp_calc_job* ccj = CONTAINING_RECORD(RemoveTailList(&calc_jobs), comp_calc_job, list_entry); 3305194ea909SVictor Perevertkin 3306194ea909SVictor Perevertkin calc_thread_main(fcb->Vcb, ccj->cj); 3307194ea909SVictor Perevertkin 3308194ea909SVictor Perevertkin KeWaitForSingleObject(&ccj->cj->event, Executive, KernelMode, false, NULL); 3309194ea909SVictor Perevertkin 3310194ea909SVictor Perevertkin if (!NT_SUCCESS(ccj->cj->Status)) 3311194ea909SVictor Perevertkin Status = ccj->cj->Status; 3312194ea909SVictor Perevertkin 3313194ea909SVictor Perevertkin RtlCopyMemory(ccj->data, (uint8_t*)ccj->decomp + ccj->offset, ccj->length); 3314194ea909SVictor Perevertkin ExFreePool(ccj->decomp); 3315194ea909SVictor Perevertkin 3316194ea909SVictor Perevertkin ExFreePool(ccj); 3317194ea909SVictor Perevertkin } 3318194ea909SVictor Perevertkin 3319c2c66affSColin Finck if (pbr) 3320c2c66affSColin Finck *pbr = bytes_read; 3321c2c66affSColin Finck 3322c2c66affSColin Finck exit: 3323194ea909SVictor Perevertkin while (!IsListEmpty(&read_parts)) { 3324194ea909SVictor Perevertkin read_part* rp = CONTAINING_RECORD(RemoveHeadList(&read_parts), read_part, list_entry); 3325194ea909SVictor Perevertkin 3326194ea909SVictor Perevertkin if (rp->buf_free) 3327194ea909SVictor Perevertkin ExFreePool(rp->buf); 3328194ea909SVictor Perevertkin 3329194ea909SVictor Perevertkin if (rp->csum_free) 3330194ea909SVictor Perevertkin ExFreePool(rp->csum); 3331194ea909SVictor Perevertkin 3332194ea909SVictor Perevertkin ExFreePool(rp); 3333194ea909SVictor Perevertkin } 3334194ea909SVictor Perevertkin 3335194ea909SVictor Perevertkin while (!IsListEmpty(&calc_jobs)) { 3336194ea909SVictor Perevertkin comp_calc_job* ccj = CONTAINING_RECORD(RemoveHeadList(&calc_jobs), comp_calc_job, list_entry); 3337194ea909SVictor Perevertkin 3338194ea909SVictor Perevertkin KeWaitForSingleObject(&ccj->cj->event, Executive, KernelMode, false, NULL); 3339194ea909SVictor Perevertkin 3340194ea909SVictor Perevertkin if (ccj->decomp) 3341194ea909SVictor Perevertkin ExFreePool(ccj->decomp); 3342194ea909SVictor Perevertkin 3343194ea909SVictor Perevertkin ExFreePool(ccj->cj); 3344194ea909SVictor Perevertkin 3345194ea909SVictor Perevertkin ExFreePool(ccj); 3346194ea909SVictor Perevertkin } 3347194ea909SVictor Perevertkin 3348c2c66affSColin Finck return Status; 3349c2c66affSColin Finck } 3350c2c66affSColin Finck 3351318da0c1SPierre Schweitzer NTSTATUS do_read(PIRP Irp, bool wait, ULONG* bytes_read) { 3352c2c66affSColin Finck PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 3353c2c66affSColin Finck PFILE_OBJECT FileObject = IrpSp->FileObject; 3354c2c66affSColin Finck fcb* fcb = FileObject->FsContext; 3355318da0c1SPierre Schweitzer uint8_t* data = NULL; 3356c2c66affSColin Finck ULONG length = IrpSp->Parameters.Read.Length, addon = 0; 3357318da0c1SPierre Schweitzer uint64_t start = IrpSp->Parameters.Read.ByteOffset.QuadPart; 3358c2c66affSColin Finck 3359c2c66affSColin Finck *bytes_read = 0; 3360c2c66affSColin Finck 3361c2c66affSColin Finck if (!fcb || !fcb->Vcb || !fcb->subvol) 3362c2c66affSColin Finck return STATUS_INTERNAL_ERROR; 3363c2c66affSColin Finck 336462e630deSPierre Schweitzer TRACE("fcb = %p\n", fcb); 3365194ea909SVictor Perevertkin TRACE("offset = %I64x, length = %lx\n", start, length); 3366318da0c1SPierre Schweitzer TRACE("paging_io = %s, no cache = %s\n", Irp->Flags & IRP_PAGING_IO ? "true" : "false", Irp->Flags & IRP_NOCACHE ? "true" : "false"); 3367c2c66affSColin Finck 3368c2c66affSColin Finck if (!fcb->ads && fcb->type == BTRFS_TYPE_DIRECTORY) 3369c2c66affSColin Finck return STATUS_INVALID_DEVICE_REQUEST; 3370c2c66affSColin Finck 3371c2c66affSColin Finck if (!(Irp->Flags & IRP_PAGING_IO) && !FsRtlCheckLockForReadAccess(&fcb->lock, Irp)) { 3372c2c66affSColin Finck WARN("tried to read locked region\n"); 3373c2c66affSColin Finck return STATUS_FILE_LOCK_CONFLICT; 3374c2c66affSColin Finck } 3375c2c66affSColin Finck 3376c2c66affSColin Finck if (length == 0) { 3377c2c66affSColin Finck TRACE("tried to read zero bytes\n"); 3378c2c66affSColin Finck return STATUS_SUCCESS; 3379c2c66affSColin Finck } 3380c2c66affSColin Finck 3381318da0c1SPierre Schweitzer if (start >= (uint64_t)fcb->Header.FileSize.QuadPart) { 3382318da0c1SPierre Schweitzer TRACE("tried to read with offset after file end (%I64x >= %I64x)\n", start, fcb->Header.FileSize.QuadPart); 3383c2c66affSColin Finck return STATUS_END_OF_FILE; 3384c2c66affSColin Finck } 3385c2c66affSColin Finck 3386318da0c1SPierre Schweitzer TRACE("FileObject %p fcb %p FileSize = %I64x st_size = %I64x (%p)\n", FileObject, fcb, fcb->Header.FileSize.QuadPart, fcb->inode_item.st_size, &fcb->inode_item.st_size); 3387c2c66affSColin Finck 3388174dfab6SVincent Franchomme if (!(Irp->Flags & IRP_NOCACHE) && IrpSp->MinorFunction & IRP_MN_MDL) { 3389174dfab6SVincent Franchomme NTSTATUS Status = STATUS_SUCCESS; 3390174dfab6SVincent Franchomme 3391174dfab6SVincent Franchomme _SEH2_TRY { 3392174dfab6SVincent Franchomme if (!FileObject->PrivateCacheMap) { 3393174dfab6SVincent Franchomme CC_FILE_SIZES ccfs; 3394174dfab6SVincent Franchomme 3395174dfab6SVincent Franchomme ccfs.AllocationSize = fcb->Header.AllocationSize; 3396174dfab6SVincent Franchomme ccfs.FileSize = fcb->Header.FileSize; 3397174dfab6SVincent Franchomme ccfs.ValidDataLength = fcb->Header.ValidDataLength; 3398174dfab6SVincent Franchomme 3399174dfab6SVincent Franchomme init_file_cache(FileObject, &ccfs); 3400174dfab6SVincent Franchomme } 3401174dfab6SVincent Franchomme 3402174dfab6SVincent Franchomme CcMdlRead(FileObject, &IrpSp->Parameters.Read.ByteOffset, length, &Irp->MdlAddress, &Irp->IoStatus); 3403174dfab6SVincent Franchomme } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 3404174dfab6SVincent Franchomme Status = _SEH2_GetExceptionCode(); 3405174dfab6SVincent Franchomme } _SEH2_END; 3406174dfab6SVincent Franchomme 3407174dfab6SVincent Franchomme if (NT_SUCCESS(Status)) { 3408174dfab6SVincent Franchomme Status = Irp->IoStatus.Status; 3409174dfab6SVincent Franchomme Irp->IoStatus.Information += addon; 3410174dfab6SVincent Franchomme *bytes_read = (ULONG)Irp->IoStatus.Information; 3411174dfab6SVincent Franchomme } else 3412174dfab6SVincent Franchomme ERR("EXCEPTION - %08lx\n", Status); 3413174dfab6SVincent Franchomme 3414174dfab6SVincent Franchomme return Status; 3415174dfab6SVincent Franchomme } 3416174dfab6SVincent Franchomme 3417c2c66affSColin Finck data = map_user_buffer(Irp, fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE ? HighPagePriority : NormalPagePriority); 3418c2c66affSColin Finck 3419c2c66affSColin Finck if (Irp->MdlAddress && !data) { 3420c2c66affSColin Finck ERR("MmGetSystemAddressForMdlSafe returned NULL\n"); 3421c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 3422c2c66affSColin Finck } 3423c2c66affSColin Finck 3424318da0c1SPierre Schweitzer if (start >= (uint64_t)fcb->Header.ValidDataLength.QuadPart) { 3425318da0c1SPierre Schweitzer length = (ULONG)min(length, min(start + length, (uint64_t)fcb->Header.FileSize.QuadPart) - fcb->Header.ValidDataLength.QuadPart); 3426c2c66affSColin Finck RtlZeroMemory(data, length); 3427c2c66affSColin Finck Irp->IoStatus.Information = *bytes_read = length; 3428c2c66affSColin Finck return STATUS_SUCCESS; 3429c2c66affSColin Finck } 3430c2c66affSColin Finck 3431318da0c1SPierre Schweitzer if (length + start > (uint64_t)fcb->Header.ValidDataLength.QuadPart) { 3432318da0c1SPierre Schweitzer addon = (ULONG)(min(start + length, (uint64_t)fcb->Header.FileSize.QuadPart) - fcb->Header.ValidDataLength.QuadPart); 3433c2c66affSColin Finck RtlZeroMemory(data + (fcb->Header.ValidDataLength.QuadPart - start), addon); 3434c2c66affSColin Finck length = (ULONG)(fcb->Header.ValidDataLength.QuadPart - start); 3435c2c66affSColin Finck } 3436c2c66affSColin Finck 3437c2c66affSColin Finck if (!(Irp->Flags & IRP_NOCACHE)) { 3438c2c66affSColin Finck NTSTATUS Status = STATUS_SUCCESS; 3439c2c66affSColin Finck 3440c2c66affSColin Finck _SEH2_TRY { 3441c2c66affSColin Finck if (!FileObject->PrivateCacheMap) { 3442c2c66affSColin Finck CC_FILE_SIZES ccfs; 3443c2c66affSColin Finck 3444c2c66affSColin Finck ccfs.AllocationSize = fcb->Header.AllocationSize; 3445c2c66affSColin Finck ccfs.FileSize = fcb->Header.FileSize; 3446c2c66affSColin Finck ccfs.ValidDataLength = fcb->Header.ValidDataLength; 3447c2c66affSColin Finck 3448c2c66affSColin Finck init_file_cache(FileObject, &ccfs); 3449c2c66affSColin Finck } 3450c2c66affSColin Finck 3451c2c66affSColin Finck if (fCcCopyReadEx) { 3452194ea909SVictor Perevertkin TRACE("CcCopyReadEx(%p, %I64x, %lx, %u, %p, %p, %p)\n", FileObject, IrpSp->Parameters.Read.ByteOffset.QuadPart, 3453c2c66affSColin Finck length, wait, data, &Irp->IoStatus, Irp->Tail.Overlay.Thread); 3454194ea909SVictor Perevertkin TRACE("sizes = %I64x, %I64x, %I64x\n", fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart); 3455c2c66affSColin Finck if (!fCcCopyReadEx(FileObject, &IrpSp->Parameters.Read.ByteOffset, length, wait, data, &Irp->IoStatus, Irp->Tail.Overlay.Thread)) { 3456c2c66affSColin Finck TRACE("CcCopyReadEx could not wait\n"); 3457c2c66affSColin Finck 3458c2c66affSColin Finck IoMarkIrpPending(Irp); 3459c2c66affSColin Finck return STATUS_PENDING; 3460c2c66affSColin Finck } 3461c2c66affSColin Finck TRACE("CcCopyReadEx finished\n"); 3462c2c66affSColin Finck } else { 3463194ea909SVictor Perevertkin TRACE("CcCopyRead(%p, %I64x, %lx, %u, %p, %p)\n", FileObject, IrpSp->Parameters.Read.ByteOffset.QuadPart, length, wait, data, &Irp->IoStatus); 3464194ea909SVictor Perevertkin TRACE("sizes = %I64x, %I64x, %I64x\n", fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart); 3465c2c66affSColin Finck if (!CcCopyRead(FileObject, &IrpSp->Parameters.Read.ByteOffset, length, wait, data, &Irp->IoStatus)) { 3466c2c66affSColin Finck TRACE("CcCopyRead could not wait\n"); 3467c2c66affSColin Finck 3468c2c66affSColin Finck IoMarkIrpPending(Irp); 3469c2c66affSColin Finck return STATUS_PENDING; 3470c2c66affSColin Finck } 3471c2c66affSColin Finck TRACE("CcCopyRead finished\n"); 3472c2c66affSColin Finck } 3473c2c66affSColin Finck } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 3474c2c66affSColin Finck Status = _SEH2_GetExceptionCode(); 3475c2c66affSColin Finck } _SEH2_END; 3476c2c66affSColin Finck 3477c2c66affSColin Finck if (NT_SUCCESS(Status)) { 3478c2c66affSColin Finck Status = Irp->IoStatus.Status; 3479c2c66affSColin Finck Irp->IoStatus.Information += addon; 3480c2c66affSColin Finck *bytes_read = (ULONG)Irp->IoStatus.Information; 3481c2c66affSColin Finck } else 3482194ea909SVictor Perevertkin ERR("EXCEPTION - %08lx\n", Status); 3483c2c66affSColin Finck 3484c2c66affSColin Finck return Status; 3485c2c66affSColin Finck } else { 3486c2c66affSColin Finck NTSTATUS Status; 3487c2c66affSColin Finck 3488c2c66affSColin Finck if (!wait) { 3489c2c66affSColin Finck IoMarkIrpPending(Irp); 3490c2c66affSColin Finck return STATUS_PENDING; 3491c2c66affSColin Finck } 3492c2c66affSColin Finck 3493194ea909SVictor Perevertkin if (fcb->ads) { 3494c2c66affSColin Finck Status = read_stream(fcb, data, start, length, bytes_read); 3495194ea909SVictor Perevertkin 3496194ea909SVictor Perevertkin if (!NT_SUCCESS(Status)) 3497194ea909SVictor Perevertkin ERR("read_stream returned %08lx\n", Status); 3498194ea909SVictor Perevertkin } else { 3499c2c66affSColin Finck Status = read_file(fcb, data, start, length, bytes_read, Irp); 3500c2c66affSColin Finck 3501194ea909SVictor Perevertkin if (!NT_SUCCESS(Status)) 3502194ea909SVictor Perevertkin ERR("read_file returned %08lx\n", Status); 3503194ea909SVictor Perevertkin } 3504194ea909SVictor Perevertkin 3505c2c66affSColin Finck *bytes_read += addon; 3506194ea909SVictor Perevertkin TRACE("read %lu bytes\n", *bytes_read); 3507c2c66affSColin Finck 3508c2c66affSColin Finck Irp->IoStatus.Information = *bytes_read; 3509c2c66affSColin Finck 3510c2c66affSColin Finck if (diskacc && Status != STATUS_PENDING) { 3511c2c66affSColin Finck PETHREAD thread = NULL; 3512c2c66affSColin Finck 3513c2c66affSColin Finck if (Irp->Tail.Overlay.Thread && !IoIsSystemThread(Irp->Tail.Overlay.Thread)) 3514c2c66affSColin Finck thread = Irp->Tail.Overlay.Thread; 3515c2c66affSColin Finck else if (!IoIsSystemThread(PsGetCurrentThread())) 3516c2c66affSColin Finck thread = PsGetCurrentThread(); 3517c2c66affSColin Finck else if (IoIsSystemThread(PsGetCurrentThread()) && IoGetTopLevelIrp() == Irp) 3518c2c66affSColin Finck thread = PsGetCurrentThread(); 3519c2c66affSColin Finck 3520c2c66affSColin Finck if (thread) 3521c2c66affSColin Finck fPsUpdateDiskCounters(PsGetThreadProcess(thread), *bytes_read, 0, 1, 0, 0); 3522c2c66affSColin Finck } 3523c2c66affSColin Finck 3524c2c66affSColin Finck return Status; 3525c2c66affSColin Finck } 3526c2c66affSColin Finck } 3527c2c66affSColin Finck 3528c2c66affSColin Finck _Dispatch_type_(IRP_MJ_READ) 3529c2c66affSColin Finck _Function_class_(DRIVER_DISPATCH) 3530318da0c1SPierre Schweitzer NTSTATUS __stdcall drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp) { 3531c2c66affSColin Finck device_extension* Vcb = DeviceObject->DeviceExtension; 3532c2c66affSColin Finck PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 3533c2c66affSColin Finck PFILE_OBJECT FileObject = IrpSp->FileObject; 3534c2c66affSColin Finck ULONG bytes_read = 0; 3535c2c66affSColin Finck NTSTATUS Status; 3536318da0c1SPierre Schweitzer bool top_level; 3537c2c66affSColin Finck fcb* fcb; 3538c2c66affSColin Finck ccb* ccb; 3539318da0c1SPierre Schweitzer bool acquired_fcb_lock = false, wait; 3540c2c66affSColin Finck 3541c2c66affSColin Finck FsRtlEnterFileSystem(); 3542c2c66affSColin Finck 3543c2c66affSColin Finck top_level = is_top_level(Irp); 3544c2c66affSColin Finck 3545c2c66affSColin Finck TRACE("read\n"); 3546c2c66affSColin Finck 3547c2c66affSColin Finck if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 3548c2c66affSColin Finck Status = vol_read(DeviceObject, Irp); 3549c2c66affSColin Finck goto exit2; 3550c2c66affSColin Finck } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 3551c2c66affSColin Finck Status = STATUS_INVALID_PARAMETER; 3552c2c66affSColin Finck goto end; 3553c2c66affSColin Finck } 3554c2c66affSColin Finck 3555c2c66affSColin Finck Irp->IoStatus.Information = 0; 3556c2c66affSColin Finck 3557c2c66affSColin Finck if (IrpSp->MinorFunction & IRP_MN_COMPLETE) { 3558c2c66affSColin Finck CcMdlReadComplete(IrpSp->FileObject, Irp->MdlAddress); 3559c2c66affSColin Finck 3560c2c66affSColin Finck Irp->MdlAddress = NULL; 3561c2c66affSColin Finck Status = STATUS_SUCCESS; 3562c2c66affSColin Finck 3563c2c66affSColin Finck goto exit; 3564c2c66affSColin Finck } 3565c2c66affSColin Finck 3566c2c66affSColin Finck fcb = FileObject->FsContext; 3567c2c66affSColin Finck 3568c2c66affSColin Finck if (!fcb) { 3569c2c66affSColin Finck ERR("fcb was NULL\n"); 3570c2c66affSColin Finck Status = STATUS_INVALID_PARAMETER; 3571c2c66affSColin Finck goto exit; 3572c2c66affSColin Finck } 3573c2c66affSColin Finck 3574c2c66affSColin Finck ccb = FileObject->FsContext2; 3575c2c66affSColin Finck 3576c2c66affSColin Finck if (!ccb) { 3577c2c66affSColin Finck ERR("ccb was NULL\n"); 3578c2c66affSColin Finck Status = STATUS_INVALID_PARAMETER; 3579c2c66affSColin Finck goto exit; 3580c2c66affSColin Finck } 3581c2c66affSColin Finck 3582c2c66affSColin Finck if (Irp->RequestorMode == UserMode && !(ccb->access & FILE_READ_DATA)) { 3583c2c66affSColin Finck WARN("insufficient privileges\n"); 3584c2c66affSColin Finck Status = STATUS_ACCESS_DENIED; 3585c2c66affSColin Finck goto exit; 3586c2c66affSColin Finck } 3587c2c66affSColin Finck 3588c2c66affSColin Finck if (fcb == Vcb->volume_fcb) { 3589c2c66affSColin Finck TRACE("reading volume FCB\n"); 3590c2c66affSColin Finck 3591c2c66affSColin Finck IoSkipCurrentIrpStackLocation(Irp); 3592c2c66affSColin Finck 3593c2c66affSColin Finck Status = IoCallDriver(Vcb->Vpb->RealDevice, Irp); 3594c2c66affSColin Finck 3595c2c66affSColin Finck goto exit2; 3596c2c66affSColin Finck } 3597c2c66affSColin Finck 359862e630deSPierre Schweitzer if (!(Irp->Flags & IRP_PAGING_IO)) 359962e630deSPierre Schweitzer FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL); 360062e630deSPierre Schweitzer 3601c2c66affSColin Finck wait = IoIsOperationSynchronous(Irp); 3602c2c66affSColin Finck 3603c2c66affSColin Finck // Don't offload jobs when doing paging IO - otherwise this can lead to 3604c2c66affSColin Finck // deadlocks in CcCopyRead. 3605c2c66affSColin Finck if (Irp->Flags & IRP_PAGING_IO) 3606318da0c1SPierre Schweitzer wait = true; 3607c2c66affSColin Finck 3608883b1f31SPierre Schweitzer if (!(Irp->Flags & IRP_PAGING_IO) && FileObject->SectionObjectPointer && FileObject->SectionObjectPointer->DataSectionObject) { 36094672b2baSPierre Schweitzer IO_STATUS_BLOCK iosb; 36104672b2baSPierre Schweitzer 36114672b2baSPierre Schweitzer CcFlushCache(FileObject->SectionObjectPointer, &IrpSp->Parameters.Read.ByteOffset, IrpSp->Parameters.Read.Length, &iosb); 36124672b2baSPierre Schweitzer if (!NT_SUCCESS(iosb.Status)) { 3613194ea909SVictor Perevertkin ERR("CcFlushCache returned %08lx\n", iosb.Status); 36144672b2baSPierre Schweitzer return iosb.Status; 36154672b2baSPierre Schweitzer } 36164672b2baSPierre Schweitzer } 36174672b2baSPierre Schweitzer 3618c2c66affSColin Finck if (!ExIsResourceAcquiredSharedLite(fcb->Header.Resource)) { 3619c2c66affSColin Finck if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) { 3620c2c66affSColin Finck Status = STATUS_PENDING; 3621c2c66affSColin Finck IoMarkIrpPending(Irp); 3622c2c66affSColin Finck goto exit; 3623c2c66affSColin Finck } 3624c2c66affSColin Finck 3625318da0c1SPierre Schweitzer acquired_fcb_lock = true; 3626c2c66affSColin Finck } 3627c2c66affSColin Finck 3628c2c66affSColin Finck Status = do_read(Irp, wait, &bytes_read); 3629c2c66affSColin Finck 3630318da0c1SPierre Schweitzer if (acquired_fcb_lock) 3631c2c66affSColin Finck ExReleaseResourceLite(fcb->Header.Resource); 3632c2c66affSColin Finck 3633c2c66affSColin Finck exit: 3634c2c66affSColin Finck if (FileObject->Flags & FO_SYNCHRONOUS_IO && !(Irp->Flags & IRP_PAGING_IO)) 3635c2c66affSColin Finck FileObject->CurrentByteOffset.QuadPart = IrpSp->Parameters.Read.ByteOffset.QuadPart + (NT_SUCCESS(Status) ? bytes_read : 0); 3636c2c66affSColin Finck 3637c2c66affSColin Finck end: 3638c2c66affSColin Finck Irp->IoStatus.Status = Status; 3639c2c66affSColin Finck 3640194ea909SVictor Perevertkin TRACE("Irp->IoStatus.Status = %08lx\n", Irp->IoStatus.Status); 3641194ea909SVictor Perevertkin TRACE("Irp->IoStatus.Information = %Iu\n", Irp->IoStatus.Information); 3642194ea909SVictor Perevertkin TRACE("returning %08lx\n", Status); 3643c2c66affSColin Finck 3644c2c66affSColin Finck if (Status != STATUS_PENDING) 3645c2c66affSColin Finck IoCompleteRequest(Irp, IO_NO_INCREMENT); 3646c2c66affSColin Finck else { 3647c2c66affSColin Finck if (!add_thread_job(Vcb, Irp)) 3648318da0c1SPierre Schweitzer Status = do_read_job(Irp); 3649c2c66affSColin Finck } 3650c2c66affSColin Finck 3651c2c66affSColin Finck exit2: 3652c2c66affSColin Finck if (top_level) 3653c2c66affSColin Finck IoSetTopLevelIrp(NULL); 3654c2c66affSColin Finck 3655c2c66affSColin Finck FsRtlExitFileSystem(); 3656c2c66affSColin Finck 3657c2c66affSColin Finck return Status; 3658c2c66affSColin Finck } 3659