+/* Copyright (c) Mark Harmstone 2016
+ *
+ * This file is part of WinBtrfs.
+ *
+ * WinBtrfs is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public Licence as published by
+ * the Free Software Foundation, either version 3 of the Licence, or
+ * (at your option) any later version.
+ *
+ * WinBtrfs is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public Licence
+ * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
+
#include "btrfs_drv.h"
enum read_data_status {
UINT64 *stripestart = NULL, *stripeend = NULL;
UINT16 startoffstripe;
+ Status = verify_vcb(Vcb, Irp);
+ if (!NT_SUCCESS(Status)) {
+ ERR("verify_vcb returned %08x\n", Status);
+ return Status;
+ }
+
if (Vcb->log_to_phys_loaded) {
chunk* c = get_chunk_from_address(Vcb, addr);
for (i = 0; i < ci->num_stripes; i++) {
if (context->stripes[i].status == ReadDataStatus_Error && IoIsErrorUserInduced(context->stripes[i].iosb.Status)) {
- IoSetHardErrorOrVerifyDevice(context->stripes[i].Irp, devices[i]->devobj);
+ if (Irp && context->stripes[i].iosb.Status == STATUS_VERIFY_REQUIRED) {
+ PDEVICE_OBJECT dev;
+
+ dev = IoGetDeviceToVerify(Irp->Tail.Overlay.Thread);
+ IoSetDeviceToVerify(Irp->Tail.Overlay.Thread, NULL);
+
+ if (!dev) {
+ dev = IoGetDeviceToVerify(PsGetCurrentThread());
+ IoSetDeviceToVerify(PsGetCurrentThread(), NULL);
+ }
+
+ dev = Vcb->Vpb ? Vcb->Vpb->RealDevice : NULL;
+
+ if (dev)
+ IoVerifyVolume(dev, FALSE);
+ }
+// IoSetHardErrorOrVerifyDevice(context->stripes[i].Irp, devices[i]->devobj);
Status = context->stripes[i].iosb.Status;
goto exit;
return Status;
}
-static NTSTATUS load_csum_from_disk(device_extension* Vcb, UINT32* csum, UINT64 start, UINT64 length) {
+static NTSTATUS load_csum_from_disk(device_extension* Vcb, UINT32* csum, UINT64 start, UINT64 length, PIRP Irp) {
NTSTATUS Status;
KEY searchkey;
traverse_ptr tp, next_tp;
searchkey.obj_type = TYPE_EXTENT_CSUM;
searchkey.offset = start;
- Status = find_item(Vcb, Vcb->checksum_root, &tp, &searchkey, FALSE);
+ Status = find_item(Vcb, Vcb->checksum_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
break;
}
- b = find_next_item(Vcb, &tp, &next_tp, FALSE);
+ b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
if (b)
tp = next_tp;
return STATUS_SUCCESS;
}
-static NTSTATUS load_csum(device_extension* Vcb, UINT64 start, UINT64 length, UINT32** pcsum) {
+static NTSTATUS load_csum(device_extension* Vcb, UINT64 start, UINT64 length, UINT32** pcsum, PIRP Irp) {
UINT32* csum = NULL;
NTSTATUS Status;
UINT64 end;
runlength = RtlFindFirstRunClear(&bmp, &index);
while (runlength != 0) {
- Status = load_csum_from_disk(Vcb, &csum[index], start + (index * Vcb->superblock.sector_size), runlength);
+ Status = load_csum_from_disk(Vcb, &csum[index], start + (index * Vcb->superblock.sector_size), runlength, Irp);
if (!NT_SUCCESS(Status)) {
ERR("load_csum_from_disk returned %08x\n", Status);
goto end;
NTSTATUS Status;
EXTENT_DATA* ed;
UINT64 bytes_read = 0;
+ UINT64 last_end;
LIST_ENTRY* le;
TRACE("(%p, %p, %llx, %llx, %p)\n", fcb, data, start, length, pbr);
if (pbr)
*pbr = 0;
-
- le = fcb->extents.Flink;
- while (le != &fcb->extents) {
- extent* ext = CONTAINING_RECORD(le, extent, list_entry);
-
- if (!ext->ignore) {
- if (ext->offset == start)
- break;
- else if (ext->offset > start) {
- LIST_ENTRY* le2 = le->Blink;
-
- ext = NULL;
-
- while (le2 != &fcb->extents) {
- extent* ext2 = CONTAINING_RECORD(le2, extent, list_entry);
-
- if (!ext2->ignore) {
- le = le2;
- ext = ext2;
- break;
- }
-
- le2 = le2->Blink;
- }
-
- if (!ext) {
- ERR("first extent was after offset\n");
- Status = STATUS_INTERNAL_ERROR;
- goto exit;
- } else
- break;
- }
- }
-
- le = le->Flink;
+ if (start >= fcb->inode_item.st_size) {
+ WARN("Tried to read beyond end of file\n");
+ Status = STATUS_END_OF_FILE;
+ goto exit;
}
-
- if (le == &fcb->extents) {
- LIST_ENTRY* le2 = le->Blink;
- extent* ext = NULL;
- while (le2 != &fcb->extents) {
- extent* ext2 = CONTAINING_RECORD(le2, extent, list_entry);
-
- if (!ext2->ignore) {
- le = le2;
- ext = ext2;
- break;
- }
-
- le2 = le2->Blink;
- }
-
- if (!ext) {
- ERR("could not find extent\n");
- Status = STATUS_INTERNAL_ERROR;
- goto exit;
- }
- }
+ le = fcb->extents.Flink;
+
+ last_end = start;
while (le != &fcb->extents) {
UINT64 len;
if (!ext->ignore) {
ed = ext->data;
- if (ext->datalen < sizeof(EXTENT_DATA)) {
- ERR("extent %llx was %u bytes, expected at least %u\n", ext->offset, ext->datalen, sizeof(EXTENT_DATA));
- Status = STATUS_INTERNAL_ERROR;
- goto exit;
- }
-
- if ((ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) && ext->datalen < sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) {
- ERR("extent %llx was %u bytes, expected at least %u\n", ext->offset, ext->datalen, sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2));
- Status = STATUS_INTERNAL_ERROR;
- goto exit;
- }
-
- ed2 = (EXTENT_DATA2*)ed->data;
+ ed2 = (ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) ? (EXTENT_DATA2*)ed->data : NULL;
- len = ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes;
+ len = ed2 ? ed2->num_bytes : ed->decoded_size;
- if (ext->offset + len < start) {
- ERR("Tried to read beyond end of file\n");
- Status = STATUS_END_OF_FILE;
- goto exit;
+ if (ext->offset + len <= start) {
+ last_end = ext->offset + len;
+ goto nextitem;
}
- if (ed->compression != BTRFS_COMPRESSION_NONE) {
- FIXME("FIXME - compression not yet supported\n");
- Status = STATUS_NOT_IMPLEMENTED;
- goto exit;
+ if (ext->offset > last_end && ext->offset > start + bytes_read) {
+ UINT32 read = min(length, ext->offset - max(start, last_end));
+
+ RtlZeroMemory(data + bytes_read, read);
+ bytes_read += read;
+ length -= read;
}
+ if (length == 0 || ext->offset > start + bytes_read + length)
+ break;
+
if (ed->encryption != BTRFS_ENCRYPTION_NONE) {
WARN("Encryption not supported\n");
Status = STATUS_NOT_IMPLEMENTED;
RtlCopyMemory(data + bytes_read, &ed->data[off], read);
+ // FIXME - can we have compressed inline extents?
+
bytes_read += read;
length -= read;
break;
UINT64 off = start + bytes_read - ext->offset;
UINT32 to_read, read;
UINT8* buf;
+ UINT32 *csum, bumpoff = 0;
+ UINT64 addr;
read = len - off;
if (read > length) read = length;
- if (ed2->address == 0) {
- RtlZeroMemory(data + bytes_read, read);
- } else {
- UINT32 *csum, bumpoff = 0;
- UINT64 addr;
-
+ if (ed->compression == BTRFS_COMPRESSION_NONE) {
addr = ed2->address + ed2->offset + off;
to_read = sector_align(read, fcb->Vcb->superblock.sector_size);
addr -= bumpoff;
to_read = sector_align(read + bumpoff, fcb->Vcb->superblock.sector_size);
}
+ } else {
+ addr = ed2->address;
+ to_read = sector_align(ed2->size, fcb->Vcb->superblock.sector_size);
+ }
+
+ buf = ExAllocatePoolWithTag(PagedPool, to_read, ALLOC_TAG);
+
+ if (!buf) {
+ ERR("out of memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto exit;
+ }
+
+ if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) {
+ Status = load_csum(fcb->Vcb, addr, to_read / fcb->Vcb->superblock.sector_size, &csum, Irp);
- buf = ExAllocatePoolWithTag(PagedPool, to_read, ALLOC_TAG);
+ if (!NT_SUCCESS(Status)) {
+ ERR("load_csum returned %08x\n", Status);
+ ExFreePool(buf);
+ goto exit;
+ }
+ } else
+ csum = NULL;
+
+ Status = read_data(fcb->Vcb, addr, to_read, csum, FALSE, buf, NULL, Irp);
+ if (!NT_SUCCESS(Status)) {
+ ERR("read_data returned %08x\n", Status);
+ ExFreePool(buf);
+ goto exit;
+ }
+
+ if (ed->compression == BTRFS_COMPRESSION_NONE) {
+ RtlCopyMemory(data + bytes_read, buf + bumpoff, read);
+ } else {
+ UINT8* decomp = NULL;
+
+ // FIXME - don't mess around with decomp if we're reading the whole extent
- if (!buf) {
+ decomp = ExAllocatePoolWithTag(PagedPool, ed->decoded_size, ALLOC_TAG);
+ if (!decomp) {
ERR("out of memory\n");
+ ExFreePool(buf);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
- if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) {
- Status = load_csum(fcb->Vcb, addr, to_read / fcb->Vcb->superblock.sector_size, &csum);
-
- if (!NT_SUCCESS(Status)) {
- ERR("load_csum returned %08x\n", Status);
- ExFreePool(buf);
- goto exit;
- }
- } else
- csum = NULL;
+ Status = decompress(ed->compression, buf, ed2->size, decomp, ed->decoded_size);
- Status = read_data(fcb->Vcb, addr, to_read, csum, FALSE, buf, NULL, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("read_data returned %08x\n", Status);
+ ERR("decompress returned %08x\n", Status);
ExFreePool(buf);
+ ExFreePool(decomp);
goto exit;
}
- RtlCopyMemory(data + bytes_read, buf + bumpoff, read);
+ RtlCopyMemory(data + bytes_read, decomp + ed2->offset + off, min(read, ed2->num_bytes - off));
- ExFreePool(buf);
-
- if (csum)
- ExFreePool(csum);
+ ExFreePool(decomp);
}
+ ExFreePool(buf);
+
+ if (csum)
+ ExFreePool(csum);
+
bytes_read += read;
length -= read;
Status = STATUS_NOT_IMPLEMENTED;
goto exit;
}
+
+ last_end = ext->offset + len;
if (length == 0)
break;
}
+nextitem:
le = le->Flink;
}
+ if (length > 0 && start + bytes_read < fcb->inode_item.st_size) {
+ UINT32 read = min(fcb->inode_item.st_size - start - bytes_read, length);
+
+ RtlZeroMemory(data + bytes_read, read);
+
+ bytes_read += read;
+ length -= read;
+ }
+
Status = STATUS_SUCCESS;
if (pbr)
*pbr = bytes_read;
}
if (start >= fcb->Header.ValidDataLength.QuadPart) {
- length = min(start + length, fcb->Header.FileSize.QuadPart) - fcb->Header.ValidDataLength.QuadPart;
+ length = min(length, min(start + length, fcb->Header.FileSize.QuadPart) - fcb->Header.ValidDataLength.QuadPart);
RtlZeroMemory(data, length);
Irp->IoStatus.Information = *bytes_read = length;
return STATUS_SUCCESS;
BOOL top_level;
fcb* fcb;
ccb* ccb;
- BOOL tree_lock = FALSE, fcb_lock = FALSE;
+ BOOL tree_lock = FALSE, fcb_lock = FALSE, pagefile;
FsRtlEnterFileSystem();
goto exit;
}
+ if (fcb == Vcb->volume_fcb) {
+ TRACE("not allowing read of volume FCB\n");
+ Status = STATUS_INVALID_PARAMETER;
+ goto exit;
+ }
+
ccb = FileObject->FsContext2;
if (!ccb) {
goto exit;
}
+ pagefile = fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE && Irp->Flags & IRP_PAGING_IO;
+
if (Irp->Flags & IRP_NOCACHE) {
- if (!ExAcquireResourceSharedLite(&Vcb->tree_lock, IoIsOperationSynchronous(Irp))) {
- Status = STATUS_PENDING;
- IoMarkIrpPending(Irp);
- goto exit;
+ if (!pagefile) {
+ if (!ExAcquireResourceSharedLite(&Vcb->tree_lock, IoIsOperationSynchronous(Irp))) {
+ Status = STATUS_PENDING;
+ IoMarkIrpPending(Irp);
+ goto exit;
+ }
+
+ tree_lock = TRUE;
}
-
- tree_lock = TRUE;
if (!ExAcquireResourceSharedLite(fcb->Header.Resource, IoIsOperationSynchronous(Irp))) {
Status = STATUS_PENDING;