From f5556fdc1057d5a254da4343d7277d4d7a54c321 Mon Sep 17 00:00:00 2001 From: Vincent Franchomme Date: Thu, 28 Apr 2022 21:35:58 +0200 Subject: [PATCH] [BTRFS][UBTRFS][SHELLBTRFS] Upgrade to 1.7.9 (#4417) v1.7.9 (2021-10-02): - Fixed deadlock when mounting on Windows 11 - Added support for BitLocker-encrypted volumes - Improved filename checks when renaming or creating hard links - Miscellaneous bug fixes --- dll/shellext/shellbtrfs/shellbtrfs.rc | 8 +- dll/win32/ubtrfs/ubtrfs.rc | 8 +- drivers/filesystems/btrfs/blake2-impl.h | 2 + drivers/filesystems/btrfs/btrfs.c | 56 +++-- drivers/filesystems/btrfs/btrfs.inf | 2 +- drivers/filesystems/btrfs/btrfs.rc | 8 +- drivers/filesystems/btrfs/btrfs_drv.h | 7 +- drivers/filesystems/btrfs/create.c | 6 +- drivers/filesystems/btrfs/devctrl.c | 6 +- drivers/filesystems/btrfs/fileinfo.c | 22 +- drivers/filesystems/btrfs/flushthread.c | 5 +- drivers/filesystems/btrfs/fsctl.c | 2 +- drivers/filesystems/btrfs/search.c | 256 +++++++++++++++++++-- drivers/filesystems/btrfs/zstd/zstd_lazy.c | 2 +- 14 files changed, 317 insertions(+), 73 deletions(-) diff --git a/dll/shellext/shellbtrfs/shellbtrfs.rc b/dll/shellext/shellbtrfs/shellbtrfs.rc index acf070e40f9..980929f108c 100644 --- a/dll/shellext/shellbtrfs/shellbtrfs.rc +++ b/dll/shellext/shellbtrfs/shellbtrfs.rc @@ -61,8 +61,8 @@ IDI_ICON1 ICON "subvol.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,7,8,0 - PRODUCTVERSION 1,7,8,0 + FILEVERSION 1,7,9,0 + PRODUCTVERSION 1,7,9,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -78,12 +78,12 @@ BEGIN BLOCK "080904b0" BEGIN VALUE "FileDescription", "WinBtrfs shell extension" - VALUE "FileVersion", "1.7.8" + VALUE "FileVersion", "1.7.9" VALUE "InternalName", "btrfs" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-21" VALUE "OriginalFilename", "shellbtrfs.dll" VALUE "ProductName", "WinBtrfs" - VALUE "ProductVersion", "1.7.8" + VALUE "ProductVersion", "1.7.9" END END BLOCK "VarFileInfo" diff --git a/dll/win32/ubtrfs/ubtrfs.rc b/dll/win32/ubtrfs/ubtrfs.rc index 2b17773476b..79609cf3464 100644 --- a/dll/win32/ubtrfs/ubtrfs.rc +++ b/dll/win32/ubtrfs/ubtrfs.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,7,8,0 - PRODUCTVERSION 1,7,8,0 + FILEVERSION 1,7,9,0 + PRODUCTVERSION 1,7,9,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -68,12 +68,12 @@ BEGIN BLOCK "080904b0" BEGIN VALUE "FileDescription", "Btrfs utility DLL" - VALUE "FileVersion", "1.7.8" + VALUE "FileVersion", "1.7.9" VALUE "InternalName", "ubtrfs" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-21" VALUE "OriginalFilename", "ubtrfs.dll" VALUE "ProductName", "WinBtrfs" - VALUE "ProductVersion", "1.7.8" + VALUE "ProductVersion", "1.7.9" END END BLOCK "VarFileInfo" diff --git a/drivers/filesystems/btrfs/blake2-impl.h b/drivers/filesystems/btrfs/blake2-impl.h index d6b05c09f15..1bd067b6d28 100644 --- a/drivers/filesystems/btrfs/blake2-impl.h +++ b/drivers/filesystems/btrfs/blake2-impl.h @@ -29,6 +29,8 @@ #define BLAKE2_INLINE inline #endif +#define NATIVE_LITTLE_ENDIAN + static BLAKE2_INLINE uint32_t load32( const void *src ) { #if defined(NATIVE_LITTLE_ENDIAN) diff --git a/drivers/filesystems/btrfs/btrfs.c b/drivers/filesystems/btrfs/btrfs.c index efd80d94357..ea5d2f5cc20 100644 --- a/drivers/filesystems/btrfs/btrfs.c +++ b/drivers/filesystems/btrfs/btrfs.c @@ -4389,10 +4389,8 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { TRACE("(%p, %p)\n", DeviceObject, Irp); - if (DeviceObject != master_devobj) { - Status = STATUS_INVALID_DEVICE_REQUEST; - goto exit; - } + if (DeviceObject != master_devobj) + return STATUS_INVALID_DEVICE_REQUEST; IrpSp = IoGetCurrentIrpStackLocation(Irp); DeviceToMount = IrpSp->Parameters.MountVolume.DeviceObject; @@ -4412,7 +4410,7 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { if (!not_pnp) { Status = STATUS_UNRECOGNIZED_VOLUME; - goto exit2; + goto exit; } } else { PDEVICE_OBJECT pdo; @@ -4451,7 +4449,7 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { if (!vde || vde->type != VCB_TYPE_VOLUME) { vde = NULL; Status = STATUS_UNRECOGNIZED_VOLUME; - goto exit2; + goto exit; } } @@ -4472,11 +4470,13 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { if (pdode->num_children == 0) { ERR("error - number of devices is zero\n"); Status = STATUS_INTERNAL_ERROR; - goto exit2; + ExReleaseResourceLite(&pdode->child_lock); + goto exit; } Status = STATUS_DEVICE_NOT_READY; - goto exit2; + ExReleaseResourceLite(&pdode->child_lock); + goto exit; } le = le2; @@ -4485,6 +4485,7 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { if (pdode->num_children == 0 || pdode->children_loaded == 0) { ERR("error - number of devices is zero\n"); Status = STATUS_INTERNAL_ERROR; + ExReleaseResourceLite(&pdode->child_lock); goto exit; } @@ -4519,6 +4520,10 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { if (!NT_SUCCESS(Status)) { ERR("IoCreateDevice returned %08lx\n", Status); Status = STATUS_UNRECOGNIZED_VOLUME; + + if (pdode) + ExReleaseResourceLite(&pdode->child_lock); + goto exit; } @@ -4558,18 +4563,29 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { else if (Irp->Tail.Overlay.Thread) IoSetHardErrorOrVerifyDevice(Irp, readobj); + if (pdode) + ExReleaseResourceLite(&pdode->child_lock); + goto exit; } if (!vde && Vcb->superblock.num_devices > 1) { ERR("cannot mount multi-device FS with non-PNP device\n"); Status = STATUS_UNRECOGNIZED_VOLUME; + + if (pdode) + ExReleaseResourceLite(&pdode->child_lock); + goto exit; } Status = registry_load_volume_options(Vcb); if (!NT_SUCCESS(Status)) { ERR("registry_load_volume_options returned %08lx\n", Status); + + if (pdode) + ExReleaseResourceLite(&pdode->child_lock); + goto exit; } @@ -4579,9 +4595,15 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { if (pdode && pdode->children_loaded < pdode->num_children && (!Vcb->options.allow_degraded || !finished_probing || degraded_wait)) { ERR("could not mount as %I64u device(s) missing\n", pdode->num_children - pdode->children_loaded); Status = STATUS_DEVICE_NOT_READY; + ExReleaseResourceLite(&pdode->child_lock); goto exit; } + if (pdode) { + // Windows holds DeviceObject->DeviceLock, guaranteeing that mount_vol is serialized + ExReleaseResourceLite(&pdode->child_lock); + } + if (Vcb->options.ignore) { TRACE("ignoring volume\n"); Status = STATUS_UNRECOGNIZED_VOLUME; @@ -5014,10 +5036,6 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { ExInitializeResourceLite(&Vcb->send_load_lock); exit: - if (pdode) - ExReleaseResourceLite(&pdode->child_lock); - -exit2: if (Vcb) { ExReleaseResourceLite(&Vcb->tree_lock); ExReleaseResourceLite(&Vcb->load_lock); @@ -5784,6 +5802,14 @@ NTSTATUS check_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix, _In_ bo (!posix && !stream && (us->Buffer[i] == '<' || us->Buffer[i] == '>' || us->Buffer[i] == '"' || us->Buffer[i] == '|' || us->Buffer[i] == '?' || us->Buffer[i] == '*' || (us->Buffer[i] >= 1 && us->Buffer[i] <= 31)))) return STATUS_OBJECT_NAME_INVALID; + + /* Don't allow unpaired surrogates ("WTF-16") */ + + if ((us->Buffer[i] & 0xfc00) == 0xdc00 && (i == 0 || ((us->Buffer[i-1] & 0xfc00) != 0xd800))) + return STATUS_OBJECT_NAME_INVALID; + + if ((us->Buffer[i] & 0xfc00) == 0xd800 && (i == (us->Length / sizeof(WCHAR)) - 1 || ((us->Buffer[i+1] & 0xfc00) != 0xdc00))) + return STATUS_OBJECT_NAME_INVALID; } if (us->Buffer[0] == '.' && (us->Length == sizeof(WCHAR) || (us->Length == 2 * sizeof(WCHAR) && us->Buffer[1] == '.'))) @@ -6290,6 +6316,8 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S is_windows_8 = ver.dwMajorVersion > 6 || (ver.dwMajorVersion == 6 && ver.dwMinorVersion >= 2); + KeInitializeSpinLock(&fve_data_lock); + InitializeListHead(&uid_map_list); InitializeListHead(&gid_map_list); @@ -6516,12 +6544,12 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S ExInitializeResourceLite(&boot_lock); Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, - (PVOID)&GUID_DEVINTERFACE_VOLUME, DriverObject, volume_notification, DriverObject, ¬ification_entry2); + (PVOID)&GUID_DEVINTERFACE_VOLUME, DriverObject, volume_notification, NULL, ¬ification_entry2); if (!NT_SUCCESS(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); + (PVOID)&GUID_DEVINTERFACE_HIDDEN_VOLUME, DriverObject, volume_notification, NULL, ¬ification_entry3); if (!NT_SUCCESS(Status)) ERR("IoRegisterPlugPlayNotification returned %08lx\n", Status); diff --git a/drivers/filesystems/btrfs/btrfs.inf b/drivers/filesystems/btrfs/btrfs.inf index b5fa3da9136..faeec384225 100644 --- a/drivers/filesystems/btrfs/btrfs.inf +++ b/drivers/filesystems/btrfs/btrfs.inf @@ -10,7 +10,7 @@ Signature = "$Windows NT$" Class = Volume ClassGuid = {71a27cdd-812a-11d0-bec7-08002be2092f} Provider = %Me% -DriverVer = 06/07/2021,1.7.8.0 +DriverVer = 10/02/2021,1.7.9 CatalogFile = btrfs.cat [DestinationDirs] diff --git a/drivers/filesystems/btrfs/btrfs.rc b/drivers/filesystems/btrfs/btrfs.rc index 72a541c3f69..6b0d46874ef 100644 --- a/drivers/filesystems/btrfs/btrfs.rc +++ b/drivers/filesystems/btrfs/btrfs.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,7,8,0 - PRODUCTVERSION 1,7,8,0 + FILEVERSION 1,7,9,0 + PRODUCTVERSION 1,7,9,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -68,12 +68,12 @@ BEGIN BLOCK "080904b0" BEGIN VALUE "FileDescription", "WinBtrfs" - VALUE "FileVersion", "1.7.8" + VALUE "FileVersion", "1.7.9" VALUE "InternalName", "btrfs" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-21" VALUE "OriginalFilename", "btrfs.sys" VALUE "ProductName", "WinBtrfs" - VALUE "ProductVersion", "1.7.8" + VALUE "ProductVersion", "1.7.9" END END BLOCK "VarFileInfo" diff --git a/drivers/filesystems/btrfs/btrfs_drv.h b/drivers/filesystems/btrfs/btrfs_drv.h index 597e5d62794..d033b789934 100644 --- a/drivers/filesystems/btrfs/btrfs_drv.h +++ b/drivers/filesystems/btrfs/btrfs_drv.h @@ -1317,15 +1317,16 @@ void __stdcall mountmgr_thread(_In_ void* context); _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) NTSTATUS __stdcall pnp_notification(PVOID NotificationStructure, PVOID Context); -void disk_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath); -void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath); -void volume_removal(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath); +void disk_arrival(PUNICODE_STRING devpath); +bool volume_arrival(PUNICODE_STRING devpath, bool fve_callback); +void volume_removal(PUNICODE_STRING devpath); _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) NTSTATUS __stdcall volume_notification(PVOID NotificationStructure, PVOID Context); void remove_volume_child(_Inout_ _Requires_exclusive_lock_held_(_Curr_->child_lock) _Releases_exclusive_lock_(_Curr_->child_lock) _In_ volume_device_extension* vde, _In_ volume_child* vc, _In_ bool skip_dev); +extern KSPIN_LOCK fve_data_lock; // in cache.c void init_cache(); diff --git a/drivers/filesystems/btrfs/create.c b/drivers/filesystems/btrfs/create.c index a5a8a2316a2..17e2e722acc 100644 --- a/drivers/filesystems/btrfs/create.c +++ b/drivers/filesystems/btrfs/create.c @@ -1774,11 +1774,11 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusiv name_bit* nb; nb = CONTAINING_RECORD(RemoveTailList(&parts), name_bit, list_entry); - ExFreePool(nb); + ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb); if (has_stream && !IsListEmpty(&parts)) { nb = CONTAINING_RECORD(RemoveTailList(&parts), name_bit, list_entry); - ExFreePool(nb); + ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb); has_stream = false; } @@ -1877,6 +1877,8 @@ NTSTATUS add_dir_child(fcb* fcb, uint64_t inode, bool subvol, PANSI_STRING utf8, return STATUS_INSUFFICIENT_RESOURCES; } + RtlZeroMemory(dc, sizeof(dir_child)); + dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, utf8->Length, ALLOC_TAG); if (!dc->utf8.Buffer) { ERR("out of memory\n"); diff --git a/drivers/filesystems/btrfs/devctrl.c b/drivers/filesystems/btrfs/devctrl.c index 4c729ec4c8e..ecff0f2eec8 100644 --- a/drivers/filesystems/btrfs/devctrl.c +++ b/drivers/filesystems/btrfs/devctrl.c @@ -202,12 +202,12 @@ static NTSTATUS probe_volume(void* data, ULONG length, KPROCESSOR_MODE processor ObDereferenceObject(FileObject); - volume_removal(drvobj, &pnp_name); + volume_removal(&pnp_name); if (RtlCompareMemory(guid, &GUID_DEVINTERFACE_DISK, sizeof(GUID)) == sizeof(GUID)) - disk_arrival(drvobj, &pnp_name); + disk_arrival(&pnp_name); else - volume_arrival(drvobj, &pnp_name); + volume_arrival(&pnp_name, false); return STATUS_SUCCESS; } diff --git a/drivers/filesystems/btrfs/fileinfo.c b/drivers/filesystems/btrfs/fileinfo.c index df8652823e7..cd21a9ce8f4 100644 --- a/drivers/filesystems/btrfs/fileinfo.c +++ b/drivers/filesystems/btrfs/fileinfo.c @@ -2326,7 +2326,7 @@ static NTSTATUS rename_file_to_stream(device_extension* Vcb, file_ref* fileref, dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG); if (!dc) { - ERR("short read\n"); + ERR("out of memory\n"); Status = STATUS_INSUFFICIENT_RESOURCES;; ExFreePool(utf8.Buffer); ExFreePool(utf16.Buffer); @@ -2561,8 +2561,9 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB } else { LONG i; - while (fnlen > 0 && (fri->FileName[fnlen - 1] == '/' || fri->FileName[fnlen - 1] == '\\')) + while (fnlen > 0 && (fri->FileName[fnlen - 1] == '/' || fri->FileName[fnlen - 1] == '\\')) { fnlen--; + } if (fnlen == 0) return STATUS_INVALID_PARAMETER; @@ -2621,13 +2622,9 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB TRACE("fnus = %.*S\n", (int)(fnus.Length / sizeof(WCHAR)), fnus.Buffer); - for (unsigned int i = 0 ; i < fnus.Length / sizeof(WCHAR); i++) { - if (fnus.Buffer[i] == ':') { - TRACE("colon in filename\n"); - Status = STATUS_OBJECT_NAME_INVALID; - goto end; - } - } + Status = check_file_name_valid(&fnus, false, false); + if (!NT_SUCCESS(Status)) + goto end; origutf8len = fileref->dc->utf8.Length; @@ -3444,8 +3441,9 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJE tfofcb = tfo->FsContext; parfcb = tfofcb; - while (fnlen > 0 && (fli->FileName[fnlen - 1] == '/' || fli->FileName[fnlen - 1] == '\\')) + while (fnlen > 0 && (fli->FileName[fnlen - 1] == '/' || fli->FileName[fnlen - 1] == '\\')) { fnlen--; + } if (fnlen == 0) return STATUS_INVALID_PARAMETER; @@ -3485,6 +3483,10 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJE TRACE("fnus = %.*S\n", (int)(fnus.Length / sizeof(WCHAR)), fnus.Buffer); + Status = check_file_name_valid(&fnus, false, false); + if (!NT_SUCCESS(Status)) + goto end; + Status = utf16_to_utf8(NULL, 0, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR)); if (!NT_SUCCESS(Status)) goto end; diff --git a/drivers/filesystems/btrfs/flushthread.c b/drivers/filesystems/btrfs/flushthread.c index 565f400c4b5..a574d433192 100644 --- a/drivers/filesystems/btrfs/flushthread.c +++ b/drivers/filesystems/btrfs/flushthread.c @@ -22,7 +22,10 @@ #include #include -#define MAX_CSUM_SIZE (4096 - sizeof(tree_header) - sizeof(leaf_node)) +/* cf. __MAX_CSUM_ITEMS in Linux - it needs sizeof(leaf_node) bytes free + * so it can do a split. Linux tries to get it so a run will fit in a + * sector, but the MAX_CSUM_ITEMS logic is wrong... */ +#define MAX_CSUM_SIZE (4096 - sizeof(tree_header) - (2 * sizeof(leaf_node))) // #define DEBUG_WRITE_LOOPS diff --git a/drivers/filesystems/btrfs/fsctl.c b/drivers/filesystems/btrfs/fsctl.c index 310816c272f..191dda11aa7 100644 --- a/drivers/filesystems/btrfs/fsctl.c +++ b/drivers/filesystems/btrfs/fsctl.c @@ -2874,7 +2874,7 @@ static NTSTATUS add_device(device_extension* Vcb, PIRP Irp, KPROCESSOR_MODE proc return STATUS_INTERNAL_ERROR; } - volume_removal(drvobj, &pnp_name); + volume_removal(&pnp_name); ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true); diff --git a/drivers/filesystems/btrfs/search.c b/drivers/filesystems/btrfs/search.c index e604cc99814..96797c208ad 100644 --- a/drivers/filesystems/btrfs/search.c +++ b/drivers/filesystems/btrfs/search.c @@ -27,6 +27,7 @@ #include #include +#include extern ERESOURCE pdo_list_lock; extern LIST_ENTRY pdo_list; @@ -37,11 +38,30 @@ extern bool shutting_down; extern PDEVICE_OBJECT busobj; extern tIoUnregisterPlugPlayNotificationEx fIoUnregisterPlugPlayNotificationEx; extern ERESOURCE boot_lock; +extern PDRIVER_OBJECT drvobj; -typedef void (*pnp_callback)(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath); +typedef void (*pnp_callback)(PUNICODE_STRING devpath); + +#ifndef __REACTOS__ +// not in mingw yet +#ifndef _MSC_VER +DEFINE_GUID(GUID_IO_VOLUME_FVE_STATUS_CHANGE, 0x062998b2, 0xee1f, 0x4b6a, 0xb8, 0x57, 0xe7, 0x6c, 0xbb, 0xe9, 0xa6, 0xda); +#endif +#endif // __REACTOS__ extern PDEVICE_OBJECT master_devobj; +typedef struct { + LIST_ENTRY list_entry; + PDEVICE_OBJECT devobj; + void* notification_entry; + UNICODE_STRING devpath; + WCHAR buf[1]; +} fve_data; + +static LIST_ENTRY fve_data_list = { &fve_data_list, &fve_data_list }; +KSPIN_LOCK fve_data_lock; + static bool fs_ignored(BTRFS_UUID* uuid) { UNICODE_STRING path, ignoreus; NTSTATUS Status; @@ -115,12 +135,187 @@ static bool fs_ignored(BTRFS_UUID* uuid) { return ret; } -static void test_vol(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, - PUNICODE_STRING devpath, DWORD disk_num, DWORD part_num, uint64_t length) { +typedef struct { + PIO_WORKITEM work_item; + PFILE_OBJECT fileobj; + PDEVICE_OBJECT devobj; + UNICODE_STRING devpath; + WCHAR buf[1]; +} fve_callback_context; + +_Function_class_(IO_WORKITEM_ROUTINE) +static void __stdcall fve_callback(PDEVICE_OBJECT DeviceObject, PVOID con) { + fve_callback_context* ctx = con; + + UNUSED(DeviceObject); + + if (volume_arrival(&ctx->devpath, true)) { + KIRQL irql; + LIST_ENTRY* le; + fve_data* d = NULL; + + // volume no longer locked - unregister notification + + KeAcquireSpinLock(&fve_data_lock, &irql); + + le = fve_data_list.Flink; + while (le != &fve_data_list) { + fve_data* d2 = CONTAINING_RECORD(le, fve_data, list_entry); + + if (d2->devobj == ctx->devobj) { + RemoveEntryList(&d2->list_entry); + d = d2; + break; + } + + le = le->Flink; + } + + KeReleaseSpinLock(&fve_data_lock, irql); + + if (d) { + IoUnregisterPlugPlayNotification(d->notification_entry); + ExFreePool(d); + } + } + + IoFreeWorkItem(ctx->work_item); + ExFreePool(ctx); +} + +static NTSTATUS __stdcall event_notification(PVOID NotificationStructure, PVOID Context) { + TARGET_DEVICE_REMOVAL_NOTIFICATION* tdrn = NotificationStructure; + PDEVICE_OBJECT devobj = Context; + PIO_WORKITEM work_item; + fve_callback_context* ctx; + LIST_ENTRY* le; + KIRQL irql; + + if (RtlCompareMemory(&tdrn->Event, &GUID_IO_VOLUME_FVE_STATUS_CHANGE, sizeof(GUID)) != sizeof(GUID)) + return STATUS_SUCCESS; + + /* The FVE event has trailing data, presumably telling us whether the volume has + * been unlocked or whatever, but unfortunately it's undocumented! */ + + work_item = IoAllocateWorkItem(master_devobj); + if (!work_item) { + ERR("out of memory\n"); + return STATUS_SUCCESS; + } + + KeAcquireSpinLock(&fve_data_lock, &irql); + + le = fve_data_list.Flink; + while (le != &fve_data_list) { + fve_data* d = CONTAINING_RECORD(le, fve_data, list_entry); + + if (d->devobj == devobj) { + ctx = ExAllocatePoolWithTag(NonPagedPool, offsetof(fve_callback_context, buf) + d->devpath.Length, + ALLOC_TAG); + + if (!ctx) { + KeReleaseSpinLock(&fve_data_lock, irql); + ERR("out of memory\n"); + IoFreeWorkItem(work_item); + return STATUS_SUCCESS; + } + + RtlCopyMemory(ctx->buf, d->devpath.Buffer, d->devpath.Length); + ctx->devpath.Length = ctx->devpath.MaximumLength = d->devpath.Length; + + KeReleaseSpinLock(&fve_data_lock, irql); + + ctx->devpath.Buffer = ctx->buf; + + ctx->fileobj = tdrn->FileObject; + ctx->devobj = devobj; + ctx->work_item = work_item; + + IoQueueWorkItem(work_item, fve_callback, DelayedWorkQueue, ctx); + + return STATUS_SUCCESS; + } + + le = le->Flink; + } + + KeReleaseSpinLock(&fve_data_lock, irql); + + IoFreeWorkItem(work_item); + + return STATUS_SUCCESS; +} + +static void register_fve_callback(PDEVICE_OBJECT devobj, PFILE_OBJECT fileobj, + PUNICODE_STRING devpath) { + NTSTATUS Status; + KIRQL irql; + LIST_ENTRY* le; + + fve_data* d = ExAllocatePoolWithTag(NonPagedPool, offsetof(fve_data, buf) + devpath->Length, ALLOC_TAG); + if (!d) { + ERR("out of memory\n"); + return; + } + + d->devpath.Buffer = d->buf; + d->devpath.Length = d->devpath.MaximumLength = devpath->Length; + RtlCopyMemory(d->devpath.Buffer, devpath->Buffer, devpath->Length); + + KeAcquireSpinLock(&fve_data_lock, &irql); + + le = fve_data_list.Flink; + while (le != &fve_data_list) { + fve_data* d2 = CONTAINING_RECORD(le, fve_data, list_entry); + + if (d2->devobj == devobj) { + KeReleaseSpinLock(&fve_data_lock, irql); + ExFreePool(d); + return; + } + + le = le->Flink; + } + + KeReleaseSpinLock(&fve_data_lock, irql); + + Status = IoRegisterPlugPlayNotification(EventCategoryTargetDeviceChange, 0, fileobj, drvobj, event_notification, + devobj, &d->notification_entry); + if (!NT_SUCCESS(Status)) { + ERR("IoRegisterPlugPlayNotification returned %08lx\n", Status); + return; + } + + KeAcquireSpinLock(&fve_data_lock, &irql); + + le = fve_data_list.Flink; + while (le != &fve_data_list) { + fve_data* d2 = CONTAINING_RECORD(le, fve_data, list_entry); + + if (d2->devobj == devobj) { + KeReleaseSpinLock(&fve_data_lock, irql); + IoUnregisterPlugPlayNotification(d->notification_entry); + ExFreePool(d); + return; + } + + le = le->Flink; + } + + d->devobj = devobj; + InsertTailList(&fve_data_list, &d->list_entry); + + KeReleaseSpinLock(&fve_data_lock, irql); +} + +static bool test_vol(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, + PUNICODE_STRING devpath, DWORD disk_num, DWORD part_num, uint64_t length, + bool fve_callback) { NTSTATUS Status; ULONG toread; uint8_t* data = NULL; uint32_t sector_size; + bool ret = true; TRACE("%.*S\n", (int)(devpath->Length / sizeof(WCHAR)), devpath->Buffer); @@ -195,11 +390,18 @@ static void test_vol(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, add_volume_device(sb, devpath, length, disk_num, part_num); } } + } else if (Status == STATUS_FVE_LOCKED_VOLUME) { + if (fve_callback) + ret = false; + else + register_fve_callback(DeviceObject, FileObject, devpath); } deref: if (data) ExFreePool(data); + + return ret; } NTSTATUS remove_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath) { @@ -255,7 +457,7 @@ NTSTATUS remove_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath) { return Status; } -void disk_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { +void disk_arrival(PUNICODE_STRING devpath) { PFILE_OBJECT fileobj; PDEVICE_OBJECT devobj; NTSTATUS Status; @@ -265,8 +467,6 @@ void disk_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { IO_STATUS_BLOCK iosb; GET_LENGTH_INFORMATION gli; - UNUSED(DriverObject); - ExAcquireResourceSharedLite(&boot_lock, TRUE); Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &fileobj, &devobj); @@ -319,7 +519,8 @@ void disk_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { } else TRACE("DeviceType = %lu, DeviceNumber = %lu, PartitionNumber = %lu\n", sdn.DeviceType, sdn.DeviceNumber, sdn.PartitionNumber); - test_vol(devobj, fileobj, devpath, sdn.DeviceNumber, sdn.PartitionNumber, gli.Length.QuadPart); + test_vol(devobj, fileobj, devpath, sdn.DeviceNumber, sdn.PartitionNumber, + gli.Length.QuadPart, false); end: ObDereferenceObject(fileobj); @@ -489,12 +690,13 @@ void remove_volume_child(_Inout_ _Requires_exclusive_lock_held_(_Curr_->child_lo ExReleaseResourceLite(&pdode->child_lock); } -void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { +bool volume_arrival(PUNICODE_STRING devpath, bool fve_callback) { STORAGE_DEVICE_NUMBER sdn; PFILE_OBJECT fileobj; PDEVICE_OBJECT devobj; GET_LENGTH_INFORMATION gli; NTSTATUS Status; + bool ret = true; TRACE("%.*S\n", (int)(devpath->Length / sizeof(WCHAR)), devpath->Buffer); @@ -504,12 +706,12 @@ void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { if (!NT_SUCCESS(Status)) { ExReleaseResourceLite(&boot_lock); ERR("IoGetDeviceObjectPointer returned %08lx\n", Status); - return; + return false; } // make sure we're not processing devices we've created ourselves - if (devobj->DriverObject == DriverObject) + if (devobj->DriverObject == drvobj) goto end; Status = dev_ioctl(devobj, IOCTL_VOLUME_ONLINE, NULL, 0, NULL, 0, true, NULL); @@ -575,22 +777,27 @@ void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { ExReleaseResourceLite(&pdo_list_lock); } - test_vol(devobj, fileobj, devpath, sdn.DeviceNumber, sdn.PartitionNumber, gli.Length.QuadPart); + ret = test_vol(devobj, fileobj, devpath, sdn.DeviceNumber, sdn.PartitionNumber, + gli.Length.QuadPart, fve_callback); end: ObDereferenceObject(fileobj); ExReleaseResourceLite(&boot_lock); + + return ret; } -void volume_removal(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { +static void volume_arrival2(PUNICODE_STRING devpath) { + volume_arrival(devpath, false); +} + +void volume_removal(PUNICODE_STRING devpath) { LIST_ENTRY* le; UNICODE_STRING devpath2; TRACE("%.*S\n", (int)(devpath->Length / sizeof(WCHAR)), devpath->Buffer); - UNUSED(DriverObject); - devpath2 = *devpath; if (devpath->Length > 4 * sizeof(WCHAR) && devpath->Buffer[0] == '\\' && (devpath->Buffer[1] == '\\' || devpath->Buffer[1] == '?') && @@ -643,7 +850,6 @@ void volume_removal(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { } typedef struct { - PDRIVER_OBJECT DriverObject; UNICODE_STRING name; pnp_callback func; PIO_WORKITEM work_item; @@ -655,7 +861,7 @@ static void __stdcall do_pnp_callback(PDEVICE_OBJECT DeviceObject, PVOID con) { UNUSED(DeviceObject); - context->func(context->DriverObject, &context->name); + context->func(&context->name); if (context->name.Buffer) ExFreePool(context->name.Buffer); @@ -665,7 +871,7 @@ static void __stdcall do_pnp_callback(PDEVICE_OBJECT DeviceObject, PVOID con) { ExFreePool(context); } -static void enqueue_pnp_callback(PDRIVER_OBJECT DriverObject, PUNICODE_STRING name, pnp_callback func) { +static void enqueue_pnp_callback(PUNICODE_STRING name, pnp_callback func) { PIO_WORKITEM work_item; pnp_callback_context* context; @@ -683,8 +889,6 @@ static void enqueue_pnp_callback(PDRIVER_OBJECT DriverObject, PUNICODE_STRING na return; } - context->DriverObject = DriverObject; - if (name->Length > 0) { context->name.Buffer = ExAllocatePoolWithTag(PagedPool, name->Length, ALLOC_TAG); if (!context->name.Buffer) { @@ -710,12 +914,13 @@ static void enqueue_pnp_callback(PDRIVER_OBJECT DriverObject, PUNICODE_STRING na _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) NTSTATUS __stdcall volume_notification(PVOID NotificationStructure, PVOID Context) { DEVICE_INTERFACE_CHANGE_NOTIFICATION* dicn = (DEVICE_INTERFACE_CHANGE_NOTIFICATION*)NotificationStructure; - PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Context; + + UNUSED(Context); if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID)) == sizeof(GUID)) - enqueue_pnp_callback(DriverObject, dicn->SymbolicLinkName, volume_arrival); + enqueue_pnp_callback(dicn->SymbolicLinkName, volume_arrival2); else if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_REMOVAL, sizeof(GUID)) == sizeof(GUID)) - enqueue_pnp_callback(DriverObject, dicn->SymbolicLinkName, volume_removal); + enqueue_pnp_callback(dicn->SymbolicLinkName, volume_removal); return STATUS_SUCCESS; } @@ -723,12 +928,13 @@ NTSTATUS __stdcall volume_notification(PVOID NotificationStructure, PVOID Contex _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) NTSTATUS __stdcall pnp_notification(PVOID NotificationStructure, PVOID Context) { DEVICE_INTERFACE_CHANGE_NOTIFICATION* dicn = (DEVICE_INTERFACE_CHANGE_NOTIFICATION*)NotificationStructure; - PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Context; + + UNUSED(Context); if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID)) == sizeof(GUID)) - enqueue_pnp_callback(DriverObject, dicn->SymbolicLinkName, disk_arrival); + enqueue_pnp_callback(dicn->SymbolicLinkName, disk_arrival); else if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_REMOVAL, sizeof(GUID)) == sizeof(GUID)) - enqueue_pnp_callback(DriverObject, dicn->SymbolicLinkName, volume_removal); + enqueue_pnp_callback(dicn->SymbolicLinkName, volume_removal); return STATUS_SUCCESS; } diff --git a/drivers/filesystems/btrfs/zstd/zstd_lazy.c b/drivers/filesystems/btrfs/zstd/zstd_lazy.c index 4cf5c88b532..abe51cb2e90 100644 --- a/drivers/filesystems/btrfs/zstd/zstd_lazy.c +++ b/drivers/filesystems/btrfs/zstd/zstd_lazy.c @@ -621,7 +621,7 @@ FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS ( *********************************/ typedef enum { search_hashChain, search_binaryTree } searchMethod_e; -FORCE_INLINE_TEMPLATE size_t +size_t ZSTD_compressBlock_lazy_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],