#endif
#include "btrfs_drv.h"
+#include "xxhash.h"
+#include "crc32c.h"
#ifndef __REACTOS__
#ifndef _MSC_VER
#include <cpuid.h>
#else
#include <intrin.h>
#endif
-#endif
+#endif // __REACTOS__
#include <ntddscsi.h>
#include "btrfs.h"
#include <ata.h>
#define INCOMPAT_SUPPORTED (BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF | BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL | BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS | \
BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO | BTRFS_INCOMPAT_FLAGS_BIG_METADATA | BTRFS_INCOMPAT_FLAGS_RAID56 | \
BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF | BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA | BTRFS_INCOMPAT_FLAGS_NO_HOLES | \
- BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD)
+ BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD | BTRFS_INCOMPAT_FLAGS_METADATA_UUID | BTRFS_INCOMPAT_FLAGS_RAID1C34)
#define COMPAT_RO_SUPPORTED (BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE | BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID)
static const WCHAR device_name[] = {'\\','B','t','r','f','s',0};
PDRIVER_OBJECT drvobj;
PDEVICE_OBJECT master_devobj, busobj;
#ifndef __REACTOS__
-bool have_sse42 = false, have_sse2 = false;
+bool have_sse2 = false;
#endif
uint64_t num_reads = 0;
LIST_ENTRY uid_map_list, gid_map_list;
KEVENT mountmgr_thread_event;
bool shutting_down = false;
ERESOURCE boot_lock;
+extern uint64_t boot_subvol;
#ifdef _DEBUG
PFILE_OBJECT comfo = NULL;
}
#ifdef DEBUG_LONG_MESSAGES
- sprintf(buf2, "%p:%s:%s:%u:", PsGetCurrentThread(), func, file, line);
+ sprintf(buf2, "%p:%s:%s:%u:", (void*)PsGetCurrentThread(), func, file, line);
#else
- sprintf(buf2, "%p:%s:", PsGetCurrentThread(), func);
+ sprintf(buf2, "%p:%s:", (void*)PsGetCurrentThread(), func);
#endif
buf = &buf2[strlen(buf2)];
IoFreeMdl(Irp->MdlAddress);
if (!NT_SUCCESS(Status)) {
- DbgPrint("failed to write to COM1 - error %08x\n", Status);
+ DbgPrint("failed to write to COM1 - error %08lx\n", Status);
goto exit;
}
Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, buf2, length, NULL, NULL);
if (!NT_SUCCESS(Status)) {
- DbgPrint("failed to write to file - error %08x\n", Status);
+ DbgPrint("failed to write to file - error %08lx\n", Status);
}
}
Status = find_item(Vcb, r, &tp, &searchkey, false, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("error - find_item returned %08x\n", Status);
+ ERR("error - find_item returned %08lx\n", Status);
return false;
}
Status = find_item(Vcb, subvol, &tp, &searchkey, false, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("error - find_item returned %08x\n", Status);
+ ERR("error - find_item returned %08lx\n", Status);
return false;
}
}
if (tp.item->size < sizeof(DIR_ITEM)) {
- ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM));
+ ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM));
return false;
}
if (top_level)
IoSetTopLevelIrp(NULL);
- TRACE("returning %08x\n", Status);
+ TRACE("returning %08lx\n", Status);
FsRtlExitFileSystem();
end:
IoCompleteRequest(Irp, IO_NO_INCREMENT);
- TRACE("returning %08x\n", Status);
+ TRACE("returning %08lx\n", Status);
if (top_level)
IoSetTopLevelIrp(NULL);
} else if (Vcb->data_flags & BLOCK_FLAG_RAID6) {
nfactor = Vcb->superblock.num_devices - 2;
dfactor = Vcb->superblock.num_devices;
+ } else if (Vcb->data_flags & BLOCK_FLAG_RAID1C3) {
+ nfactor = 1;
+ dfactor = 3;
+ } else if (Vcb->data_flags & BLOCK_FLAG_RAID1C4) {
+ nfactor = 1;
+ dfactor = 4;
} else {
nfactor = 1;
dfactor = 1;
}
- sectors_used = Vcb->superblock.bytes_used / Vcb->superblock.sector_size;
+ sectors_used = (Vcb->superblock.bytes_used / Vcb->superblock.sector_size) * nfactor / dfactor;
*totalsize = (Vcb->superblock.total_bytes / Vcb->superblock.sector_size) * nfactor / dfactor;
*freespace = sectors_used > *totalsize ? 0 : (*totalsize - sectors_used);
Status = ZwQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), &retlen);
if (!NT_SUCCESS(Status)) {
- ERR("ZwQueryInformationProcess returned %08x\n", Status);
+ ERR("ZwQueryInformationProcess returned %08lx\n", Status);
return false;
}
return false;
}
-#endif
+#endif // __REACTOS__
// version of RtlUTF8ToUnicodeN for Vista and below
NTSTATUS utf8_to_utf16(WCHAR* dest, ULONG dest_max, ULONG* dest_len, char* src, ULONG src_len) {
ULONG label_len, orig_label_len;
TRACE("FileFsVolumeInformation\n");
- TRACE("max length = %u\n", IrpSp->Parameters.QueryVolume.Length);
+ TRACE("max length = %lu\n", IrpSp->Parameters.QueryVolume.Length);
ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
Status = utf8_to_utf16(NULL, 0, &label_len, Vcb->superblock.label, (ULONG)strlen(Vcb->superblock.label));
if (!NT_SUCCESS(Status)) {
- ERR("utf8_to_utf16 returned %08x\n", Status);
+ ERR("utf8_to_utf16 returned %08lx\n", Status);
ExReleaseResourceLite(&Vcb->tree_lock);
break;
}
overflow = true;
}
- TRACE("label_len = %u\n", label_len);
+ TRACE("label_len = %lu\n", label_len);
ffvi.VolumeCreationTime.QuadPart = 0; // FIXME
ffvi.VolumeSerialNumber = Vcb->superblock.uuid.uuid[12] << 24 | Vcb->superblock.uuid.uuid[13] << 16 | Vcb->superblock.uuid.uuid[14] << 8 | Vcb->superblock.uuid.uuid[15];
Status = utf8_to_utf16(&data->VolumeLabel[0], label_len, &bytecount, Vcb->superblock.label, (ULONG)strlen(Vcb->superblock.label));
if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) {
- ERR("utf8_to_utf16 returned %08x\n", Status);
+ ERR("utf8_to_utf16 returned %08lx\n", Status);
ExReleaseResourceLite(&Vcb->tree_lock);
break;
}
- TRACE("label = %.*S\n", label_len / sizeof(WCHAR), data->VolumeLabel);
+ TRACE("label = %.*S\n", (int)(label_len / sizeof(WCHAR)), data->VolumeLabel);
}
ExReleaseResourceLite(&Vcb->tree_lock);
data->Flags |= SSINFO_FLAGS_TRIM_ENABLED;
BytesCopied = sizeof(FILE_FS_SECTOR_SIZE_INFORMATION);
+ Status = STATUS_SUCCESS;
break;
}
if (top_level)
IoSetTopLevelIrp(NULL);
- TRACE("query volume information returning %08x\n", Status);
+ TRACE("query volume information returning %08lx\n", Status);
FsRtlExitFileSystem();
r->root_item.num_references = 1;
r->fcbs_version = 0;
r->checked_for_orphans = true;
+ r->dropped = false;
InitializeListHead(&r->fcbs);
RtlZeroMemory(r->fcbs_ptrs, sizeof(LIST_ENTRY*) * 256);
Status = insert_tree_item(Vcb, Vcb->root_root, id, TYPE_ROOT_ITEM, offset, ri, sizeof(ROOT_ITEM), &tp, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("insert_tree_item returned %08x\n", Status);
+ ERR("insert_tree_item returned %08lx\n", Status);
ExFreePool(ri);
if (t)
NTSTATUS Status;
ULONG vollen, i;
- TRACE("label = %.*S\n", ffli->VolumeLabelLength / sizeof(WCHAR), ffli->VolumeLabel);
+ TRACE("label = %.*S\n", (int)(ffli->VolumeLabelLength / sizeof(WCHAR)), ffli->VolumeLabel);
vollen = ffli->VolumeLabelLength;
ExReleaseResourceLite(&Vcb->tree_lock);
end:
- TRACE("returning %08x\n", Status);
+ TRACE("returning %08lx\n", Status);
return Status;
}
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
- TRACE("returning %08x\n", Status);
+ TRACE("returning %08lx\n", Status);
IoCompleteRequest( Irp, IO_NO_INCREMENT );
fn.Length = fn.MaximumLength = 0;
Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
if (Status != STATUS_BUFFER_OVERFLOW) {
- ERR("fileref_get_filename returned %08x\n", Status);
+ ERR("fileref_get_filename returned %08lx\n", Status);
return;
}
Status = fileref_get_filename(fileref, &fn, &name_offset, &reqlen);
if (!NT_SUCCESS(Status)) {
- ERR("fileref_get_filename returned %08x\n", Status);
+ ERR("fileref_get_filename returned %08lx\n", Status);
ExFreePool(fn.Buffer);
return;
}
Status = open_fileref_by_inode(fcb->Vcb, fcb->subvol, hl->parent, &parfr, NULL);
if (!NT_SUCCESS(Status))
- ERR("open_fileref_by_inode returned %08x\n", Status);
+ ERR("open_fileref_by_inode returned %08lx\n", Status);
else if (!parfr->deleted) {
UNICODE_STRING fn;
ULONG pathlen;
fn.Length = fn.MaximumLength = 0;
Status = fileref_get_filename(parfr, &fn, NULL, &pathlen);
if (Status != STATUS_BUFFER_OVERFLOW) {
- ERR("fileref_get_filename returned %08x\n", Status);
+ ERR("fileref_get_filename returned %08lx\n", Status);
free_fileref(parfr);
break;
}
Status = fileref_get_filename(parfr, &fn, NULL, NULL);
if (!NT_SUCCESS(Status)) {
- ERR("fileref_get_filename returned %08x\n", Status);
+ ERR("fileref_get_filename returned %08lx\n", Status);
free_fileref(parfr);
ExFreePool(fn.Buffer);
break;
fcb->subvol->fcbs_ptrs[c] = NULL;
}
- if (fcb->list_entry.Flink)
+ if (fcb->list_entry.Flink) {
RemoveEntryList(&fcb->list_entry);
+ if (fcb->subvol && fcb->subvol->dropped && IsListEmpty(&fcb->subvol->fcbs)) {
+ ExDeleteResourceLite(&fcb->subvol->nonpaged->load_tree_lock);
+ ExFreePool(fcb->subvol->nonpaged);
+ ExFreePool(fcb->subvol);
+ }
+ }
+
if (fcb->list_entry_all.Flink)
RemoveEntryList(&fcb->list_entry_all);
#ifdef _DEBUG
if (rc < 0) {
- ERR("fileref %p: refcount now %i\n", fr, rc);
+ ERR("fileref %p: refcount now %li\n", fr, rc);
int3;
}
#endif
Vcb->Vpb->DeviceObject = NULL;
IoReleaseVpbSpinLock(irql);
- RemoveEntryList(&Vcb->list_entry);
+ // FIXME - needs global_loading_lock to be held
+ if (Vcb->list_entry.Flink)
+ RemoveEntryList(&Vcb->list_entry);
if (Vcb->balance.thread) {
Vcb->balance.paused = false;
Status = registry_mark_volume_unmounted(&Vcb->superblock.uuid);
if (!NT_SUCCESS(Status) && Status != STATUS_TOO_LATE)
- WARN("registry_mark_volume_unmounted returned %08x\n", Status);
+ WARN("registry_mark_volume_unmounted returned %08lx\n", Status);
for (i = 0; i < Vcb->calcthreads.num_threads; i++) {
Vcb->calcthreads.threads[i].quit = true;
ZwClose(Vcb->calcthreads.threads[i].handle);
}
- ExDeleteResourceLite(&Vcb->calcthreads.lock);
ExFreePool(Vcb->calcthreads.threads);
time.QuadPart = 0;
if (fileref->fcb->type != BTRFS_TYPE_DIRECTORY && fileref->fcb->inode_item.st_size > 0) {
Status = excise_extents(fileref->fcb->Vcb, fileref->fcb, 0, sector_align(fileref->fcb->inode_item.st_size, fileref->fcb->Vcb->superblock.sector_size), Irp, rollback);
if (!NT_SUCCESS(Status)) {
- ERR("excise_extents returned %08x\n", Status);
+ ERR("excise_extents returned %08lx\n", Status);
return Status;
}
}
} _SEH2_END;
if (!NT_SUCCESS(Status)) {
- ERR("CcSetFileSizes threw exception %08x\n", Status);
+ ERR("CcSetFileSizes threw exception %08lx\n", Status);
return Status;
}
}
} else {
Status = delete_fileref_fcb(fileref, FileObject, Irp, rollback);
if (!NT_SUCCESS(Status)) {
- ERR("delete_fileref_fcb returned %08x\n", Status);
+ ERR("delete_fileref_fcb returned %08lx\n", Status);
ExReleaseResourceLite(fileref->fcb->Header.Resource);
return Status;
}
// remove dir_child from parent
if (fileref->dc) {
- TRACE("delete file %.*S\n", fileref->dc->name.Length / sizeof(WCHAR), fileref->dc->name.Buffer);
+ TRACE("delete file %.*S\n", (int)(fileref->dc->name.Length / sizeof(WCHAR)), fileref->dc->name.Buffer);
ExAcquireResourceExclusiveLite(&fileref->parent->fcb->nonpaged->dir_children_lock, true);
RemoveEntryList(&fileref->dc->list_entry_index);
fileref = ccb ? ccb->fileref : NULL;
TRACE("cleanup called for FileObject %p\n", FileObject);
- TRACE("fileref %p, refcount = %u, open_count = %u\n", fileref, fileref ? fileref->refcount : 0, fileref ? fileref->open_count : 0);
+ TRACE("fileref %p, refcount = %li, open_count = %li\n", fileref, fileref ? fileref->refcount : 0, fileref ? fileref->open_count : 0);
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true);
Status = delete_fileref_fcb(fileref, FileObject, Irp, &rollback);
if (!NT_SUCCESS(Status)) {
- ERR("delete_fileref_fcb returned %08x\n", Status);
+ ERR("delete_fileref_fcb returned %08lx\n", Status);
do_rollback(fcb->Vcb, &rollback);
ExReleaseResourceLite(fileref->fcb->Header.Resource);
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
Status = delete_fileref(fileref, FileObject, oc > 0 && fileref->posix_delete, Irp, &rollback);
if (!NT_SUCCESS(Status)) {
- ERR("delete_fileref returned %08x\n", Status);
+ ERR("delete_fileref returned %08lx\n", Status);
do_rollback(fcb->Vcb, &rollback);
ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
clear_rollback(&rollback);
} else if (FileObject->Flags & FO_CACHE_SUPPORTED && FileObject->SectionObjectPointer->DataSectionObject) {
IO_STATUS_BLOCK iosb;
- CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb);
- if (!NT_SUCCESS(iosb.Status)) {
- ERR("CcFlushCache returned %08x\n", iosb.Status);
+ if (locked) {
+ ExReleaseResourceLite(fcb->Header.Resource);
+ locked = false;
}
+ CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb);
+
+ if (!NT_SUCCESS(iosb.Status))
+ ERR("CcFlushCache returned %08lx\n", iosb.Status);
+
if (!ExIsResourceAcquiredSharedLite(fcb->Header.PagingIoResource)) {
ExAcquireResourceExclusiveLite(fcb->Header.PagingIoResource, true);
ExReleaseResourceLite(fcb->Header.PagingIoResource);
Status = STATUS_SUCCESS;
exit:
- TRACE("returning %08x\n", Status);
+ TRACE("returning %08lx\n", Status);
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
dosnum |= val[i] + 10 - 'a';
}
- TRACE("DOSATTRIB: %08x\n", dosnum);
+ TRACE("DOSATTRIB: %08lx\n", dosnum);
*atts = dosnum;
} _SEH2_END;
if (!NT_SUCCESS(Status)) {
- ERR("MmProbeAndLockPages threw exception %08x\n", Status);
+ ERR("MmProbeAndLockPages threw exception %08lx\n", Status);
IoFreeMdl(Irp->MdlAddress);
goto exit;
}
return Status;
}
+bool check_superblock_checksum(superblock* sb) {
+ switch (sb->csum_type) {
+ case CSUM_TYPE_CRC32C: {
+ uint32_t crc32 = ~calc_crc32c(0xffffffff, (uint8_t*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
+
+ if (crc32 == *((uint32_t*)sb->checksum))
+ return true;
+
+ WARN("crc32 was %08x, expected %08x\n", crc32, *((uint32_t*)sb->checksum));
+
+ break;
+ }
+
+ case CSUM_TYPE_XXHASH: {
+ uint64_t hash = XXH64(&sb->uuid, sizeof(superblock) - sizeof(sb->checksum), 0);
+
+ if (hash == *((uint64_t*)sb->checksum))
+ return true;
+
+ WARN("superblock hash was %I64x, expected %I64x\n", hash, *((uint64_t*)sb->checksum));
+
+ break;
+ }
+
+ case CSUM_TYPE_SHA256: {
+ uint8_t hash[SHA256_HASH_SIZE];
+
+ calc_sha256(hash, &sb->uuid, sizeof(superblock) - sizeof(sb->checksum));
+
+ if (RtlCompareMemory(hash, sb, SHA256_HASH_SIZE) == SHA256_HASH_SIZE)
+ return true;
+
+ WARN("superblock hash was invalid\n");
+
+ break;
+ }
+
+ case CSUM_TYPE_BLAKE2: {
+ uint8_t hash[BLAKE2_HASH_SIZE];
+
+ blake2b(hash, sizeof(hash), &sb->uuid, sizeof(superblock) - sizeof(sb->checksum));
+
+ if (RtlCompareMemory(hash, sb, BLAKE2_HASH_SIZE) == BLAKE2_HASH_SIZE)
+ return true;
+
+ WARN("superblock hash was invalid\n");
+
+ break;
+ }
+
+ default:
+ WARN("unrecognized csum type %x\n", sb->csum_type);
+ }
+
+ return false;
+}
+
static NTSTATUS read_superblock(_In_ device_extension* Vcb, _In_ PDEVICE_OBJECT device, _In_ PFILE_OBJECT fileobj, _In_ uint64_t length) {
NTSTATUS Status;
superblock* sb;
valid_superblocks = 0;
while (superblock_addrs[i] > 0) {
- uint32_t crc32;
-
if (i > 0 && superblock_addrs[i] + to_read > length)
break;
Status = sync_read_phys(device, fileobj, superblock_addrs[i], to_read, (PUCHAR)sb, false);
if (!NT_SUCCESS(Status)) {
- ERR("Failed to read superblock %u: %08x\n", i, Status);
+ ERR("Failed to read superblock %lu: %08lx\n", i, Status);
ExFreePool(sb);
return Status;
}
return STATUS_UNRECOGNIZED_VOLUME;
}
} else {
- TRACE("got superblock %u!\n", i);
+ TRACE("got superblock %lu!\n", i);
- crc32 = ~calc_crc32c(0xffffffff, (uint8_t*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
-
- if (crc32 != *((uint32_t*)sb->checksum))
- WARN("crc32 was %08x, expected %08x\n", crc32, *((uint32_t*)sb->checksum));
- else if (sb->sector_size == 0)
+ if (sb->sector_size == 0)
WARN("superblock sector size was 0\n");
else if (sb->node_size < sizeof(tree_header) + sizeof(internal_node) || sb->node_size > 0x10000)
WARN("invalid node size %x\n", sb->node_size);
else if ((sb->node_size % sb->sector_size) != 0)
WARN("node size %x was not a multiple of sector_size %x\n", sb->node_size, sb->sector_size);
- else if (valid_superblocks == 0 || sb->generation > Vcb->superblock.generation) {
+ else if (check_superblock_checksum(sb) && (valid_superblocks == 0 || sb->generation > Vcb->superblock.generation)) {
RtlCopyMemory(&Vcb->superblock, sb, sizeof(superblock));
valid_superblocks++;
}
r->send_ops = 0;
r->fcbs_version = 0;
r->checked_for_orphans = false;
+ r->dropped = false;
InitializeListHead(&r->fcbs);
RtlZeroMemory(r->fcbs_ptrs, sizeof(LIST_ENTRY*) * 256);
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("error - find_item returned %08x\n", Status);
+ ERR("error - find_item returned %08lx\n", Status);
return Status;
}
ROOT_ITEM* ri = (ROOT_ITEM*)tp.item->data;
if (tp.item->size < offsetof(ROOT_ITEM, byte_limit)) {
- ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, offsetof(ROOT_ITEM, byte_limit));
+ ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, offsetof(ROOT_ITEM, byte_limit));
} else {
TRACE("root %I64x - address %I64x\n", tp.item->key.obj_id, ri->block_number);
Status = add_root(Vcb, tp.item->key.obj_id, ri->block_number, ri->generation, &tp);
if (!NT_SUCCESS(Status)) {
- ERR("add_root returned %08x\n", Status);
+ ERR("add_root returned %08lx\n", Status);
return Status;
}
}
Status = create_root(Vcb, BTRFS_ROOT_DATA_RELOC, &reloc_root, false, 0, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("create_root returned %08x\n", Status);
+ ERR("create_root returned %08lx\n", Status);
return Status;
}
Status = insert_tree_item(Vcb, reloc_root, SUBVOL_ROOT_INODE, TYPE_INODE_ITEM, 0, ii, sizeof(INODE_ITEM), NULL, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("insert_tree_item returned %08x\n", Status);
+ ERR("insert_tree_item returned %08lx\n", Status);
ExFreePool(ii);
return Status;
}
Status = insert_tree_item(Vcb, reloc_root, SUBVOL_ROOT_INODE, TYPE_INODE_REF, SUBVOL_ROOT_INODE, ir, irlen, NULL, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("insert_tree_item returned %08x\n", Status);
+ ERR("insert_tree_item returned %08lx\n", Status);
ExFreePool(ir);
return Status;
}
Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, false, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("error - find_item returned %08x\n", Status);
+ ERR("error - find_item returned %08lx\n", Status);
return Status;
}
if (tp.item->key.offset > lastaddr) {
Status = add_space_entry(&dev->space, NULL, lastaddr, tp.item->key.offset - lastaddr);
if (!NT_SUCCESS(Status)) {
- ERR("add_space_entry returned %08x\n", Status);
+ ERR("add_space_entry returned %08lx\n", Status);
return Status;
}
}
lastaddr = tp.item->key.offset + de->length;
} else {
- ERR("(%I64x,%x,%I64x) was %u bytes, expected %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DEV_EXTENT));
+ ERR("(%I64x,%x,%I64x) was %u bytes, expected %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DEV_EXTENT));
}
}
if (lastaddr < dev->devitem.num_bytes) {
Status = add_space_entry(&dev->space, NULL, lastaddr, dev->devitem.num_bytes - lastaddr);
if (!NT_SUCCESS(Status)) {
- ERR("add_space_entry returned %08x\n", Status);
+ ERR("add_space_entry returned %08lx\n", Status);
return Status;
}
}
Status = dev_ioctl(devobj, IOCTL_STORAGE_GET_HOTPLUG_INFO, NULL, 0, &shi, sizeof(STORAGE_HOTPLUG_INFO), true, NULL);
if (!NT_SUCCESS(Status)) {
- ERR("dev_ioctl returned %08x\n", Status);
+ ERR("dev_ioctl returned %08lx\n", Status);
return false;
}
Status = dev_ioctl(devobj, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &cc, sizeof(ULONG), true, &iosb);
if (!NT_SUCCESS(Status)) {
- ERR("dev_ioctl returned %08x\n", Status);
+ ERR("dev_ioctl returned %08lx\n", Status);
return 0;
}
&sdn, sizeof(STORAGE_DEVICE_NUMBER), true, NULL);
if (!NT_SUCCESS(Status)) {
- WARN("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x\n", Status);
+ WARN("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08lx\n", Status);
dev->disk_num = 0xffffffff;
dev->part_num = 0xffffffff;
} else {
apte, aptelen, true, NULL);
if (!NT_SUCCESS(Status))
- TRACE("IOCTL_ATA_PASS_THROUGH returned %08x for IDENTIFY DEVICE\n", Status);
+ TRACE("IOCTL_ATA_PASS_THROUGH returned %08lx for IDENTIFY DEVICE\n", Status);
else {
IDENTIFY_DEVICE_DATA* idd = (IDENTIFY_DEVICE_DATA*)((uint8_t*)apte + sizeof(ATA_PASS_THROUGH_EX));
Status = find_item(Vcb, Vcb->chunk_root, &tp, &searchkey, false, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("error - find_item returned %08x\n", Status);
+ ERR("error - find_item returned %08lx\n", Status);
return Status;
}
if (tp.item->key.obj_id == 1 && tp.item->key.obj_type == TYPE_DEV_ITEM) {
if (tp.item->size < sizeof(DEV_ITEM)) {
- ERR("(%I64x,%x,%I64x) was %u bytes, expected %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DEV_ITEM));
+ ERR("(%I64x,%x,%I64x) was %u bytes, expected %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DEV_ITEM));
} else {
DEV_ITEM* di = (DEV_ITEM*)tp.item->data;
LIST_ENTRY* le;
}
} else if (tp.item->key.obj_type == TYPE_CHUNK_ITEM) {
if (tp.item->size < sizeof(CHUNK_ITEM)) {
- ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(CHUNK_ITEM));
+ ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(CHUNK_ITEM));
} else {
c = ExAllocatePoolWithTag(NonPagedPool, sizeof(chunk), ALLOC_TAG);
for (i = 0; i < c->chunk_item->num_stripes; i++) {
c->devices[i] = find_device_from_uuid(Vcb, &cis[i].dev_uuid);
- TRACE("device %I64u = %p\n", i, c->devices[i]);
+ TRACE("device %u = %p\n", i, c->devices[i]);
if (!c->devices[i]) {
ERR("missing device\n");
space_list_subtract(c, false, c->offset + off_start, off_end - off_start, NULL);
}
}
- } else { // SINGLE, DUPLICATE, RAID1
+ } else { // SINGLE, DUPLICATE, RAID1, RAID1C3, RAID1C4
for (j = 0; j < ci->num_stripes; j++) {
if (cis[j].offset + ci->size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) {
TRACE("cut out superblock in chunk %I64x\n", c->offset);
} else if (c->chunk_item->type & BLOCK_FLAG_RAID6) {
nfactor = Vcb->superblock.num_devices - 2;
dfactor = Vcb->superblock.num_devices;
+ } else if (c->chunk_item->type & BLOCK_FLAG_RAID1C3) {
+ nfactor = 1;
+ dfactor = 3;
+ } else if (c->chunk_item->type & BLOCK_FLAG_RAID1C4) {
+ nfactor = 1;
+ dfactor = 4;
} else {
nfactor = 1;
dfactor = 1;
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, false, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("error - find_item returned %08x\n", Status);
+ ERR("error - find_item returned %08lx\n", Status);
return Status;
}
Vcb->superblock.bytes_used += chunk_estimate_phys_size(Vcb, c, bgi->used);
} else {
- ERR("(%I64x;%I64x,%x,%I64x) is %u bytes, expected %u\n",
+ ERR("(%I64x;%I64x,%x,%I64x) is %u bytes, expected %Iu\n",
Vcb->extent_root->id, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(BLOCK_GROUP_ITEM));
}
}
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("error - find_item returned %08x\n", Status);
+ ERR("error - find_item returned %08lx\n", Status);
goto end;
}
}
if (tp.item->size < sizeof(DIR_ITEM)) {
- ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM));
+ ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM));
goto end;
}
di = (DIR_ITEM*)tp.item->data;
if (tp.item->size < sizeof(DIR_ITEM) - 1 + di->n) {
- ERR("(%I64x,%x,%I64x) was %u bytes, expected %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM) - 1 + di->n);
+ ERR("(%I64x,%x,%I64x) was %u bytes, expected %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM) - 1 + di->n);
goto end;
}
}
InitializeListHead(&Vcb->calcthreads.job_list);
- ExInitializeResourceLite(&Vcb->calcthreads.lock);
+ KeInitializeSpinLock(&Vcb->calcthreads.spinlock);
KeInitializeEvent(&Vcb->calcthreads.event, NotificationEvent, false);
RtlZeroMemory(Vcb->calcthreads.threads, sizeof(drv_calc_thread) * Vcb->calcthreads.num_threads);
NTSTATUS Status;
Vcb->calcthreads.threads[i].DeviceObject = DeviceObject;
+ Vcb->calcthreads.threads[i].number = i;
KeInitializeEvent(&Vcb->calcthreads.threads[i].finished, NotificationEvent, false);
Status = PsCreateSystemThread(&Vcb->calcthreads.threads[i].handle, 0, &oa, NULL, NULL, calc_thread, &Vcb->calcthreads.threads[i]);
if (!NT_SUCCESS(Status)) {
ULONG j;
- ERR("PsCreateSystemThread returned %08x\n", Status);
+ ERR("PsCreateSystemThread returned %08lx\n", Status);
for (j = 0; j < i; j++) {
Vcb->calcthreads.threads[i].quit = true;
Status = dev_ioctl(DeviceObject, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, &mdn, sizeof(MOUNTDEV_NAME), true, NULL);
if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) {
- ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status);
+ ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08lx\n", Status);
return false;
}
Status = dev_ioctl(DeviceObject, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, mdn2, mdnsize, true, NULL);
if (!NT_SUCCESS(Status)) {
- ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status);
+ ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08lx\n", Status);
ExFreePool(mdn2);
return false;
}
Status = IoGetDeviceInterfaces((PVOID)guid, NULL, 0, &list);
if (!NT_SUCCESS(Status)) {
- ERR("IoGetDeviceInterfaces returned %08x\n", Status);
+ ERR("IoGetDeviceInterfaces returned %08lx\n", Status);
return Status;
}
NTSTATUS Status;
ULONG to_read;
superblock* sb;
- uint32_t crc32;
UNICODE_STRING pnp_name;
const GUID* guid;
Status = sync_read_phys(DeviceObject, NULL, superblock_addrs[0], to_read, (PUCHAR)sb, true);
if (!NT_SUCCESS(Status)) {
- ERR("sync_read_phys returned %08x\n", Status);
+ ERR("sync_read_phys returned %08lx\n", Status);
goto end;
}
goto end;
}
- crc32 = ~calc_crc32c(0xffffffff, (uint8_t*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
-
- if (crc32 != *((uint32_t*)sb->checksum)) {
- WARN("crc32 was %08x, expected %08x\n", crc32, *((uint32_t*)sb->checksum));
+ if (!check_superblock_checksum(sb)) {
Status = STATUS_SUCCESS;
goto end;
}
Status = get_device_pnp_name(DeviceObject, &pnp_name, &guid);
if (!NT_SUCCESS(Status)) {
- WARN("get_device_pnp_name returned %08x\n", Status);
+ WARN("get_device_pnp_name returned %08lx\n", Status);
pnp_name.Length = 0;
}
Status = sync_read_phys(device, fileobj, superblock_addrs[0], to_read, (PUCHAR)sb, true);
if (!NT_SUCCESS(Status)) {
- ERR("Failed to read superblock: %08x\n", Status);
+ ERR("Failed to read superblock: %08lx\n", Status);
ExFreePool(sb);
return false;
}
ExFreePool(sb);
return false;
} else {
- uint32_t crc32 = ~calc_crc32c(0xffffffff, (uint8_t*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
-
- if (crc32 != *((uint32_t*)sb->checksum)) {
- WARN("crc32 was %08x, expected %08x\n", crc32, *((uint32_t*)sb->checksum));
+ if (!check_superblock_checksum(sb)) {
ExFreePool(sb);
return false;
}
Status = check_mount_device(DeviceToMount, ¬_pnp);
if (!NT_SUCCESS(Status))
- WARN("check_mount_device returned %08x\n", Status);
+ WARN("check_mount_device returned %08lx\n", Status);
if (!not_pnp) {
Status = STATUS_UNRECOGNIZED_VOLUME;
&gli, sizeof(gli), true, NULL);
if (!NT_SUCCESS(Status)) {
- ERR("error reading length information: %08x\n", Status);
+ ERR("error reading length information: %08lx\n", Status);
goto exit;
}
Status = IoCreateDevice(drvobj, sizeof(device_extension), NULL, FILE_DEVICE_DISK_FILE_SYSTEM, 0, false, &NewDeviceObject);
if (!NT_SUCCESS(Status)) {
- ERR("IoCreateDevice returned %08x\n", Status);
+ ERR("IoCreateDevice returned %08lx\n", Status);
Status = STATUS_UNRECOGNIZED_VOLUME;
goto exit;
}
Status = registry_load_volume_options(Vcb);
if (!NT_SUCCESS(Status)) {
- ERR("registry_load_volume_options returned %08x\n", Status);
+ ERR("registry_load_volume_options returned %08lx\n", Status);
goto exit;
}
+ if (pdode && RtlCompareMemory(&boot_uuid, &pdode->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID) && boot_subvol != 0)
+ Vcb->options.subvol_id = boot_subvol;
+
if (pdode && pdode->children_loaded < pdode->num_children && (!Vcb->options.allow_degraded || !finished_probing || degraded_wait)) {
- ERR("could not mount as %u device(s) missing\n", pdode->num_children - pdode->children_loaded);
+ ERR("could not mount as %I64u device(s) missing\n", pdode->num_children - pdode->children_loaded);
Status = STATUS_DEVICE_NOT_READY;
goto exit;
}
goto exit;
}
+ if (!(Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_METADATA_UUID))
+ Vcb->superblock.metadata_uuid = Vcb->superblock.uuid;
+
Vcb->readonly = false;
if (Vcb->superblock.compat_ro_flags & ~COMPAT_RO_SUPPORTED) {
WARN("mounting read-only because of unsupported flags (%I64x)\n", Vcb->superblock.compat_ro_flags & ~COMPAT_RO_SUPPORTED);
Vcb->superblock.generation++;
Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF;
+ if (Vcb->superblock.log_tree_addr != 0) {
+ FIXME("FIXME - replay transaction log (clearing for now)\n");
+ Vcb->superblock.log_tree_addr = 0;
+ }
+
+ switch (Vcb->superblock.csum_type) {
+ case CSUM_TYPE_CRC32C:
+ Vcb->csum_size = sizeof(uint32_t);
+ break;
+
+ case CSUM_TYPE_XXHASH:
+ Vcb->csum_size = sizeof(uint64_t);
+ break;
+
+ case CSUM_TYPE_SHA256:
+ Vcb->csum_size = SHA256_HASH_SIZE;
+ break;
+
+ case CSUM_TYPE_BLAKE2:
+ Vcb->csum_size = BLAKE2_HASH_SIZE;
+ break;
+
+ default:
+ ERR("unrecognized csum type %x\n", Vcb->superblock.csum_type);
+ break;
+ }
+
InitializeListHead(&Vcb->devices);
dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(device), ALLOC_TAG);
if (!dev) {
InitializeListHead(&Vcb->sys_chunks);
Status = load_sys_chunks(Vcb);
if (!NT_SUCCESS(Status)) {
- ERR("load_sys_chunks returned %08x\n", Status);
+ ERR("load_sys_chunks returned %08lx\n", Status);
goto exit;
}
Status = load_chunk_root(Vcb, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("load_chunk_root returned %08x\n", Status);
+ ERR("load_chunk_root returned %08lx\n", Status);
goto exit;
}
if (Vcb->superblock.num_devices > 1) {
if (Vcb->devices_loaded < Vcb->superblock.num_devices && (!Vcb->options.allow_degraded || !finished_probing)) {
- ERR("could not mount as %u device(s) missing\n", Vcb->superblock.num_devices - Vcb->devices_loaded);
+ ERR("could not mount as %I64u device(s) missing\n", Vcb->superblock.num_devices - Vcb->devices_loaded);
IoRaiseInformationalHardError(IO_ERR_INTERNAL_ERROR, NULL, NULL);
Status = look_for_roots(Vcb, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("look_for_roots returned %08x\n", Status);
+ ERR("look_for_roots returned %08lx\n", Status);
goto exit;
}
if (!Vcb->readonly) {
Status = find_chunk_usage(Vcb, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("find_chunk_usage returned %08x\n", Status);
+ ERR("find_chunk_usage returned %08lx\n", Status);
goto exit;
}
}
Status = clear_free_space_cache(Vcb, &batchlist, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("clear_free_space_cache returned %08x\n", Status);
+ ERR("clear_free_space_cache returned %08lx\n", Status);
clear_batch_list(Vcb, &batchlist);
goto exit;
}
Status = commit_batch_list(Vcb, &batchlist, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("commit_batch_list returned %08x\n", Status);
+ ERR("commit_batch_list returned %08lx\n", Status);
goto exit;
}
Status = load_dir_children(Vcb, root_fcb, true, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("load_dir_children returned %08x\n", Status);
+ ERR("load_dir_children returned %08lx\n", Status);
goto exit;
}
Status = find_item(Vcb, root_fcb->subvol, &tp, &searchkey, false, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("error - find_item returned %08x\n", Status);
+ ERR("error - find_item returned %08lx\n", Status);
goto exit;
}
root_fcb->atts = get_file_attributes(Vcb, root_fcb->subvol, root_fcb->inode, root_fcb->type, false, false, Irp);
+ if (root_fcb->subvol->id == BTRFS_ROOT_FSTREE)
+ root_fcb->atts &= ~FILE_ATTRIBUTE_HIDDEN;
+
Vcb->root_fileref = create_fileref(Vcb);
if (!Vcb->root_fileref) {
ERR("out of memory\n");
Status = find_disk_holes(Vcb, dev2, Irp);
if (!NT_SUCCESS(Status)) {
- ERR("find_disk_holes returned %08x\n", Status);
+ ERR("find_disk_holes returned %08lx\n", Status);
goto exit;
}
Status = PsCreateSystemThread(&Vcb->flush_thread_handle, 0, &oa, NULL, NULL, flush_thread, NewDeviceObject);
if (!NT_SUCCESS(Status)) {
- ERR("PsCreateSystemThread returned %08x\n", Status);
+ ERR("PsCreateSystemThread returned %08lx\n", Status);
goto exit;
}
Status = create_calc_threads(NewDeviceObject);
if (!NT_SUCCESS(Status)) {
- ERR("create_calc_threads returned %08x\n", Status);
+ ERR("create_calc_threads returned %08lx\n", Status);
goto exit;
}
Status = registry_mark_volume_mounted(&Vcb->superblock.uuid);
if (!NT_SUCCESS(Status))
- WARN("registry_mark_volume_mounted returned %08x\n", Status);
+ WARN("registry_mark_volume_mounted returned %08lx\n", Status);
Status = look_for_balance_item(Vcb);
if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND)
- WARN("look_for_balance_item returned %08x\n", Status);
+ WARN("look_for_balance_item returned %08lx\n", Status);
Status = STATUS_SUCCESS;
static NTSTATUS verify_device(_In_ device_extension* Vcb, _Inout_ device* dev) {
NTSTATUS Status;
superblock* sb;
- uint32_t crc32;
ULONG to_read, cc;
if (!dev->devobj)
Status = dev_ioctl(dev->devobj, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &cc, sizeof(ULONG), true, &iosb);
if (IoIsErrorUserInduced(Status)) {
- ERR("IOCTL_STORAGE_CHECK_VERIFY returned %08x (user-induced)\n", Status);
+ ERR("IOCTL_STORAGE_CHECK_VERIFY returned %08lx (user-induced)\n", Status);
if (Vcb->vde) {
pdo_device_extension* pdode = Vcb->vde->pdode;
ExReleaseResourceLite(&pdode->child_lock);
}
} else if (!NT_SUCCESS(Status)) {
- ERR("IOCTL_STORAGE_CHECK_VERIFY returned %08x\n", Status);
+ ERR("IOCTL_STORAGE_CHECK_VERIFY returned %08lx\n", Status);
return Status;
} else if (iosb.Information < sizeof(ULONG)) {
ERR("iosb.Information was too short\n");
Status = sync_read_phys(dev->devobj, dev->fileobj, superblock_addrs[0], to_read, (PUCHAR)sb, true);
if (!NT_SUCCESS(Status)) {
- ERR("Failed to read superblock: %08x\n", Status);
+ ERR("Failed to read superblock: %08lx\n", Status);
ExFreePool(sb);
return Status;
}
return STATUS_WRONG_VOLUME;
}
- crc32 = ~calc_crc32c(0xffffffff, (uint8_t*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
- TRACE("crc32 was %08x, expected %08x\n", crc32, *((uint32_t*)sb->checksum));
-
- if (crc32 != *((uint32_t*)sb->checksum)) {
- ERR("checksum error\n");
+ if (!check_superblock_checksum(sb)) {
ExFreePool(sb);
return STATUS_WRONG_VOLUME;
}
}
end:
- TRACE("returning %08x\n", Status);
+ TRACE("returning %08lx\n", Status);
if (Irp) {
Irp->IoStatus.Status = Status;
fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
exit:
- TRACE("returning %08x\n", Status);
+ TRACE("returning %08lx\n", Status);
if (top_level)
IoSetTopLevelIrp(NULL);
device_extension* Vcb = CONTAINING_RECORD(le, device_extension, list_entry);
volume_device_extension* vde = Vcb->vde;
+ PDEVICE_OBJECT devobj = vde ? vde->device : NULL;
TRACE("shutting down Vcb %p\n", Vcb);
if (vde)
InterlockedIncrement(&vde->open_count);
+ if (devobj)
+ ObReferenceObject(devobj);
+
dismount_volume(Vcb, true, Irp);
if (vde) {
PDEVICE_OBJECT mountmgr;
PFILE_OBJECT mountmgrfo;
KIRQL irql;
+ PVPB newvpb;
RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr);
if (!NT_SUCCESS(Status))
- ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
+ ERR("IoGetDeviceObjectPointer returned %08lx\n", Status);
else {
remove_drive_letter(mountmgr, &vde->name);
vde->removing = true;
+ newvpb = ExAllocatePoolWithTag(NonPagedPool, sizeof(VPB), ALLOC_TAG);
+ if (!newvpb) {
+ ERR("out of memory\n");
+ return;
+ }
+
+ RtlZeroMemory(newvpb, sizeof(VPB));
+
+ newvpb->Type = IO_TYPE_VPB;
+ newvpb->Size = sizeof(VPB);
+ newvpb->RealDevice = newvpb->DeviceObject = vde->device;
+ newvpb->Flags = VPB_DIRECT_WRITES_ALLOWED;
+
IoAcquireVpbSpinLock(&irql);
- vde->device->Vpb->DeviceObject = vde->device;
+ vde->device->Vpb = newvpb;
IoReleaseVpbSpinLock(irql);
if (InterlockedDecrement(&vde->open_count) == 0)
free_vol(vde);
}
+ if (devobj)
+ ObDereferenceObject(devobj);
+
le = le2;
}
return Status;
}
+static bool device_still_valid(device* dev, uint64_t expected_generation) {
+ NTSTATUS Status;
+ unsigned int to_read;
+ superblock* sb;
+
+ to_read = (unsigned int)(dev->devobj->SectorSize == 0 ? sizeof(superblock) : sector_align(sizeof(superblock), dev->devobj->SectorSize));
+
+ sb = ExAllocatePoolWithTag(NonPagedPool, to_read, ALLOC_TAG);
+ if (!sb) {
+ ERR("out of memory\n");
+ return false;
+ }
+
+ Status = sync_read_phys(dev->devobj, dev->fileobj, superblock_addrs[0], to_read, (PUCHAR)sb, false);
+ if (!NT_SUCCESS(Status)) {
+ ERR("sync_read_phys returned %08lx\n", Status);
+ ExFreePool(sb);
+ return false;
+ }
+
+ if (sb->magic != BTRFS_MAGIC) {
+ ERR("magic not found\n");
+ ExFreePool(sb);
+ return false;
+ }
+
+ if (!check_superblock_checksum(sb)) {
+ ExFreePool(sb);
+ return false;
+ }
+
+ if (sb->generation > expected_generation) {
+ ERR("generation was %I64x, expected %I64x\n", sb->generation, expected_generation);
+ ExFreePool(sb);
+ return false;
+ }
+
+ ExFreePool(sb);
+
+ return true;
+}
+
+_Function_class_(IO_WORKITEM_ROUTINE)
+static void __stdcall check_after_wakeup(PDEVICE_OBJECT DeviceObject, PVOID con) {
+ device_extension* Vcb = (device_extension*)con;
+ LIST_ENTRY* le;
+
+ UNUSED(DeviceObject);
+
+ ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
+
+ le = Vcb->devices.Flink;
+
+ // FIXME - do reads in parallel?
+
+ while (le != &Vcb->devices) {
+ device* dev = CONTAINING_RECORD(le, device, list_entry);
+
+ if (dev->devobj) {
+ if (!device_still_valid(dev, Vcb->superblock.generation - 1)) {
+ PDEVICE_OBJECT voldev = Vcb->Vpb->RealDevice;
+ KIRQL irql;
+ PVPB newvpb;
+
+ WARN("forcing remount\n");
+
+ newvpb = ExAllocatePoolWithTag(NonPagedPool, sizeof(VPB), ALLOC_TAG);
+ if (!newvpb) {
+ ERR("out of memory\n");
+ return;
+ }
+
+ RtlZeroMemory(newvpb, sizeof(VPB));
+
+ newvpb->Type = IO_TYPE_VPB;
+ newvpb->Size = sizeof(VPB);
+ newvpb->RealDevice = voldev;
+ newvpb->Flags = VPB_DIRECT_WRITES_ALLOWED;
+
+ Vcb->removing = true;
+
+ IoAcquireVpbSpinLock(&irql);
+ voldev->Vpb = newvpb;
+ IoReleaseVpbSpinLock(irql);
+
+ Vcb->vde = NULL;
+
+ ExReleaseResourceLite(&Vcb->tree_lock);
+
+ if (Vcb->open_files == 0)
+ uninit(Vcb);
+ else { // remove from VcbList
+ ExAcquireResourceExclusiveLite(&global_loading_lock, true);
+ RemoveEntryList(&Vcb->list_entry);
+ Vcb->list_entry.Flink = NULL;
+ ExReleaseResourceLite(&global_loading_lock);
+ }
+
+ return;
+ }
+ }
+
+ le = le->Flink;
+ }
+
+ ExReleaseResourceLite(&Vcb->tree_lock);
+}
+
_Dispatch_type_(IRP_MJ_POWER)
_Function_class_(DRIVER_DISPATCH)
static NTSTATUS __stdcall drv_power(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
device_extension* Vcb = DeviceObject->DeviceExtension;
bool top_level;
- FsRtlEnterFileSystem();
+ // no need for FsRtlEnterFileSystem, as this only ever gets called in a system thread
top_level = is_top_level(Irp);
if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
volume_device_extension* vde = DeviceObject->DeviceExtension;
+ if (IrpSp->MinorFunction == IRP_MN_QUERY_POWER && IrpSp->Parameters.Power.Type == SystemPowerState &&
+ IrpSp->Parameters.Power.State.SystemState != PowerSystemWorking && vde->mounted_device) {
+ device_extension* Vcb2 = vde->mounted_device->DeviceExtension;
+
+ /* If power state is about to go to sleep or hibernate, do a flush. We do this on IRP_MJ_QUERY_POWER
+ * rather than IRP_MJ_SET_POWER because we know that the hard disks are still awake. */
+
+ if (Vcb2) {
+ ExAcquireResourceExclusiveLite(&Vcb2->tree_lock, true);
+
+ if (Vcb2->need_write && !Vcb2->readonly) {
+ TRACE("doing protective flush on power state change\n");
+ Status = do_write(Vcb2, NULL);
+ } else
+ Status = STATUS_SUCCESS;
+
+ free_trees(Vcb2);
+
+ if (!NT_SUCCESS(Status))
+ ERR("do_write returned %08lx\n", Status);
+
+ ExReleaseResourceLite(&Vcb2->tree_lock);
+ }
+ } else if (IrpSp->MinorFunction == IRP_MN_SET_POWER && IrpSp->Parameters.Power.Type == SystemPowerState &&
+ IrpSp->Parameters.Power.State.SystemState == PowerSystemWorking && vde->mounted_device) {
+ device_extension* Vcb2 = vde->mounted_device->DeviceExtension;
+
+ /* If waking up, make sure that the FS hasn't been changed while we've been out (e.g., by dual-boot Linux) */
+
+ if (Vcb2) {
+ PIO_WORKITEM work_item;
+
+ work_item = IoAllocateWorkItem(DeviceObject);
+ if (!work_item) {
+ ERR("out of memory\n");
+ } else
+ IoQueueWorkItem(work_item, check_after_wakeup, DelayedWorkQueue, Vcb2);
+ }
+ }
+
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
Status = PoCallDriver(vde->attached_device, Irp);
if (top_level)
IoSetTopLevelIrp(NULL);
- FsRtlExitFileSystem();
-
return Status;
}
Status = IoGetDeviceObjectPointer(&log_device, FILE_WRITE_DATA, &comfo, &comdo);
if (!NT_SUCCESS(Status)) {
- ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
+ ERR("IoGetDeviceObjectPointer returned %08lx\n", Status);
if (first_time) {
OBJECT_ATTRIBUTES oa;
Status = PsCreateSystemThread(&serial_thread_handle, 0, &oa, NULL, NULL, serial_thread, NULL);
if (!NT_SUCCESS(Status)) {
- ERR("PsCreateSystemThread returned %08x\n", Status);
+ ERR("PsCreateSystemThread returned %08lx\n", Status);
return;
}
}
}
#endif
-#ifndef __REACTOS__
+#if !defined(__REACTOS__) && (defined(_X86_) || defined(_AMD64_))
static void check_cpu() {
unsigned int cpuInfo[4];
+ bool have_sse42;
+
#ifndef _MSC_VER
__get_cpuid(1, &cpuInfo[0], &cpuInfo[1], &cpuInfo[2], &cpuInfo[3]);
have_sse42 = cpuInfo[2] & bit_SSE4_2;
have_sse2 = cpuInfo[3] & bit_SSE2;
#else
- __cpuid(cpuInfo, 1);
- have_sse42 = cpuInfo[2] & (1 << 20);
- have_sse2 = cpuInfo[3] & (1 << 26);
+ __cpuid(cpuInfo, 1);
+ have_sse42 = cpuInfo[2] & (1 << 20);
+ have_sse2 = cpuInfo[3] & (1 << 26);
#endif
- if (have_sse42)
+ if (have_sse42) {
TRACE("SSE4.2 is supported\n");
- else
+ calc_crc32c = calc_crc32c_hw;
+ } else
TRACE("SSE4.2 not supported\n");
if (have_sse2)
FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE | FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_ALERT, NULL, 0);
if (!NT_SUCCESS(Status)) {
- ERR("ZwCreateFile returned %08x\n", Status);
+ ERR("ZwCreateFile returned %08lx\n", Status);
goto end;
}
Status = ZwQueryInformationFile(log_handle, &iosb, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
if (!NT_SUCCESS(Status)) {
- ERR("ZwQueryInformationFile returned %08x\n", Status);
+ ERR("ZwQueryInformationFile returned %08lx\n", Status);
goto end;
}
Status = ZwSetInformationFile(log_handle, &iosb, &fpi, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation);
if (!NT_SUCCESS(Status)) {
- ERR("ZwSetInformationFile returned %08x\n", Status);
+ ERR("ZwSetInformationFile returned %08lx\n", Status);
goto end;
}
Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, (void*)delim, sizeof(delim) - 1, NULL, NULL);
if (!NT_SUCCESS(Status)) {
- ERR("ZwWriteFile returned %08x\n", Status);
+ ERR("ZwWriteFile returned %08lx\n", Status);
goto end;
}
}
ExFreePool(dateline);
if (!NT_SUCCESS(Status)) {
- ERR("ZwWriteFile returned %08x\n", Status);
+ ERR("ZwWriteFile returned %08lx\n", Status);
goto end;
}
}
LIST_ENTRY* le;
NTSTATUS Status;
UNICODE_STRING volname;
- ULONG i, j;
+ ULONG i;
+ WCHAR* s;
pdo_device_extension* pdode = NULL;
PDEVICE_OBJECT voldev;
volume_device_extension* vde;
+ UNICODE_STRING arc_name_us;
+ WCHAR* anp;
+
+ static const WCHAR arc_name_prefix[] = L"\\ArcName\\btrfs(";
+
+ WCHAR arc_name[(sizeof(arc_name_prefix) / sizeof(WCHAR)) - 1 + 37];
TRACE("(%p, %p)\n", DriverObject, PhysicalDeviceObject);
}
RtlCopyMemory(volname.Buffer, BTRFS_VOLUME_PREFIX, sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR));
+ RtlCopyMemory(arc_name, arc_name_prefix, sizeof(arc_name_prefix) - sizeof(WCHAR));
+
+ anp = &arc_name[(sizeof(arc_name_prefix) / sizeof(WCHAR)) - 1];
+ s = &volname.Buffer[(sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1];
- j = (sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1;
for (i = 0; i < 16; i++) {
- volname.Buffer[j] = hex_digit(pdode->uuid.uuid[i] >> 4); j++;
- volname.Buffer[j] = hex_digit(pdode->uuid.uuid[i] & 0xf); j++;
+ *s = *anp = hex_digit(pdode->uuid.uuid[i] >> 4);
+ s++;
+ anp++;
+
+ *s = *anp = hex_digit(pdode->uuid.uuid[i] & 0xf);
+ s++;
+ anp++;
if (i == 3 || i == 5 || i == 7 || i == 9) {
- volname.Buffer[j] = '-';
- j++;
+ *s = *anp = '-';
+ s++;
+ anp++;
}
}
- volname.Buffer[j] = '}';
+ *s = '}';
+ *anp = ')';
Status = IoCreateDevice(drvobj, sizeof(volume_device_extension), &volname, FILE_DEVICE_DISK,
WdmlibRtlIsNtDdiVersionAvailable(NTDDI_WIN8) ? FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL : 0, false, &voldev);
if (!NT_SUCCESS(Status)) {
- ERR("IoCreateDevice returned %08x\n", Status);
+ ERR("IoCreateDevice returned %08lx\n", Status);
goto end2;
}
+ arc_name_us.Buffer = arc_name;
+ arc_name_us.Length = arc_name_us.MaximumLength = sizeof(arc_name);
+
+ Status = IoCreateSymbolicLink(&arc_name_us, &volname);
+ if (!NT_SUCCESS(Status))
+ WARN("IoCreateSymbolicLink returned %08lx\n", Status);
+
voldev->SectorSize = PhysicalDeviceObject->SectorSize;
voldev->Flags |= DO_DIRECT_IO;
Status = IoRegisterDeviceInterface(PhysicalDeviceObject, &GUID_DEVINTERFACE_VOLUME, NULL, &vde->bus_name);
if (!NT_SUCCESS(Status))
- WARN("IoRegisterDeviceInterface returned %08x\n", Status);
+ WARN("IoRegisterDeviceInterface returned %08lx\n", Status);
vde->attached_device = IoAttachDeviceToDeviceStack(voldev, PhysicalDeviceObject);
if (pdode->removable)
voldev->Characteristics |= FILE_REMOVABLE_MEDIA;
+ if (RtlCompareMemory(&boot_uuid, &pdode->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
+ voldev->Flags |= DO_SYSTEM_BOOT_PARTITION;
+ PhysicalDeviceObject->Flags |= DO_SYSTEM_BOOT_PARTITION;
+ }
+
voldev->Flags &= ~DO_DEVICE_INITIALIZING;
Status = IoSetDeviceInterfaceState(&vde->bus_name, true);
if (!NT_SUCCESS(Status))
- WARN("IoSetDeviceInterfaceState returned %08x\n", Status);
+ WARN("IoSetDeviceInterfaceState returned %08lx\n", Status);
Status = STATUS_SUCCESS;
TRACE("DriverEntry\n");
-#ifndef __REACTOS__
+#if !defined(__REACTOS__) && (defined(_X86_) || defined(_AMD64_))
check_cpu();
#endif
Status = IoCreateDevice(DriverObject, sizeof(control_device_extension), &device_nameW, FILE_DEVICE_DISK_FILE_SYSTEM,
FILE_DEVICE_SECURE_OPEN, false, &DeviceObject);
if (!NT_SUCCESS(Status)) {
- ERR("IoCreateDevice returned %08x\n", Status);
+ ERR("IoCreateDevice returned %08lx\n", Status);
return Status;
}
Status = IoCreateSymbolicLink(&dosdevice_nameW, &device_nameW);
if (!NT_SUCCESS(Status)) {
- ERR("IoCreateSymbolicLink returned %08x\n", Status);
+ ERR("IoCreateSymbolicLink returned %08lx\n", Status);
return Status;
}
InitializeObjectAttributes(&oa, RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
Status = ZwCreateKey(®h, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos);
if (!NT_SUCCESS(Status)) {
- ERR("ZwCreateKey returned %08x\n", Status);
+ ERR("ZwCreateKey returned %08lx\n", Status);
return Status;
}
Status = IoCreateDevice(DriverObject, sizeof(bus_device_extension), NULL, FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN, false, &busobj);
if (!NT_SUCCESS(Status)) {
- ERR("IoCreateDevice returned %08x\n", Status);
+ ERR("IoCreateDevice returned %08lx\n", Status);
return Status;
}
Status = IoReportDetectedDevice(drvobj, InterfaceTypeUndefined, 0xFFFFFFFF, 0xFFFFFFFF,
NULL, NULL, 0, &bde->buspdo);
if (!NT_SUCCESS(Status)) {
- ERR("IoReportDetectedDevice returned %08x\n", Status);
+ ERR("IoReportDetectedDevice returned %08lx\n", Status);
return Status;
}
Status = IoRegisterDeviceInterface(bde->buspdo, &BtrfsBusInterface, NULL, &bde->bus_name);
if (!NT_SUCCESS(Status))
- WARN("IoRegisterDeviceInterface returned %08x\n", Status);
+ WARN("IoRegisterDeviceInterface returned %08lx\n", Status);
bde->attached_device = IoAttachDeviceToDeviceStack(busobj, bde->buspdo);
Status = IoSetDeviceInterfaceState(&bde->bus_name, true);
if (!NT_SUCCESS(Status))
- WARN("IoSetDeviceInterfaceState returned %08x\n", Status);
+ WARN("IoSetDeviceInterfaceState returned %08lx\n", Status);
IoInvalidateDeviceRelations(bde->buspdo, BusRelations);
Status = PsCreateSystemThread(°raded_wait_handle, 0, &system_thread_attributes, NULL, NULL, degraded_wait_thread, NULL);
if (!NT_SUCCESS(Status))
- WARN("PsCreateSystemThread returned %08x\n", Status);
+ WARN("PsCreateSystemThread returned %08lx\n", Status);
ExInitializeResourceLite(&boot_lock);
Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
(PVOID)&GUID_DEVINTERFACE_VOLUME, DriverObject, volume_notification, DriverObject, ¬ification_entry2);
if (!NT_SUCCESS(Status))
- ERR("IoRegisterPlugPlayNotification returned %08x\n", Status);
+ ERR("IoRegisterPlugPlayNotification returned %08lx\n", Status);
Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
(PVOID)&GUID_DEVINTERFACE_HIDDEN_VOLUME, DriverObject, volume_notification, DriverObject, ¬ification_entry3);
if (!NT_SUCCESS(Status))
- ERR("IoRegisterPlugPlayNotification returned %08x\n", Status);
+ ERR("IoRegisterPlugPlayNotification returned %08lx\n", Status);
Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
(PVOID)&GUID_DEVINTERFACE_DISK, DriverObject, pnp_notification, DriverObject, ¬ification_entry);
if (!NT_SUCCESS(Status))
- ERR("IoRegisterPlugPlayNotification returned %08x\n", Status);
+ ERR("IoRegisterPlugPlayNotification returned %08lx\n", Status);
finished_probing = true;
Status = PsCreateSystemThread(&mountmgr_thread_handle, 0, &system_thread_attributes, NULL, NULL, mountmgr_thread, NULL);
if (!NT_SUCCESS(Status))
- WARN("PsCreateSystemThread returned %08x\n", Status);
+ WARN("PsCreateSystemThread returned %08lx\n", Status);
IoRegisterFileSystem(DeviceObject);