https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f5556fdc1057d5a254da4343d7277d4d7a54c321

commit f5556fdc1057d5a254da4343d7277d4d7a54c321
Author:     Vincent Franchomme <[email protected]>
AuthorDate: Thu Apr 28 21:35:58 2022 +0200
Commit:     Hermès BÉLUSCA - MAÏTO <[email protected]>
CommitDate: Tue May 3 17:30:11 2022 +0200

    [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, &notification_entry2);
+                                            (PVOID)&GUID_DEVINTERFACE_VOLUME, 
DriverObject, volume_notification, NULL, &notification_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, &notification_entry3);
+                                            
(PVOID)&GUID_DEVINTERFACE_HIDDEN_VOLUME, DriverObject, volume_notification, 
NULL, &notification_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 <ntddscsi.h>
 #include <ntddstor.h>
 
-#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 <initguid.h>
 #include <wdmguid.h>
+#include <ioevent.h>
 
 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],

Reply via email to