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

commit c982533ea9ede11a719925731c9c1b2fc5b5d347
Author:     Vincent Franchomme <[email protected]>
AuthorDate: Thu Apr 28 21:34:48 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.6 (#4417)
    
    v1.7.6 (2021-01-14):
    
    - Fixed race condition when booting with Quibble
    - No longer need to restart Windows after initial installation
    - Forced maximum file name to 255 UTF-8 characters, to match Linux driver
    - Fixed issue where directories could be created with trailing backslash
    - Fixed potential deadlock when Windows calls NtCreateSection during flush
    - Miscellaneous bug fixes
---
 dll/shellext/shellbtrfs/shellbtrfs.rc  |  10 +-
 dll/win32/ubtrfs/ubtrfs.rc             |  10 +-
 drivers/filesystems/btrfs/boot.c       | 360 +++-------------------
 drivers/filesystems/btrfs/btrfs.c      |  49 ++-
 drivers/filesystems/btrfs/btrfs.inf    |   2 +-
 drivers/filesystems/btrfs/btrfs.rc     |  10 +-
 drivers/filesystems/btrfs/btrfs_drv.h  |  12 +-
 drivers/filesystems/btrfs/create.c     | 529 +++++++++++++++++++--------------
 drivers/filesystems/btrfs/fastio.c     |  46 +++
 drivers/filesystems/btrfs/fileinfo.c   | 132 +++++---
 drivers/filesystems/btrfs/free-space.c |   3 +
 drivers/filesystems/btrfs/fsctl.c      | 103 +++++--
 drivers/filesystems/btrfs/pnp.c        |  12 +
 drivers/filesystems/btrfs/reparse.c    |  10 +-
 drivers/filesystems/btrfs/search.c     |   2 +-
 drivers/filesystems/btrfs/security.c   |   2 +-
 drivers/filesystems/btrfs/treefuncs.c  |   6 +
 drivers/filesystems/btrfs/write.c      |  15 +-
 sdk/lib/fslib/btrfslib/btrfslib.c      |   7 -
 19 files changed, 657 insertions(+), 663 deletions(-)

diff --git a/dll/shellext/shellbtrfs/shellbtrfs.rc 
b/dll/shellext/shellbtrfs/shellbtrfs.rc
index 4852681751d..845d8bc7844 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,5,0
- PRODUCTVERSION 1,7,5,0
+ FILEVERSION 1,7,6,0
+ PRODUCTVERSION 1,7,6,0
  FILEFLAGSMASK 0x17L
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -78,12 +78,12 @@ BEGIN
         BLOCK "080904b0"
         BEGIN
             VALUE "FileDescription", "WinBtrfs shell extension"
-            VALUE "FileVersion", "1.7.5"
+            VALUE "FileVersion", "1.7.6"
             VALUE "InternalName", "btrfs"
-            VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-20"
+            VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-21"
             VALUE "OriginalFilename", "shellbtrfs.dll"
             VALUE "ProductName", "WinBtrfs"
-            VALUE "ProductVersion", "1.7.5"
+            VALUE "ProductVersion", "1.7.6"
         END
     END
     BLOCK "VarFileInfo"
diff --git a/dll/win32/ubtrfs/ubtrfs.rc b/dll/win32/ubtrfs/ubtrfs.rc
index 686e30e7b3c..27eef7a7c0b 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,5,0
- PRODUCTVERSION 1,7,5,0
+ FILEVERSION 1,7,6,0
+ PRODUCTVERSION 1,7,6,0
  FILEFLAGSMASK 0x17L
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -68,12 +68,12 @@ BEGIN
         BLOCK "080904b0"
         BEGIN
             VALUE "FileDescription", "Btrfs utility DLL"
-            VALUE "FileVersion", "1.7.5"
+            VALUE "FileVersion", "1.7.6"
             VALUE "InternalName", "ubtrfs"
-            VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-20"
+            VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-21"
             VALUE "OriginalFilename", "ubtrfs.dll"
             VALUE "ProductName", "WinBtrfs"
-            VALUE "ProductVersion", "1.7.5"
+            VALUE "ProductVersion", "1.7.6"
         END
     END
     BLOCK "VarFileInfo"
diff --git a/drivers/filesystems/btrfs/boot.c b/drivers/filesystems/btrfs/boot.c
index 43486cfad33..011fd544c80 100644
--- a/drivers/filesystems/btrfs/boot.c
+++ b/drivers/filesystems/btrfs/boot.c
@@ -46,20 +46,7 @@ typedef struct {
     ULONG ExtensionFlags;
 } DEVOBJ_EXTENSION2;
 
-typedef enum {
-    system_root_unknown,
-    system_root_partition,
-    system_root_btrfs
-} system_root_type;
-
-typedef struct {
-    uint32_t disk_num;
-    uint32_t partition_num;
-    BTRFS_UUID uuid;
-    system_root_type type;
-} system_root;
-
-static void get_system_root(system_root* sr) {
+static bool get_system_root() {
     NTSTATUS Status;
     HANDLE h;
     UNICODE_STRING us, target;
@@ -69,8 +56,6 @@ static void get_system_root(system_root* sr) {
 
     static const WCHAR system_root[] = L"\\SystemRoot";
     static const WCHAR boot_device[] = L"\\Device\\BootDevice";
-    static const WCHAR arc_prefix[] = L"\\ArcName\\multi(0)disk(0)rdisk(";
-    static const WCHAR arc_middle[] = L")partition(";
     static const WCHAR arc_btrfs_prefix[] = L"\\ArcName\\btrfs(";
 
     us.Buffer = (WCHAR*)system_root;
@@ -82,7 +67,7 @@ static void get_system_root(system_root* sr) {
         Status = ZwOpenSymbolicLinkObject(&h, GENERIC_READ, &objatt);
         if (!NT_SUCCESS(Status)) {
             ERR("ZwOpenSymbolicLinkObject returned %08lx\n", Status);
-            return;
+            return false;
         }
 
         target.Length = target.MaximumLength = 0;
@@ -91,19 +76,19 @@ static void get_system_root(system_root* sr) {
         if (Status != STATUS_BUFFER_TOO_SMALL) {
             ERR("ZwQuerySymbolicLinkObject returned %08lx\n", Status);
             NtClose(h);
-            return;
+            return false;
         }
 
         if (retlen == 0) {
             NtClose(h);
-            return;
+            return false;
         }
 
         target.Buffer = ExAllocatePoolWithTag(NonPagedPool, retlen, ALLOC_TAG);
         if (!target.Buffer) {
             ERR("out of memory\n");
             NtClose(h);
-            return;
+            return false;
         }
 
         target.Length = target.MaximumLength = (USHORT)retlen;
@@ -113,7 +98,7 @@ static void get_system_root(system_root* sr) {
             ERR("ZwQuerySymbolicLinkObject returned %08lx\n", Status);
             NtClose(h);
             ExFreePool(target.Buffer);
-            return;
+            return false;
         }
 
         NtClose(h);
@@ -136,85 +121,33 @@ static void get_system_root(system_root* sr) {
             break;
     }
 
-    sr->type = system_root_unknown;
-
-    if (target.Length >= sizeof(arc_prefix) - sizeof(WCHAR) &&
-        RtlCompareMemory(target.Buffer, arc_prefix, sizeof(arc_prefix) - 
sizeof(WCHAR)) == sizeof(arc_prefix) - sizeof(WCHAR)) {
-        WCHAR* s = &target.Buffer[(sizeof(arc_prefix) / sizeof(WCHAR)) - 1];
-        ULONG left = ((target.Length - sizeof(arc_prefix)) / sizeof(WCHAR)) + 
1;
-
-        if (left == 0 || s[0] < '0' || s[0] > '9') {
-            ExFreePool(target.Buffer);
-            return;
-        }
-
-        sr->disk_num = 0;
-
-        while (left > 0 && s[0] >= '0' && s[0] <= '9') {
-            sr->disk_num *= 10;
-            sr->disk_num += s[0] - '0';
-            s++;
-            left--;
-        }
-
-        if (left <= (sizeof(arc_middle) / sizeof(WCHAR)) - 1 ||
-            RtlCompareMemory(s, arc_middle, sizeof(arc_middle) - 
sizeof(WCHAR)) != sizeof(arc_middle) - sizeof(WCHAR)) {
-            ExFreePool(target.Buffer);
-            return;
-        }
-
-        s = &s[(sizeof(arc_middle) / sizeof(WCHAR)) - 1];
-        left -= (sizeof(arc_middle) / sizeof(WCHAR)) - 1;
-
-        if (left == 0 || s[0] < '0' || s[0] > '9') {
-            ExFreePool(target.Buffer);
-            return;
-        }
-
-        sr->partition_num = 0;
-
-        while (left > 0 && s[0] >= '0' && s[0] <= '9') {
-            sr->partition_num *= 10;
-            sr->partition_num += s[0] - '0';
-            s++;
-            left--;
-        }
-
-        sr->type = system_root_partition;
-    } else if (target.Length >= sizeof(arc_btrfs_prefix) - sizeof(WCHAR) &&
+    if (target.Length >= sizeof(arc_btrfs_prefix) - sizeof(WCHAR) &&
         RtlCompareMemory(target.Buffer, arc_btrfs_prefix, 
sizeof(arc_btrfs_prefix) - sizeof(WCHAR)) == sizeof(arc_btrfs_prefix) - 
sizeof(WCHAR)) {
         WCHAR* s = &target.Buffer[(sizeof(arc_btrfs_prefix) / sizeof(WCHAR)) - 
1];
-#ifdef __REACTOS__
-        unsigned int i;
-#endif // __REACTOS__
 
-#ifndef __REACTOS__
         for (unsigned int i = 0; i < 16; i++) {
-#else
-        for (i = 0; i < 16; i++) {
-#endif // __REACTOS__
             if (*s >= '0' && *s <= '9')
-                sr->uuid.uuid[i] = (*s - '0') << 4;
+                boot_uuid.uuid[i] = (*s - '0') << 4;
             else if (*s >= 'a' && *s <= 'f')
-                sr->uuid.uuid[i] = (*s - 'a' + 0xa) << 4;
+                boot_uuid.uuid[i] = (*s - 'a' + 0xa) << 4;
             else if (*s >= 'A' && *s <= 'F')
-                sr->uuid.uuid[i] = (*s - 'A' + 0xa) << 4;
+                boot_uuid.uuid[i] = (*s - 'A' + 0xa) << 4;
             else {
                 ExFreePool(target.Buffer);
-                return;
+                return false;
             }
 
             s++;
 
             if (*s >= '0' && *s <= '9')
-                sr->uuid.uuid[i] |= *s - '0';
+                boot_uuid.uuid[i] |= *s - '0';
             else if (*s >= 'a' && *s <= 'f')
-                sr->uuid.uuid[i] |= *s - 'a' + 0xa;
+                boot_uuid.uuid[i] |= *s - 'a' + 0xa;
             else if (*s >= 'A' && *s <= 'F')
-                sr->uuid.uuid[i] |= *s - 'A' + 0xa;
+                boot_uuid.uuid[i] |= *s - 'A' + 0xa;
             else {
                 ExFreePool(target.Buffer);
-                return;
+                return false;
             }
 
             s++;
@@ -222,7 +155,7 @@ static void get_system_root(system_root* sr) {
             if (i == 3 || i == 5 || i == 7 || i == 9) {
                 if (*s != '-') {
                     ExFreePool(target.Buffer);
-                    return;
+                    return false;
                 }
 
                 s++;
@@ -231,97 +164,17 @@ static void get_system_root(system_root* sr) {
 
         if (*s != ')') {
             ExFreePool(target.Buffer);
-            return;
+            return false;
         }
 
-        sr->type = system_root_btrfs;
-    }
-
-    ExFreePool(target.Buffer);
-}
-
-static void append_int_to_us(UNICODE_STRING* us, unsigned int n) {
-    unsigned int num, digits = 0;
-    WCHAR* ptr;
-
-    if (n == 0) {
-        us->Buffer[us->Length / sizeof(WCHAR)] = '0';
-        us->Length += sizeof(WCHAR);
-        return;
-    }
-
-    num = n;
-
-    while (num > 0) {
-        digits++;
-        num /= 10;
-    }
-
-    ptr = &us->Buffer[(us->Length / sizeof(WCHAR)) + digits - 1];
+        ExFreePool(target.Buffer);
 
-    while (n > 0) {
-        *ptr = L'0' + (n % 10);
-        ptr--;
-        n /= 10;
+        return true;
     }
 
-    us->Length += digits * sizeof(WCHAR);
-}
-
-static void change_symlink(uint32_t disk_num, uint32_t partition_num, 
BTRFS_UUID* uuid) {
-    NTSTATUS Status;
-    UNICODE_STRING us, us2;
-    WCHAR symlink[60], target[(sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) + 
36], *w;
-#ifdef __REACTOS__
-    unsigned int i;
-#endif
-
-    static const WCHAR dev_path1[] = L"\\Device\\Harddisk";
-    static const WCHAR dev_path2[] = L"\\Partition";
-
-    us.Buffer = symlink;
-    us.Length = sizeof(dev_path1) - sizeof(WCHAR);
-    us.MaximumLength = sizeof(symlink);
-
-    RtlCopyMemory(symlink, dev_path1, sizeof(dev_path1) - sizeof(WCHAR));
-
-    append_int_to_us(&us, disk_num);
-
-    RtlCopyMemory(&us.Buffer[us.Length / sizeof(WCHAR)], dev_path2, 
sizeof(dev_path2) - sizeof(WCHAR));
-    us.Length += sizeof(dev_path2) - sizeof(WCHAR);
-
-    append_int_to_us(&us, partition_num);
-
-    Status = IoDeleteSymbolicLink(&us);
-    if (!NT_SUCCESS(Status))
-        ERR("IoDeleteSymbolicLink returned %08lx\n", Status);
-
-    RtlCopyMemory(target, BTRFS_VOLUME_PREFIX, sizeof(BTRFS_VOLUME_PREFIX) - 
sizeof(WCHAR));
-
-    w = &target[(sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1];
-
-#ifndef __REACTOS__
-    for (unsigned int i = 0; i < 16; i++) {
-#else
-    for (i = 0; i < 16; i++) {
-#endif
-        *w = hex_digit(uuid->uuid[i] >> 4); w++;
-        *w = hex_digit(uuid->uuid[i] & 0xf); w++;
-
-        if (i == 3 || i == 5 || i == 7 || i == 9) {
-            *w = L'-';
-            w++;
-        }
-    }
-
-    *w = L'}';
-
-    us2.Buffer = target;
-    us2.Length = us2.MaximumLength = sizeof(target);
+    ExFreePool(target.Buffer);
 
-    Status = IoCreateSymbolicLink(&us, &us2);
-    if (!NT_SUCCESS(Status))
-        ERR("IoCreateSymbolicLink returned %08lx\n", Status);
+    return false;
 }
 
 static void mountmgr_notification(BTRFS_UUID* uuid) {
@@ -332,9 +185,6 @@ static void mountmgr_notification(BTRFS_UUID* uuid) {
     ULONG mmtnlen;
     MOUNTMGR_TARGET_NAME* mmtn;
     WCHAR* w;
-#ifdef __REACTOS__
-    unsigned int i;
-#endif
 
     RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
     Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, 
&FileObject, &mountmgr);
@@ -357,11 +207,7 @@ static void mountmgr_notification(BTRFS_UUID* uuid) {
 
     w = &mmtn->DeviceName[(sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1];
 
-#ifndef __REACTOS__
     for (unsigned int i = 0; i < 16; i++) {
-#else
-    for (i = 0; i < 16; i++) {
-#endif
         *w = hex_digit(uuid->uuid[i] >> 4); w++;
         *w = hex_digit(uuid->uuid[i] & 0xf); w++;
 
@@ -487,166 +333,52 @@ void boot_add_device(DEVICE_OBJECT* pdo) {
     mountmgr_notification(&pdode->uuid);
 }
 
-/* If booting from Btrfs, Windows will pass the device object for the raw 
partition to
- * mount_vol - which is no good to us, as we only use the \Device\Btrfs{} 
devices we
- * create so that RAID works correctly.
- * At the time check_system_root gets called, \SystemRoot is a symlink to the 
ARC device,
- * e.g. \ArcName\multi(0)disk(0)rdisk(0)partition(1)\Windows. We can't change 
the symlink,
- * as it gets clobbered by IopReassignSystemRoot shortly afterwards, and we 
can't touch
- * the \ArcName symlinks as they haven't been created yet. Instead, we need to 
change the
- * symlink \Device\HarddiskX\PartitionY, which is what the ArcName symlink 
will shortly
- * point to.
- */
-void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID Context, 
ULONG Count) {
-    system_root sr;
+void check_system_root() {
     LIST_ENTRY* le;
-    bool done = false;
     PDEVICE_OBJECT pdo_to_add = NULL;
-    volume_child* boot_vc = NULL;
-
-    TRACE("(%p, %p, %lu)\n", DriverObject, Context, Count);
 
-    UNUSED(DriverObject);
-    UNUSED(Context);
-    UNUSED(Count);
+    TRACE("()\n");
 
     // wait for any PNP notifications in progress to finish
     ExAcquireResourceExclusiveLite(&boot_lock, TRUE);
     ExReleaseResourceLite(&boot_lock);
 
-    get_system_root(&sr);
-
-    if (sr.type == system_root_partition) {
-        TRACE("system boot partition is disk %u, partition %u\n", sr.disk_num, 
sr.partition_num);
-
-        ExAcquireResourceSharedLite(&pdo_list_lock, true);
-
-        le = pdo_list.Flink;
-        while (le != &pdo_list) {
-            LIST_ENTRY* le2;
-            pdo_device_extension* pdode = CONTAINING_RECORD(le, 
pdo_device_extension, list_entry);
-
-            ExAcquireResourceSharedLite(&pdode->child_lock, true);
-
-            le2 = pdode->children.Flink;
-
-            while (le2 != &pdode->children) {
-                volume_child* vc = CONTAINING_RECORD(le2, volume_child, 
list_entry);
-
-                if (vc->disk_num == sr.disk_num && vc->part_num == 
sr.partition_num) {
-                    change_symlink(sr.disk_num, sr.partition_num, 
&pdode->uuid);
-                    done = true;
-
-                    vc->boot_volume = true;
-                    boot_uuid = pdode->uuid;
-
-                    if (!pdode->vde)
-                        pdo_to_add = pdode->pdo;
-
-                    boot_vc = vc;
-
-                    break;
-                }
-
-                le2 = le2->Flink;
-            }
-
-            if (done) {
-                le2 = pdode->children.Flink;
-
-                while (le2 != &pdode->children) {
-                    volume_child* vc = CONTAINING_RECORD(le2, volume_child, 
list_entry);
-
-                    /* On Windows 7 we need to clear the 
DO_SYSTEM_BOOT_PARTITION flag of
-                    * all of our underlying partition objects - otherwise 
IopMountVolume
-                    * will bugcheck with UNMOUNTABLE_BOOT_VOLUME when it tries 
and fails
-                    * to mount one. */
-                    if (vc->devobj) {
-                        PDEVICE_OBJECT dev = vc->devobj;
-
-                        ObReferenceObject(dev);
-
-                        while (dev) {
-                            PDEVICE_OBJECT dev2 = IoGetLowerDeviceObject(dev);
-
-                            dev->Flags &= ~DO_SYSTEM_BOOT_PARTITION;
-
-                            ObDereferenceObject(dev);
-
-                            dev = dev2;
-                        }
-                    }
-
-                    le2 = le2->Flink;
-                }
-
-                ExReleaseResourceLite(&pdode->child_lock);
-
-                break;
-            }
-
-            ExReleaseResourceLite(&pdode->child_lock);
+    if (!get_system_root())
+        return;
 
-            le = le->Flink;
-        }
+    ExAcquireResourceSharedLite(&pdo_list_lock, true);
 
-        ExReleaseResourceLite(&pdo_list_lock);
-    } else if (sr.type == system_root_btrfs) {
-        boot_uuid = sr.uuid;
+    le = pdo_list.Flink;
+    while (le != &pdo_list) {
+        pdo_device_extension* pdode = CONTAINING_RECORD(le, 
pdo_device_extension, list_entry);
 
-        ExAcquireResourceSharedLite(&pdo_list_lock, true);
+        if (RtlCompareMemory(&pdode->uuid, &boot_uuid, sizeof(BTRFS_UUID)) == 
sizeof(BTRFS_UUID)) {
+            if (!pdode->vde)
+                pdo_to_add = pdode->pdo;
+            else if (pdode->vde->device && !(pdode->vde->device->Flags & 
DO_SYSTEM_BOOT_PARTITION)) { // AddDevice has beaten us to it
+                NTSTATUS Status;
 
-        le = pdo_list.Flink;
-        while (le != &pdo_list) {
-            pdo_device_extension* pdode = CONTAINING_RECORD(le, 
pdo_device_extension, list_entry);
+                pdode->vde->device->Flags |= DO_SYSTEM_BOOT_PARTITION;
+                pdode->pdo->Flags |= DO_SYSTEM_BOOT_PARTITION;
 
-            if (RtlCompareMemory(&pdode->uuid, &sr.uuid, sizeof(BTRFS_UUID)) 
== sizeof(BTRFS_UUID)) {
-                if (!pdode->vde)
-                    pdo_to_add = pdode->pdo;
+                Status = IoSetDeviceInterfaceState(&pdode->vde->bus_name, 
false);
+                if (!NT_SUCCESS(Status))
+                    ERR("IoSetDeviceInterfaceState returned %08lx\n", Status);
 
-                break;
+                Status = IoSetDeviceInterfaceState(&pdode->vde->bus_name, 
true);
+                if (!NT_SUCCESS(Status))
+                    ERR("IoSetDeviceInterfaceState returned %08lx\n", Status);
             }
 
-            le = le->Flink;
+            break;
         }
 
-        ExReleaseResourceLite(&pdo_list_lock);
+        le = le->Flink;
     }
 
-    if (boot_vc) {
-        NTSTATUS Status;
-        UNICODE_STRING name;
-
-        /* On Windows 8, mountmgr!MountMgrFindBootVolume returns the first 
volume in its database
-         * with the DO_SYSTEM_BOOT_PARTITION flag set. We've cleared the bit 
on the underlying devices,
-         * but as it caches it we need to disable and re-enable the volume so 
mountmgr receives a PNP
-         * notification to refresh its list. */
-
-        static const WCHAR prefix[] = L"\\??";
-
-        name.Length = name.MaximumLength = boot_vc->pnp_name.Length + 
sizeof(prefix) - sizeof(WCHAR);
-
-        name.Buffer = ExAllocatePoolWithTag(PagedPool, name.MaximumLength, 
ALLOC_TAG);
-        if (!name.Buffer)
-            ERR("out of memory\n");
-        else {
-            RtlCopyMemory(name.Buffer, prefix, sizeof(prefix) - sizeof(WCHAR));
-            RtlCopyMemory(&name.Buffer[(sizeof(prefix) / sizeof(WCHAR)) - 1], 
boot_vc->pnp_name.Buffer, boot_vc->pnp_name.Length);
-
-            Status = IoSetDeviceInterfaceState(&name, false);
-            if (!NT_SUCCESS(Status))
-                ERR("IoSetDeviceInterfaceState returned %08lx\n", Status);
-
-            Status = IoSetDeviceInterfaceState(&name, true);
-            if (!NT_SUCCESS(Status))
-                ERR("IoSetDeviceInterfaceState returned %08lx\n", Status);
-
-            ExFreePool(name.Buffer);
-        }
-    }
+    ExReleaseResourceLite(&pdo_list_lock);
 
-    if (sr.type == system_root_btrfs || boot_vc)
-        check_boot_options();
+    check_boot_options();
 
     // If our FS depends on volumes that aren't there when we do our 
IoRegisterPlugPlayNotification calls
     // in DriverEntry, bus_query_device_relations won't get called until it's 
too late. We need to do our
diff --git a/drivers/filesystems/btrfs/btrfs.c 
b/drivers/filesystems/btrfs/btrfs.c
index 2f2932f1205..6c821f12534 100644
--- a/drivers/filesystems/btrfs/btrfs.c
+++ b/drivers/filesystems/btrfs/btrfs.c
@@ -667,6 +667,9 @@ static bool lie_about_fs_type() {
     INIT_UNICODE_STRING(fsutil, L"FSUTIL.EXE");
     INIT_UNICODE_STRING(storsvc, L"STORSVC.DLL");
 
+    /* Not doing a Volkswagen, honest! Some IFS tests won't run if not 
recognized FS. */
+    INIT_UNICODE_STRING(ifstest, L"IFSTEST.EXE");
+
     if (!PsGetCurrentProcess())
         return false;
 
@@ -733,6 +736,15 @@ static bool lie_about_fs_type() {
             blacklist = FsRtlAreNamesEqual(&name, &usstorsvc, true, NULL);
         }
 
+        if (!blacklist && entry->FullDllName.Length >= usifstest.Length) {
+            UNICODE_STRING name;
+
+            name.Buffer = 
&entry->FullDllName.Buffer[(entry->FullDllName.Length - usifstest.Length) / 
sizeof(WCHAR)];
+            name.Length = name.MaximumLength = usifstest.Length;
+
+            blacklist = FsRtlAreNamesEqual(&name, &usifstest, true, NULL);
+        }
+
         if (blacklist) {
             void** frames;
             ULONG i, num_frames;
@@ -1833,10 +1845,6 @@ void reap_fileref(device_extension* Vcb, file_ref* fr) {
 
     // FIXME - do delete if needed
 
-    ExDeleteResourceLite(&fr->nonpaged->fileref_lock);
-
-    ExFreeToNPagedLookasideList(&Vcb->fileref_np_lookaside, fr->nonpaged);
-
     // FIXME - throw error if children not empty
 
     if (fr->fcb->fileref == fr)
@@ -2161,7 +2169,6 @@ void uninit(_In_ device_extension* Vcb) {
     ExDeletePagedLookasideList(&Vcb->fcb_lookaside);
     ExDeletePagedLookasideList(&Vcb->name_bit_lookaside);
     ExDeleteNPagedLookasideList(&Vcb->range_lock_lookaside);
-    ExDeleteNPagedLookasideList(&Vcb->fileref_np_lookaside);
     ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside);
 
     ZwClose(Vcb->flush_thread_handle);
@@ -4709,7 +4716,6 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT 
DeviceObject, _In_ PIRP Irp) {
     ExInitializePagedLookasideList(&Vcb->fcb_lookaside, NULL, NULL, 0, 
sizeof(fcb), ALLOC_TAG, 0);
     ExInitializePagedLookasideList(&Vcb->name_bit_lookaside, NULL, NULL, 0, 
sizeof(name_bit), ALLOC_TAG, 0);
     ExInitializeNPagedLookasideList(&Vcb->range_lock_lookaside, NULL, NULL, 0, 
sizeof(range_lock), ALLOC_TAG, 0);
-    ExInitializeNPagedLookasideList(&Vcb->fileref_np_lookaside, NULL, NULL, 0, 
sizeof(file_ref_nonpaged), ALLOC_TAG, 0);
     ExInitializeNPagedLookasideList(&Vcb->fcb_np_lookaside, NULL, NULL, 0, 
sizeof(fcb_nonpaged), ALLOC_TAG, 0);
     init_lookaside = true;
 
@@ -5027,7 +5033,6 @@ exit2:
                 ExDeletePagedLookasideList(&Vcb->fcb_lookaside);
                 ExDeletePagedLookasideList(&Vcb->name_bit_lookaside);
                 ExDeleteNPagedLookasideList(&Vcb->range_lock_lookaside);
-                ExDeleteNPagedLookasideList(&Vcb->fileref_np_lookaside);
                 ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside);
             }
 
@@ -5764,27 +5769,43 @@ exit:
     return Status;
 }
 
-bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix, _In_ bool 
stream) {
+NTSTATUS check_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix, _In_ 
bool stream) {
     ULONG i;
 
     if (us->Length < sizeof(WCHAR))
-        return false;
+        return STATUS_OBJECT_NAME_INVALID;
 
     if (us->Length > 255 * sizeof(WCHAR))
-        return false;
+        return STATUS_OBJECT_NAME_INVALID;
 
     for (i = 0; i < us->Length / sizeof(WCHAR); i++) {
         if (us->Buffer[i] == '/' || us->Buffer[i] == 0 ||
             (!posix && (us->Buffer[i] == '/' || us->Buffer[i] == ':')) ||
             (!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 false;
+            return STATUS_OBJECT_NAME_INVALID;
     }
 
     if (us->Buffer[0] == '.' && (us->Length == sizeof(WCHAR) || (us->Length == 
2 * sizeof(WCHAR) && us->Buffer[1] == '.')))
-        return false;
+        return STATUS_OBJECT_NAME_INVALID;
 
-    return true;
+    /* The Linux driver expects filenames with a maximum length of 255 bytes - 
make sure
+     * that our UTF-8 length won't be longer than that. */
+    if (us->Length >= 85 * sizeof(WCHAR)) {
+        NTSTATUS Status;
+        ULONG utf8len;
+
+        Status = utf16_to_utf8(NULL, 0, &utf8len, us->Buffer, us->Length);
+        if (!NT_SUCCESS(Status))
+            return Status;
+
+        if (utf8len > 255)
+            return STATUS_OBJECT_NAME_INVALID;
+        else if (stream && utf8len > 250) // minus five bytes for "user."
+            return STATUS_OBJECT_NAME_INVALID;
+    }
+
+    return STATUS_SUCCESS;
 }
 
 void chunk_lock_range(_In_ device_extension* Vcb, _In_ chunk* c, _In_ uint64_t 
start, _In_ uint64_t length) {
@@ -6519,7 +6540,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT 
DriverObject, _In_ PUNICODE_S
 
     IoRegisterFileSystem(DeviceObject);
 
-    IoRegisterBootDriverReinitialization(DriverObject, check_system_root, 
NULL);
+    check_system_root();
 
     return STATUS_SUCCESS;
 }
diff --git a/drivers/filesystems/btrfs/btrfs.inf 
b/drivers/filesystems/btrfs/btrfs.inf
index ac8ff69dc4d..42a3e97068c 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   = 10/31/2020,1.7.5.0
+DriverVer   = 01/14/2021,1.7.6.0
 CatalogFile = btrfs.cat
 
 [DestinationDirs]
diff --git a/drivers/filesystems/btrfs/btrfs.rc 
b/drivers/filesystems/btrfs/btrfs.rc
index e7a7ad6c280..198fcc4e8a9 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,5,0
- PRODUCTVERSION 1,7,5,0
+ FILEVERSION 1,7,6,0
+ PRODUCTVERSION 1,7,6,0
  FILEFLAGSMASK 0x17L
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -68,12 +68,12 @@ BEGIN
         BLOCK "080904b0"
         BEGIN
             VALUE "FileDescription", "WinBtrfs"
-            VALUE "FileVersion", "1.7.5"
+            VALUE "FileVersion", "1.7.6"
             VALUE "InternalName", "btrfs"
-            VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-20"
+            VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-21"
             VALUE "OriginalFilename", "btrfs.sys"
             VALUE "ProductName", "WinBtrfs"
-            VALUE "ProductVersion", "1.7.5"
+            VALUE "ProductVersion", "1.7.6"
         END
     END
     BLOCK "VarFileInfo"
diff --git a/drivers/filesystems/btrfs/btrfs_drv.h 
b/drivers/filesystems/btrfs/btrfs_drv.h
index 0e2554adbc3..106332d77c4 100644
--- a/drivers/filesystems/btrfs/btrfs_drv.h
+++ b/drivers/filesystems/btrfs/btrfs_drv.h
@@ -338,10 +338,6 @@ typedef struct _fcb {
     LIST_ENTRY list_entry_dirty;
 } fcb;
 
-typedef struct {
-    ERESOURCE fileref_lock;
-} file_ref_nonpaged;
-
 typedef struct _file_ref {
     fcb* fcb;
     ANSI_STRING oldutf8;
@@ -350,7 +346,6 @@ typedef struct _file_ref {
     bool posix_delete;
     bool deleted;
     bool created;
-    file_ref_nonpaged* nonpaged;
     LIST_ENTRY children;
     LONG refcount;
     LONG open_count;
@@ -832,7 +827,6 @@ typedef struct _device_extension {
     PAGED_LOOKASIDE_LIST fcb_lookaside;
     PAGED_LOOKASIDE_LIST name_bit_lookaside;
     NPAGED_LOOKASIDE_LIST range_lock_lookaside;
-    NPAGED_LOOKASIDE_LIST fileref_np_lookaside;
     NPAGED_LOOKASIDE_LIST fcb_np_lookaside;
     LIST_ENTRY list_entry;
 } device_extension;
@@ -1122,7 +1116,7 @@ NTSTATUS create_root(_In_ 
_Requires_exclusive_lock_held_(_Curr_->tree_lock) devi
 void uninit(_In_ device_extension* Vcb);
 NTSTATUS dev_ioctl(_In_ PDEVICE_OBJECT DeviceObject, _In_ ULONG ControlCode, 
_In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer, _In_ ULONG 
InputBufferSize,
                    _Out_writes_bytes_opt_(OutputBufferSize) PVOID 
OutputBuffer, _In_ ULONG OutputBufferSize, _In_ bool Override, _Out_opt_ 
IO_STATUS_BLOCK* iosb);
-bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix, _In_ bool 
stream);
+NTSTATUS check_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix, _In_ 
bool stream);
 void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG 
filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream);
 void queue_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, 
_In_ ULONG action, _In_opt_ PUNICODE_STRING stream);
 
@@ -1419,6 +1413,8 @@ NTSTATUS 
stream_set_end_of_file_information(device_extension* Vcb, uint16_t end,
 NTSTATUS fileref_get_filename(file_ref* fileref, PUNICODE_STRING fn, USHORT* 
name_offset, ULONG* preqlen);
 void insert_dir_child_into_hash_lists(fcb* fcb, dir_child* dc);
 void remove_dir_child_from_hash_lists(fcb* fcb, dir_child* dc);
+void add_fcb_to_subvol(_In_ 
_Requires_exclusive_lock_held_(_Curr_->Vcb->fcb_lock) fcb* fcb);
+void remove_fcb_from_subvol(_In_ 
_Requires_exclusive_lock_held_(_Curr_->Vcb->fcb_lock) fcb* fcb);
 
 // in reparse.c
 NTSTATUS get_reparse_point(PFILE_OBJECT FileObject, void* buffer, DWORD 
buflen, ULONG_PTR* retlen);
@@ -1626,7 +1622,7 @@ NTSTATUS read_send_buffer(device_extension* Vcb, 
PFILE_OBJECT FileObject, void*
 NTSTATUS __stdcall compat_FsRtlValidateReparsePointBuffer(IN ULONG 
BufferLength, IN PREPARSE_DATA_BUFFER ReparseBuffer);
 
 // in boot.c
-void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID Context, 
ULONG Count);
+void check_system_root();
 void boot_add_device(DEVICE_OBJECT* pdo);
 extern BTRFS_UUID boot_uuid;
 
diff --git a/drivers/filesystems/btrfs/create.c 
b/drivers/filesystems/btrfs/create.c
index 25b0b975e53..e678a096167 100644
--- a/drivers/filesystems/btrfs/create.c
+++ b/drivers/filesystems/btrfs/create.c
@@ -80,6 +80,12 @@ static const GUID GUID_ECP_ATOMIC_CREATE = { 0x4720bd83, 
0x52ac, 0x4104, { 0xa1,
 static const GUID GUID_ECP_QUERY_ON_CREATE = { 0x1aca62e9, 0xabb4, 0x4ff2, { 
0xbb, 0x5c, 0x1c, 0x79, 0x02, 0x5e, 0x41, 0x7f } };
 static const GUID GUID_ECP_CREATE_REDIRECTION = { 0x188d6bd6, 0xa126, 0x4fa8, 
{ 0xbd, 0xf2, 0x1c, 0xcd, 0xf8, 0x96, 0xf3, 0xe0 } };
 
+typedef struct {
+    device_extension* Vcb;
+    ACCESS_MASK granted_access;
+    file_ref* fileref;
+} oplock_context;
+
 fcb* create_fcb(device_extension* Vcb, POOL_TYPE pool_type) {
     fcb* fcb;
 
@@ -160,13 +166,6 @@ file_ref* create_fileref(device_extension* Vcb) {
 
     RtlZeroMemory(fr, sizeof(file_ref));
 
-    fr->nonpaged = 
ExAllocateFromNPagedLookasideList(&Vcb->fileref_np_lookaside);
-    if (!fr->nonpaged) {
-        ERR("out of memory\n");
-        ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, fr);
-        return NULL;
-    }
-
     fr->refcount = 1;
 
 #ifdef DEBUG_FCB_REFCOUNTS
@@ -175,8 +174,6 @@ file_ref* create_fileref(device_extension* Vcb) {
 
     InitializeListHead(&fr->children);
 
-    ExInitializeResourceLite(&fr->nonpaged->fileref_lock);
-
     return fr;
 }
 
@@ -1596,7 +1593,7 @@ NTSTATUS 
open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex
         ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
 
         if (duff_fr)
-            reap_fileref(Vcb, duff_fr);
+            ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, duff_fr);
     } else {
         root* subvol;
         uint64_t inode;
@@ -1652,9 +1649,6 @@ NTSTATUS 
open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex
 
             sf2->fcb = fcb;
 
-            if (dc->type == BTRFS_TYPE_DIRECTORY)
-                fcb->fileref = sf2;
-
             
ExAcquireResourceExclusiveLite(&sf->fcb->nonpaged->dir_children_lock, true);
 
             if (!dc->fileref) {
@@ -1663,6 +1657,9 @@ NTSTATUS 
open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex
                 dc->fileref = sf2;
                 InsertTailList(&sf->children, &sf2->list_entry);
                 increase_fileref_refcount(sf);
+
+                if (dc->type == BTRFS_TYPE_DIRECTORY)
+                    fcb->fileref = sf2;
             } else {
                 duff_fr = sf2;
                 sf2 = dc->fileref;
@@ -2654,9 +2651,6 @@ static NTSTATUS 
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
 #ifdef DEBUG_FCB_REFCOUNTS
     LONG rc;
 #endif
-#ifdef __REACTOS__
-    LIST_ENTRY* le;
-#endif
 
     TRACE("fpus = %.*S\n", (int)(fpus->Length / sizeof(WCHAR)), fpus->Buffer);
     TRACE("stream = %.*S\n", (int)(stream->Length / sizeof(WCHAR)), 
stream->Buffer);
@@ -2671,8 +2665,9 @@ static NTSTATUS 
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
     if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
         UNICODE_STRING fpus2;
 
-        if (!is_file_name_valid(fpus, false, true))
-            return STATUS_OBJECT_NAME_INVALID;
+        Status = check_file_name_valid(fpus, false, true);
+        if (!NT_SUCCESS(Status))
+            return Status;
 
         fpus2.Length = fpus2.MaximumLength = fpus->Length;
         fpus2.Buffer = ExAllocatePoolWithTag(pool_type, fpus2.MaximumLength, 
ALLOC_TAG);
@@ -2775,6 +2770,7 @@ static NTSTATUS 
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
 #endif
     fcb->subvol = parfileref->fcb->subvol;
     fcb->inode = parfileref->fcb->inode;
+    fcb->hash = parfileref->fcb->hash;
     fcb->type = parfileref->fcb->type;
 
     fcb->ads = true;
@@ -2913,11 +2909,7 @@ static NTSTATUS 
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
 
     
ExAcquireResourceExclusiveLite(&parfileref->fcb->nonpaged->dir_children_lock, 
true);
 
-#ifndef __REACTOS__
     LIST_ENTRY* le = parfileref->fcb->dir_children_index.Flink;
-#else
-    le = parfileref->fcb->dir_children_index.Flink;
-#endif
     while (le != &parfileref->fcb->dir_children_index) {
         dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_index);
 
@@ -3143,10 +3135,9 @@ static NTSTATUS file_create(PIRP Irp, 
_Requires_lock_held_(_Curr_->tree_lock) _R
     } else {
         ACCESS_MASK granted_access;
 
-        if (!is_file_name_valid(&fpus, false, false)) {
-            Status = STATUS_OBJECT_NAME_INVALID;
+        Status = check_file_name_valid(&fpus, false, false);
+        if (!NT_SUCCESS(Status))
             goto end;
-        }
 
         
SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
 
@@ -3581,168 +3572,18 @@ end:
     fcb->csum_loaded = true;
 }
 
-static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, 
POOL_TYPE pool_type, file_ref* fileref, ACCESS_MASK* granted_access,
-                           PFILE_OBJECT FileObject, UNICODE_STRING* fn, ULONG 
options, PIRP Irp, LIST_ENTRY* rollback) {
+static NTSTATUS open_file3(device_extension* Vcb, PIRP Irp, ACCESS_MASK 
granted_access, file_ref* fileref, LIST_ENTRY* rollback) {
     NTSTATUS Status;
-    file_ref* sf;
-    bool readonly;
-    ccb* ccb;
     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+    ULONG options = IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
+    ULONG RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 
0xff);
+    PFILE_OBJECT FileObject = IrpSp->FileObject;
+    POOL_TYPE pool_type = IrpSp->Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : 
PagedPool;
+    ccb* ccb;
 
-    if (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == 
FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) {
-        LARGE_INTEGER zero;
-
-        if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY || 
is_subvol_readonly(fileref->fcb->subvol, Irp)) {
-            Status = STATUS_ACCESS_DENIED;
-            goto end;
-        }
-
-        if (Vcb->readonly) {
-            Status = STATUS_MEDIA_WRITE_PROTECTED;
-            goto end;
-        }
-
-        zero.QuadPart = 0;
-        if (!MmCanFileBeTruncated(&fileref->fcb->nonpaged->segment_object, 
&zero)) {
-            Status = STATUS_USER_MAPPED_FILE;
-            goto end;
-        }
-    }
-
-    if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess != 0) {
-        
SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
-
-        if (!SeAccessCheck((fileref->fcb->ads || fileref->fcb == 
Vcb->dummy_fcb) ? fileref->parent->fcb->sd : fileref->fcb->sd,
-                            
&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
-                            true, 
IrpSp->Parameters.Create.SecurityContext->DesiredAccess, 0, NULL,
-                            IoGetFileObjectGenericMapping(), IrpSp->Flags & 
SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode,
-                            granted_access, &Status)) {
-            
SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
-            TRACE("SeAccessCheck failed, returning %08lx\n", Status);
-            goto end;
-        }
-
-        
SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
-    } else
-        *granted_access = 0;
-
-    TRACE("deleted = %s\n", fileref->deleted ? "true" : "false");
-
-    sf = fileref;
-    while (sf) {
-        if (sf->delete_on_close) {
-            TRACE("could not open as deletion pending\n");
-            Status = STATUS_DELETE_PENDING;
-            goto end;
-        }
-        sf = sf->parent;
-    }
-
-    readonly = (!fileref->fcb->ads && fileref->fcb->atts & 
FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE)) ||
-               (fileref->fcb->ads && fileref->parent->fcb->atts & 
FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE)) ||
-               is_subvol_readonly(fileref->fcb->subvol, Irp) || fileref->fcb 
== Vcb->dummy_fcb || Vcb->readonly;
-
-    if (options & FILE_DELETE_ON_CLOSE && (fileref == Vcb->root_fileref || 
readonly)) {
-        Status = STATUS_CANNOT_DELETE;
-        goto end;
-    }
-
-    if (readonly) {
-        ACCESS_MASK allowed;
-
-        allowed = READ_CONTROL | SYNCHRONIZE | ACCESS_SYSTEM_SECURITY | 
FILE_READ_DATA |
-                    FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_EXECUTE | 
FILE_LIST_DIRECTORY |
-                    FILE_TRAVERSE;
-
-        if (!Vcb->readonly && (fileref->fcb == Vcb->dummy_fcb || 
fileref->fcb->inode == SUBVOL_ROOT_INODE))
-            allowed |= DELETE;
-
-        if (fileref->fcb != Vcb->dummy_fcb && 
!is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
-            allowed |= DELETE | WRITE_OWNER | WRITE_DAC | FILE_WRITE_EA | 
FILE_WRITE_ATTRIBUTES;
-
-            if (!fileref->fcb->ads && fileref->fcb->type == 
BTRFS_TYPE_DIRECTORY)
-                allowed |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | 
FILE_DELETE_CHILD;
-        } else if (fileref->fcb->inode == SUBVOL_ROOT_INODE && 
is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
-            // We allow a subvolume root to be opened read-write even if its 
readonly flag is set, so it can be cleared
-
-            allowed |= FILE_WRITE_ATTRIBUTES;
-        }
-
-        if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess & 
MAXIMUM_ALLOWED) {
-            *granted_access &= allowed;
-            
IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess 
&= allowed;
-        } else if (*granted_access & ~allowed) {
-            Status = Vcb->readonly ? STATUS_MEDIA_WRITE_PROTECTED : 
STATUS_ACCESS_DENIED;
-            goto end;
-        }
-    }
-
-    if ((fileref->fcb->type == BTRFS_TYPE_SYMLINK || fileref->fcb->atts & 
FILE_ATTRIBUTE_REPARSE_POINT) && !(options & FILE_OPEN_REPARSE_POINT))  {
-        REPARSE_DATA_BUFFER* data;
-
-        /* How reparse points work from the point of view of the filesystem 
appears to
-            * undocumented. When returning STATUS_REPARSE, MSDN encourages us 
to return
-            * IO_REPARSE in Irp->IoStatus.Information, but that means we have 
to do our own
-            * translation. If we instead return the reparse tag in 
Information, and store
-            * a pointer to the reparse data buffer in 
Irp->Tail.Overlay.AuxiliaryBuffer,
-            * IopSymlinkProcessReparse will do the translation for us. */
-
-        Status = get_reparse_block(fileref->fcb, (uint8_t**)&data);
-        if (!NT_SUCCESS(Status)) {
-            ERR("get_reparse_block returned %08lx\n", Status);
-            Status = STATUS_SUCCESS;
-        } else {
-            Irp->IoStatus.Information = data->ReparseTag;
-
-            if (fn->Buffer[(fn->Length / sizeof(WCHAR)) - 1] == '\\')
-                data->Reserved = sizeof(WCHAR);
-
-            Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
-
-            Status = STATUS_REPARSE;
-            goto end;
-        }
-    }
-
-    if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY && !fileref->fcb->ads) {
-        if (options & FILE_NON_DIRECTORY_FILE && !(fileref->fcb->atts & 
FILE_ATTRIBUTE_REPARSE_POINT)) {
-            Status = STATUS_FILE_IS_A_DIRECTORY;
-            goto end;
-        }
-    } else if (options & FILE_DIRECTORY_FILE) {
-        TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u)\n", 
fileref->fcb->type);
-        Status = STATUS_NOT_A_DIRECTORY;
-        goto end;
-    }
-
-    if (fileref->open_count > 0) {
-        Status = IoCheckShareAccess(*granted_access, 
IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access, 
false);
-
-        if (!NT_SUCCESS(Status)) {
-            if (Status == STATUS_SHARING_VIOLATION)
-                TRACE("IoCheckShareAccess failed, returning %08lx\n", Status);
-            else
-                WARN("IoCheckShareAccess failed, returning %08lx\n", Status);
-
-            goto end;
-        }
-
-        IoUpdateShareAccess(FileObject, &fileref->fcb->share_access);
-    } else
-        IoSetShareAccess(*granted_access, 
IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access);
-
-    if (*granted_access & FILE_WRITE_DATA || options & FILE_DELETE_ON_CLOSE) {
-        if (!MmFlushImageSection(&fileref->fcb->nonpaged->segment_object, 
MmFlushForWrite)) {
-            Status = (options & FILE_DELETE_ON_CLOSE) ? STATUS_CANNOT_DELETE : 
STATUS_SHARING_VIOLATION;
-            goto end2;
-        }
-    }
-
-    // FIXME - this can block waiting for network IO, while we're holding 
fileref_lock and tree_lock
-    Status = FsRtlCheckOplock(fcb_oplock(fileref->fcb), Irp, NULL, NULL, NULL);
-    if (!NT_SUCCESS(Status)) {
-        WARN("FsRtlCheckOplock returned %08lx\n", Status);
-        goto end2;
+    if (granted_access & FILE_WRITE_DATA || options & FILE_DELETE_ON_CLOSE) {
+        if (!MmFlushImageSection(&fileref->fcb->nonpaged->segment_object, 
MmFlushForWrite))
+            return (options & FILE_DELETE_ON_CLOSE) ? STATUS_CANNOT_DELETE : 
STATUS_SHARING_VIOLATION;
     }
 
     if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == 
FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) {
@@ -3750,28 +3591,20 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG 
RequestedDisposition, PO
         LARGE_INTEGER time;
         BTRFS_TIME now;
 
-        if ((RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == 
FILE_OVERWRITE_IF) && readonly) {
-            WARN("cannot overwrite readonly file\n");
-            Status = STATUS_ACCESS_DENIED;
-            goto end2;
-        }
-
-        if (!fileref->fcb->ads && (IrpSp->Parameters.Create.FileAttributes & 
(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != ((fileref->fcb->atts & 
(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)))) {
-            Status = STATUS_ACCESS_DENIED;
-            goto end2;
-        }
+        if (!fileref->fcb->ads && (IrpSp->Parameters.Create.FileAttributes & 
(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != ((fileref->fcb->atts & 
(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN))))
+            return STATUS_ACCESS_DENIED;
 
         if (fileref->fcb->ads) {
             Status = stream_set_end_of_file_information(Vcb, 0, fileref->fcb, 
fileref, false);
             if (!NT_SUCCESS(Status)) {
                 ERR("stream_set_end_of_file_information returned %08lx\n", 
Status);
-                goto end2;
+                return Status;
             }
         } else {
             Status = truncate_file(fileref->fcb, 0, Irp, rollback);
             if (!NT_SUCCESS(Status)) {
                 ERR("truncate_file returned %08lx\n", Status);
-                goto end2;
+                return Status;
             }
         }
 
@@ -3780,7 +3613,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG 
RequestedDisposition, PO
 
             if (!NT_SUCCESS(Status)) {
                 ERR("extend_file returned %08lx\n", Status);
-                goto end2;
+                return Status;
             }
         }
 
@@ -3794,7 +3627,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG 
RequestedDisposition, PO
                 Status = 
IoCheckEaBufferValidity(Irp->AssociatedIrp.SystemBuffer, 
IrpSp->Parameters.Create.EaLength, &offset);
                 if (!NT_SUCCESS(Status)) {
                     ERR("IoCheckEaBufferValidity returned %08lx (error at 
offset %lu)\n", Status, offset);
-                    goto end2;
+                    return Status;
                 }
 
                 fileref->fcb->ealen = 4;
@@ -3823,8 +3656,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG 
RequestedDisposition, PO
                 fileref->fcb->ea_xattr.Buffer = 
ExAllocatePoolWithTag(pool_type, IrpSp->Parameters.Create.EaLength, ALLOC_TAG);
                 if (!fileref->fcb->ea_xattr.Buffer) {
                     ERR("out of memory\n");
-                    Status = STATUS_INSUFFICIENT_RESOURCES;
-                    goto end2;
+                    return STATUS_INSUFFICIENT_RESOURCES;
                 }
 
                 fileref->fcb->ea_xattr.Length = 
fileref->fcb->ea_xattr.MaximumLength = 
(USHORT)IrpSp->Parameters.Create.EaLength;
@@ -3861,7 +3693,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG 
RequestedDisposition, PO
                         Status = delete_fileref(dc->fileref, NULL, false, 
NULL, rollback);
                         if (!NT_SUCCESS(Status)) {
                             ERR("delete_fileref returned %08lx\n", Status);
-                            goto end2;
+                            return Status;
                         }
                     }
                 } else
@@ -3917,8 +3749,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG 
RequestedDisposition, PO
                 if (ffei->Flags & FILE_NEED_EA) {
                     WARN("returning STATUS_ACCESS_DENIED as no EA 
knowledge\n");
 
-                    Status = STATUS_ACCESS_DENIED;
-                    goto end2;
+                    return STATUS_ACCESS_DENIED;
                 }
 
                 if (ffei->NextEntryOffset == 0)
@@ -3935,8 +3766,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG 
RequestedDisposition, PO
     if (!ccb) {
         ERR("out of memory\n");
 
-        Status = STATUS_INSUFFICIENT_RESOURCES;
-        goto end2;
+        return STATUS_INSUFFICIENT_RESOURCES;
     }
 
     RtlZeroMemory(ccb, sizeof(*ccb));
@@ -3949,7 +3779,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG 
RequestedDisposition, PO
     RtlInitUnicodeString(&ccb->query_string, NULL);
     ccb->has_wildcard = false;
     ccb->specific_file = false;
-    ccb->access = *granted_access;
+    ccb->access = granted_access;
     ccb->case_sensitive = IrpSp->Flags & SL_CASE_SENSITIVE;
     ccb->reserving = false;
     ccb->lxss = called_from_lxss();
@@ -4014,9 +3844,264 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG 
RequestedDisposition, PO
 #endif
     InterlockedIncrement(&Vcb->open_files);
 
-    Status = STATUS_SUCCESS;
+    return STATUS_SUCCESS;
+}
+
+static void oplock_complete(PVOID Context, PIRP Irp) {
+    NTSTATUS Status;
+    LIST_ENTRY rollback;
+    bool skip_lock;
+    oplock_context* ctx = Context;
+    device_extension* Vcb = ctx->Vcb;
+
+    TRACE("(%p, %p)\n", Context, Irp);
+
+    InitializeListHead(&rollback);
+
+    skip_lock = ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock);
+
+    if (!skip_lock)
+        ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
+
+    ExAcquireResourceSharedLite(&Vcb->fileref_lock, true);
+
+    // FIXME - trans
+    Status = open_file3(Vcb, Irp, ctx->granted_access, ctx->fileref, 
&rollback);
+
+    if (!NT_SUCCESS(Status)) {
+        free_fileref(ctx->fileref);
+        do_rollback(ctx->Vcb, &rollback);
+    } else
+        clear_rollback(&rollback);
+
+    ExReleaseResourceLite(&Vcb->fileref_lock);
+
+    if (Status == STATUS_SUCCESS) {
+        fcb* fcb2;
+        PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+        PFILE_OBJECT FileObject = IrpSp->FileObject;
+        bool skip_fcb_lock;
+
+        
IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess 
|= ctx->granted_access;
+        
IrpSp->Parameters.Create.SecurityContext->AccessState->RemainingDesiredAccess 
&= ~(ctx->granted_access | MAXIMUM_ALLOWED);
+
+        if (!FileObject->Vpb)
+            FileObject->Vpb = Vcb->devobj->Vpb;
+
+        fcb2 = FileObject->FsContext;
+
+        if (fcb2->ads) {
+            struct _ccb* ccb2 = FileObject->FsContext2;
+
+            fcb2 = ccb2->fileref->parent->fcb;
+        }
+
+        skip_fcb_lock = 
ExIsResourceAcquiredExclusiveLite(fcb2->Header.Resource);
+
+        if (!skip_fcb_lock)
+            ExAcquireResourceExclusiveLite(fcb2->Header.Resource, true);
+
+        fcb_load_csums(Vcb, fcb2, Irp);
+
+        if (!skip_fcb_lock)
+            ExReleaseResourceLite(fcb2->Header.Resource);
+    }
+
+    if (!skip_lock)
+        ExReleaseResourceLite(&Vcb->tree_lock);
+
+    // FIXME - call free_trans if failed and within transaction
+
+    Irp->IoStatus.Status = Status;
+    IoCompleteRequest(Irp, NT_SUCCESS(Status) ? IO_DISK_INCREMENT : 
IO_NO_INCREMENT);
+
+    ExFreePool(ctx);
+}
+
+static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, 
file_ref* fileref, ACCESS_MASK* granted_access,
+                           PFILE_OBJECT FileObject, UNICODE_STRING* fn, ULONG 
options, PIRP Irp, LIST_ENTRY* rollback) {
+    NTSTATUS Status;
+    file_ref* sf;
+    bool readonly;
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+    if (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == 
FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) {
+        LARGE_INTEGER zero;
+
+        if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY || 
is_subvol_readonly(fileref->fcb->subvol, Irp)) {
+            Status = STATUS_ACCESS_DENIED;
+            goto end;
+        }
+
+        if (Vcb->readonly) {
+            Status = STATUS_MEDIA_WRITE_PROTECTED;
+            goto end;
+        }
+
+        zero.QuadPart = 0;
+        if (!MmCanFileBeTruncated(&fileref->fcb->nonpaged->segment_object, 
&zero)) {
+            Status = STATUS_USER_MAPPED_FILE;
+            goto end;
+        }
+    }
+
+    if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess != 0) {
+        
SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
+
+        if (!SeAccessCheck((fileref->fcb->ads || fileref->fcb == 
Vcb->dummy_fcb) ? fileref->parent->fcb->sd : fileref->fcb->sd,
+                            
&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
+                            true, 
IrpSp->Parameters.Create.SecurityContext->DesiredAccess, 0, NULL,
+                            IoGetFileObjectGenericMapping(), IrpSp->Flags & 
SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode,
+                            granted_access, &Status)) {
+            
SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
+            TRACE("SeAccessCheck failed, returning %08lx\n", Status);
+            goto end;
+        }
+
+        
SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
+    } else
+        *granted_access = 0;
+
+    TRACE("deleted = %s\n", fileref->deleted ? "true" : "false");
+
+    sf = fileref;
+    while (sf) {
+        if (sf->delete_on_close) {
+            TRACE("could not open as deletion pending\n");
+            Status = STATUS_DELETE_PENDING;
+            goto end;
+        }
+        sf = sf->parent;
+    }
+
+    readonly = (!fileref->fcb->ads && fileref->fcb->atts & 
FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE)) ||
+               (fileref->fcb->ads && fileref->parent->fcb->atts & 
FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE)) ||
+               is_subvol_readonly(fileref->fcb->subvol, Irp) || fileref->fcb 
== Vcb->dummy_fcb || Vcb->readonly;
+
+    if (options & FILE_DELETE_ON_CLOSE && (fileref == Vcb->root_fileref || 
readonly)) {
+        Status = STATUS_CANNOT_DELETE;
+        goto end;
+    }
+
+    if (readonly) {
+        ACCESS_MASK allowed;
+
+        allowed = READ_CONTROL | SYNCHRONIZE | ACCESS_SYSTEM_SECURITY | 
FILE_READ_DATA |
+                    FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_EXECUTE | 
FILE_LIST_DIRECTORY |
+                    FILE_TRAVERSE;
+
+        if (!Vcb->readonly && (fileref->fcb == Vcb->dummy_fcb || 
fileref->fcb->inode == SUBVOL_ROOT_INODE))
+            allowed |= DELETE;
+
+        if (fileref->fcb != Vcb->dummy_fcb && 
!is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
+            allowed |= DELETE | WRITE_OWNER | WRITE_DAC | FILE_WRITE_EA | 
FILE_WRITE_ATTRIBUTES;
+
+            if (!fileref->fcb->ads && fileref->fcb->type == 
BTRFS_TYPE_DIRECTORY)
+                allowed |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | 
FILE_DELETE_CHILD;
+        } else if (fileref->fcb->inode == SUBVOL_ROOT_INODE && 
is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
+            // We allow a subvolume root to be opened read-write even if its 
readonly flag is set, so it can be cleared
+
+            allowed |= FILE_WRITE_ATTRIBUTES;
+        }
+
+        if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess & 
MAXIMUM_ALLOWED) {
+            *granted_access &= allowed;
+            
IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess 
&= allowed;
+        } else if (*granted_access & ~allowed) {
+            Status = Vcb->readonly ? STATUS_MEDIA_WRITE_PROTECTED : 
STATUS_ACCESS_DENIED;
+            goto end;
+        }
+
+        if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == 
FILE_OVERWRITE_IF) {
+            WARN("cannot overwrite readonly file\n");
+            Status = STATUS_ACCESS_DENIED;
+            goto end;
+        }
+    }
+
+    if ((fileref->fcb->type == BTRFS_TYPE_SYMLINK || fileref->fcb->atts & 
FILE_ATTRIBUTE_REPARSE_POINT) && !(options & FILE_OPEN_REPARSE_POINT))  {
+        REPARSE_DATA_BUFFER* data;
+
+        /* How reparse points work from the point of view of the filesystem 
appears to
+            * undocumented. When returning STATUS_REPARSE, MSDN encourages us 
to return
+            * IO_REPARSE in Irp->IoStatus.Information, but that means we have 
to do our own
+            * translation. If we instead return the reparse tag in 
Information, and store
+            * a pointer to the reparse data buffer in 
Irp->Tail.Overlay.AuxiliaryBuffer,
+            * IopSymlinkProcessReparse will do the translation for us. */
+
+        Status = get_reparse_block(fileref->fcb, (uint8_t**)&data);
+        if (!NT_SUCCESS(Status)) {
+            ERR("get_reparse_block returned %08lx\n", Status);
+            Status = STATUS_SUCCESS;
+        } else {
+            Irp->IoStatus.Information = data->ReparseTag;
+
+            if (fn->Buffer[(fn->Length / sizeof(WCHAR)) - 1] == '\\')
+                data->Reserved = sizeof(WCHAR);
+
+            Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
+
+            Status = STATUS_REPARSE;
+            goto end;
+        }
+    }
+
+    if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY && !fileref->fcb->ads) {
+        if (options & FILE_NON_DIRECTORY_FILE && !(fileref->fcb->atts & 
FILE_ATTRIBUTE_REPARSE_POINT)) {
+            Status = STATUS_FILE_IS_A_DIRECTORY;
+            goto end;
+        }
+    } else if (options & FILE_DIRECTORY_FILE) {
+        TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u)\n", 
fileref->fcb->type);
+        Status = STATUS_NOT_A_DIRECTORY;
+        goto end;
+    }
+
+    if (fileref->open_count > 0) {
+        oplock_context* ctx;
+
+        Status = IoCheckShareAccess(*granted_access, 
IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access, 
false);
+
+        if (!NT_SUCCESS(Status)) {
+            if (Status == STATUS_SHARING_VIOLATION)
+                TRACE("IoCheckShareAccess failed, returning %08lx\n", Status);
+            else
+                WARN("IoCheckShareAccess failed, returning %08lx\n", Status);
+
+            goto end;
+        }
+
+        ctx = ExAllocatePoolWithTag(NonPagedPool, sizeof(oplock_context), 
ALLOC_TAG);
+        if (!ctx) {
+            ERR("out of memory\n");
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            goto end;
+        }
+
+        ctx->Vcb = Vcb;
+        ctx->granted_access = *granted_access;
+        ctx->fileref = fileref;
+#ifdef __REACTOS__
+        Status = FsRtlCheckOplock(fcb_oplock(fileref->fcb), Irp, ctx, 
(POPLOCK_WAIT_COMPLETE_ROUTINE) oplock_complete, NULL);
+#else
+        Status = FsRtlCheckOplock(fcb_oplock(fileref->fcb), Irp, ctx, 
oplock_complete, NULL);
+#endif /* __REACTOS__ */
+        if (Status == STATUS_PENDING)
+            return Status;
+
+        ExFreePool(ctx);
+
+        if (!NT_SUCCESS(Status)) {
+            WARN("FsRtlCheckOplock returned %08lx\n", Status);
+            goto end;
+        }
+
+        IoUpdateShareAccess(FileObject, &fileref->fcb->share_access);
+    } else
+        IoSetShareAccess(*granted_access, 
IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access);
+
+    Status = open_file3(Vcb, Irp, *granted_access, fileref, rollback);
 
-end2:
     if (!NT_SUCCESS(Status))
         IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
 
@@ -4106,9 +4191,6 @@ NTSTATUS 
open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock)
                 if (tp.item->key.obj_id == fcb->inode) {
                     if (tp.item->key.obj_type == TYPE_INODE_REF) {
                         INODE_REF* ir = (INODE_REF*)tp.item->data;
-#ifdef __REACTOS__
-                        ULONG stringlen;
-#endif
 
                         if (tp.item->size < offsetof(INODE_REF, name[0]) || 
tp.item->size < offsetof(INODE_REF, name[0]) + ir->n) {
                             ERR("INODE_REF was too short\n");
@@ -4116,9 +4198,7 @@ NTSTATUS 
open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock)
                             return STATUS_INTERNAL_ERROR;
                         }
 
-#ifndef __REACTOS__
                         ULONG stringlen;
-#endif
 
                         Status = utf8_to_utf16(NULL, 0, &stringlen, ir->name, 
ir->n);
                         if (!NT_SUCCESS(Status)) {
@@ -4156,9 +4236,6 @@ NTSTATUS 
open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock)
                         break;
                     } else if (tp.item->key.obj_type == TYPE_INODE_EXTREF) {
                         INODE_EXTREF* ier = (INODE_EXTREF*)tp.item->data;
-#ifdef __REACTOS__
-                        ULONG stringlen;
-#endif
 
                         if (tp.item->size < offsetof(INODE_EXTREF, name[0]) || 
tp.item->size < offsetof(INODE_EXTREF, name[0]) + ier->n) {
                             ERR("INODE_EXTREF was too short\n");
@@ -4166,9 +4243,7 @@ NTSTATUS 
open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock)
                             return STATUS_INTERNAL_ERROR;
                         }
 
-#ifndef __REACTOS__
                         ULONG stringlen;
-#endif
 
                         Status = utf8_to_utf16(NULL, 0, &stringlen, ier->name, 
ier->n);
                         if (!NT_SUCCESS(Status)) {
@@ -4601,11 +4676,9 @@ loaded:
         goto exit;
     }
 
-    if (NT_SUCCESS(Status)) { // file already exists
-        Status = open_file2(Vcb, RequestedDisposition, pool_type, fileref, 
&granted_access, FileObject, &fn, options, Irp, rollback);
-        if (!NT_SUCCESS(Status))
-            goto exit;
-    } else {
+    if (NT_SUCCESS(Status)) // file already exists
+        Status = open_file2(Vcb, RequestedDisposition, fileref, 
&granted_access, FileObject, &fn, options, Irp, rollback);
+    else {
         file_ref* existing_file = NULL;
 
         Status = file_create(Irp, Vcb, FileObject, related, loaded_related, 
&fn, RequestedDisposition, options, &existing_file, rollback);
@@ -4613,9 +4686,7 @@ loaded:
         if (Status == STATUS_OBJECT_NAME_COLLISION) { // already exists
             fileref = existing_file;
 
-            Status = open_file2(Vcb, RequestedDisposition, pool_type, fileref, 
&granted_access, FileObject, &fn, options, Irp, rollback);
-            if (!NT_SUCCESS(Status))
-                goto exit;
+            Status = open_file2(Vcb, RequestedDisposition, fileref, 
&granted_access, FileObject, &fn, options, Irp, rollback);
         } else {
             Irp->IoStatus.Information = NT_SUCCESS(Status) ? FILE_CREATED : 0;
             granted_access = 
IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
@@ -4928,7 +4999,11 @@ NTSTATUS __stdcall drv_create(IN PDEVICE_OBJECT 
DeviceObject, IN PIRP Irp) {
 
 exit:
     Irp->IoStatus.Status = Status;
-    IoCompleteRequest( Irp, NT_SUCCESS(Status) ? IO_DISK_INCREMENT : 
IO_NO_INCREMENT );
+
+    if (Status == STATUS_PENDING)
+        IoMarkIrpPending(Irp);
+    else
+        IoCompleteRequest(Irp, NT_SUCCESS(Status) ? IO_DISK_INCREMENT : 
IO_NO_INCREMENT);
 
     TRACE("create returning %08lx\n", Status);
 
diff --git a/drivers/filesystems/btrfs/fastio.c 
b/drivers/filesystems/btrfs/fastio.c
index e073f3f9b1d..2c768895f8d 100644
--- a/drivers/filesystems/btrfs/fastio.c
+++ b/drivers/filesystems/btrfs/fastio.c
@@ -499,6 +499,50 @@ static BOOLEAN __stdcall 
fast_io_unlock_all_by_key(PFILE_OBJECT FileObject, PVOI
     return true;
 }
 
+#ifdef __REACTOS__
+_Function_class_(FAST_IO_ACQUIRE_FILE)
+static void __stdcall fast_io_acquire_for_create_section(_In_ PFILE_OBJECT 
FileObject) {
+#else
+static void fast_io_acquire_for_create_section(_In_ PFILE_OBJECT FileObject) {
+#endif /* __REACTOS__ */
+    fcb* fcb;
+
+    TRACE("(%p)\n", FileObject);
+
+    if (!FileObject)
+        return;
+
+    fcb = FileObject->FsContext;
+
+    if (!fcb)
+        return;
+
+    ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true);
+    ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
+}
+
+#ifdef __REACTOS__
+_Function_class_(FAST_IO_RELEASE_FILE)
+static void __stdcall fast_io_release_for_create_section(_In_ PFILE_OBJECT 
FileObject) {
+#else
+static void fast_io_release_for_create_section(_In_ PFILE_OBJECT FileObject) {
+#endif /* __REACTOS__ */
+    fcb* fcb;
+
+    TRACE("(%p)\n", FileObject);
+
+    if (!FileObject)
+        return;
+
+    fcb = FileObject->FsContext;
+
+    if (!fcb)
+        return;
+
+    ExReleaseResourceLite(fcb->Header.Resource);
+    ExReleaseResourceLite(&fcb->Vcb->tree_lock);
+}
+
 void init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) {
     RtlZeroMemory(&FastIoDispatch, sizeof(FastIoDispatch));
 
@@ -513,6 +557,8 @@ void init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) {
     FastIoDispatch.FastIoUnlockSingle = fast_io_unlock_single;
     FastIoDispatch.FastIoUnlockAll = fast_io_unlock_all;
     FastIoDispatch.FastIoUnlockAllByKey = fast_io_unlock_all_by_key;
+    FastIoDispatch.AcquireFileForNtCreateSection = 
fast_io_acquire_for_create_section;
+    FastIoDispatch.ReleaseFileForNtCreateSection = 
fast_io_release_for_create_section;
     FastIoDispatch.FastIoQueryNetworkOpenInfo = 
fast_io_query_network_open_info;
     FastIoDispatch.AcquireForModWrite = fast_io_acquire_for_mod_write;
     FastIoDispatch.MdlRead = FsRtlMdlReadDev;
diff --git a/drivers/filesystems/btrfs/fileinfo.c 
b/drivers/filesystems/btrfs/fileinfo.c
index 4bebfda1904..df8652823e7 100644
--- a/drivers/filesystems/btrfs/fileinfo.c
+++ b/drivers/filesystems/btrfs/fileinfo.c
@@ -801,6 +801,7 @@ static NTSTATUS create_directory_fcb(device_extension* Vcb, 
root* r, fcb* parfcb
 
     fcb->subvol = r;
     fcb->inode = InterlockedIncrement64(&r->lastinode);
+    fcb->hash = calc_crc32c(0xffffffff, (uint8_t*)&fcb->inode, 
sizeof(uint64_t));
     fcb->type = BTRFS_TYPE_DIRECTORY;
 
     fcb->inode_item.generation = Vcb->superblock.generation;
@@ -872,7 +873,7 @@ static NTSTATUS create_directory_fcb(device_extension* Vcb, 
root* r, fcb* parfcb
     RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
 
     acquire_fcb_lock_exclusive(Vcb);
-    InsertTailList(&r->fcbs, &fcb->list_entry);
+    add_fcb_to_subvol(fcb);
     InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
     r->fcbs_version++;
     release_fcb_lock(Vcb);
@@ -884,6 +885,68 @@ static NTSTATUS create_directory_fcb(device_extension* 
Vcb, root* r, fcb* parfcb
     return STATUS_SUCCESS;
 }
 
+void add_fcb_to_subvol(_In_ 
_Requires_exclusive_lock_held_(_Curr_->Vcb->fcb_lock) fcb* fcb) {
+    LIST_ENTRY* lastle = NULL;
+    uint32_t hash = fcb->hash;
+
+    if (fcb->subvol->fcbs_ptrs[hash >> 24]) {
+        LIST_ENTRY* le = fcb->subvol->fcbs_ptrs[hash >> 24];
+
+        while (le != &fcb->subvol->fcbs) {
+            struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry);
+
+            if (fcb2->hash > hash) {
+                lastle = le->Blink;
+                break;
+            }
+
+            le = le->Flink;
+        }
+    }
+
+    if (!lastle) {
+        uint8_t c = hash >> 24;
+
+        if (c != 0xff) {
+            uint8_t d = c + 1;
+
+            do {
+                if (fcb->subvol->fcbs_ptrs[d]) {
+                    lastle = fcb->subvol->fcbs_ptrs[d]->Blink;
+                    break;
+                }
+
+                d++;
+            } while (d != 0);
+        }
+    }
+
+    if (lastle) {
+        InsertHeadList(lastle, &fcb->list_entry);
+
+        if (lastle == &fcb->subvol->fcbs || (CONTAINING_RECORD(lastle, struct 
_fcb, list_entry)->hash >> 24) != (hash >> 24))
+            fcb->subvol->fcbs_ptrs[hash >> 24] = &fcb->list_entry;
+    } else {
+        InsertTailList(&fcb->subvol->fcbs, &fcb->list_entry);
+
+        if (fcb->list_entry.Blink == &fcb->subvol->fcbs || 
(CONTAINING_RECORD(fcb->list_entry.Blink, struct _fcb, list_entry)->hash >> 24) 
!= (hash >> 24))
+            fcb->subvol->fcbs_ptrs[hash >> 24] = &fcb->list_entry;
+    }
+}
+
+void remove_fcb_from_subvol(_In_ 
_Requires_exclusive_lock_held_(_Curr_->Vcb->fcb_lock) fcb* fcb) {
+    uint8_t c = fcb->hash >> 24;
+
+    if (fcb->subvol->fcbs_ptrs[c] == &fcb->list_entry) {
+        if (fcb->list_entry.Flink != &fcb->subvol->fcbs && 
(CONTAINING_RECORD(fcb->list_entry.Flink, struct _fcb, list_entry)->hash >> 24) 
== c)
+            fcb->subvol->fcbs_ptrs[c] = fcb->list_entry.Flink;
+        else
+            fcb->subvol->fcbs_ptrs[c] = NULL;
+    }
+
+    RemoveEntryList(&fcb->list_entry);
+}
+
 static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb, file_ref* 
destdir, PANSI_STRING utf8, PUNICODE_STRING fnus, PIRP Irp, LIST_ENTRY* 
rollback) {
     NTSTATUS Status;
     LIST_ENTRY move_list, *le;
@@ -930,6 +993,7 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* 
ccb, file_ref* destd
 
             if (!NT_SUCCESS(Status)) {
                 ERR("add_children_to_move_list returned %08lx\n", Status);
+                ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
                 goto end;
             }
         }
@@ -950,8 +1014,6 @@ static NTSTATUS move_across_subvols(file_ref* fileref, 
ccb* ccb, file_ref* destd
         if (me->fileref->fcb->inode != SUBVOL_ROOT_INODE && me->fileref->fcb 
!= fileref->fcb->Vcb->dummy_fcb) {
             if (!me->dummyfcb) {
                 ULONG defda;
-                bool inserted = false;
-                LIST_ENTRY* le3;
 
                 
ExAcquireResourceExclusiveLite(me->fileref->fcb->Header.Resource, true);
 
@@ -964,6 +1026,7 @@ static NTSTATUS move_across_subvols(file_ref* fileref, 
ccb* ccb, file_ref* destd
 
                 me->dummyfcb->subvol = me->fileref->fcb->subvol;
                 me->dummyfcb->inode = me->fileref->fcb->inode;
+                me->dummyfcb->hash = me->fileref->fcb->hash;
 
                 if (!me->dummyfcb->ads) {
                     me->dummyfcb->sd_dirty = me->fileref->fcb->sd_dirty;
@@ -983,6 +1046,7 @@ static NTSTATUS move_across_subvols(file_ref* fileref, 
ccb* ccb, file_ref* destd
 
                     me->fileref->fcb->subvol = destdir->fcb->subvol;
                     me->fileref->fcb->inode = 
InterlockedIncrement64(&destdir->fcb->subvol->lastinode);
+                    me->fileref->fcb->hash = calc_crc32c(0xffffffff, 
(uint8_t*)&me->fileref->fcb->inode, sizeof(uint64_t));
                     me->fileref->fcb->inode_item.st_nlink = 1;
 
                     defda = get_file_attributes(me->fileref->fcb->Vcb, 
me->fileref->fcb->subvol, me->fileref->fcb->inode,
@@ -1042,31 +1106,20 @@ static NTSTATUS move_across_subvols(file_ref* fileref, 
ccb* ccb, file_ref* destd
 
                         le2 = le2->Flink;
                     }
+
+                    add_fcb_to_subvol(me->dummyfcb);
+                    remove_fcb_from_subvol(me->fileref->fcb);
+                    add_fcb_to_subvol(me->fileref->fcb);
                 } else {
                     me->fileref->fcb->subvol = 
me->parent->fileref->fcb->subvol;
                     me->fileref->fcb->inode = me->parent->fileref->fcb->inode;
-                }
-
-                me->fileref->fcb->created = true;
-
-                InsertHeadList(&me->fileref->fcb->list_entry, 
&me->dummyfcb->list_entry);
-                RemoveEntryList(&me->fileref->fcb->list_entry);
-
-                le3 = destdir->fcb->subvol->fcbs.Flink;
-                while (le3 != &destdir->fcb->subvol->fcbs) {
-                    fcb* fcb = CONTAINING_RECORD(le3, struct _fcb, list_entry);
-
-                    if (fcb->inode > me->fileref->fcb->inode) {
-                        InsertHeadList(le3->Blink, 
&me->fileref->fcb->list_entry);
-                        inserted = true;
-                        break;
-                    }
+                    me->fileref->fcb->hash = me->parent->fileref->fcb->hash;
 
-                    le3 = le3->Flink;
+                    // put stream after parent in FCB list
+                    InsertHeadList(&me->parent->fileref->fcb->list_entry, 
&me->fileref->fcb->list_entry);
                 }
 
-                if (!inserted)
-                    InsertTailList(&destdir->fcb->subvol->fcbs, 
&me->fileref->fcb->list_entry);
+                me->fileref->fcb->created = true;
 
                 InsertTailList(&me->fileref->fcb->Vcb->all_fcbs, 
&me->dummyfcb->list_entry_all);
 
@@ -1159,7 +1212,7 @@ static NTSTATUS move_across_subvols(file_ref* fileref, 
ccb* ccb, file_ref* destd
         if (le == move_list.Flink && (me->fileref->dc->utf8.Length != 
utf8->Length || RtlCompareMemory(me->fileref->dc->utf8.Buffer, utf8->Buffer, 
utf8->Length) != utf8->Length))
             name_changed = true;
 
-        if ((le == move_list.Flink || me->fileref->fcb->inode == 
SUBVOL_ROOT_INODE) && !me->dummyfileref->oldutf8.Buffer) {
+        if (!me->dummyfileref->oldutf8.Buffer) {
             me->dummyfileref->oldutf8.Buffer = 
ExAllocatePoolWithTag(PagedPool, me->fileref->dc->utf8.Length, ALLOC_TAG);
             if (!me->dummyfileref->oldutf8.Buffer) {
                 ERR("out of memory\n");
@@ -1773,11 +1826,18 @@ static NTSTATUS rename_stream_to_file(device_extension* 
Vcb, file_ref* fileref,
     dummyfcb->Vcb = Vcb;
     dummyfcb->subvol = fileref->fcb->subvol;
     dummyfcb->inode = fileref->fcb->inode;
+    dummyfcb->hash = fileref->fcb->hash;
     dummyfcb->adsxattr = fileref->fcb->adsxattr;
     dummyfcb->adshash = fileref->fcb->adshash;
     dummyfcb->ads = true;
     dummyfcb->deleted = true;
 
+    acquire_fcb_lock_exclusive(Vcb);
+    add_fcb_to_subvol(dummyfcb);
+    InsertTailList(&Vcb->all_fcbs, &dummyfcb->list_entry_all);
+    dummyfcb->subvol->fcbs_version++;
+    release_fcb_lock(Vcb);
+
     // FIXME - dummyfileref as well?
 
     mark_fcb_dirty(dummyfcb);
@@ -1839,9 +1899,10 @@ static NTSTATUS rename_stream(device_extension* Vcb, 
file_ref* fileref, ccb* ccb
     if (fn.Length == 0)
         return rename_stream_to_file(Vcb, fileref, ccb, flags, Irp, rollback);
 
-    if (!is_file_name_valid(&fn, false, true)) {
+    Status = check_file_name_valid(&fn, false, true);
+    if (!NT_SUCCESS(Status)) {
         WARN("invalid stream name %.*S\n", (int)(fn.Length / sizeof(WCHAR)), 
fn.Buffer);
-        return STATUS_OBJECT_NAME_INVALID;
+        return Status;
     }
 
     if (!(flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE) && 
fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY) {
@@ -1989,11 +2050,18 @@ static NTSTATUS rename_stream(device_extension* Vcb, 
file_ref* fileref, ccb* ccb
     dummyfcb->Vcb = Vcb;
     dummyfcb->subvol = fileref->fcb->subvol;
     dummyfcb->inode = fileref->fcb->inode;
+    dummyfcb->hash = fileref->fcb->hash;
     dummyfcb->adsxattr = fileref->fcb->adsxattr;
     dummyfcb->adshash = fileref->fcb->adshash;
     dummyfcb->ads = true;
     dummyfcb->deleted = true;
 
+    acquire_fcb_lock_exclusive(Vcb);
+    add_fcb_to_subvol(dummyfcb);
+    InsertTailList(&Vcb->all_fcbs, &dummyfcb->list_entry_all);
+    dummyfcb->subvol->fcbs_version++;
+    release_fcb_lock(Vcb);
+
     mark_fcb_dirty(dummyfcb);
 
     free_fcb(dummyfcb);
@@ -2078,9 +2146,10 @@ static NTSTATUS rename_file_to_stream(device_extension* 
Vcb, file_ref* fileref,
         return STATUS_INVALID_PARAMETER;
     }
 
-    if (!is_file_name_valid(&fn, false, true)) {
+    Status = check_file_name_valid(&fn, false, true);
+    if (!NT_SUCCESS(Status)) {
         WARN("invalid stream name %.*S\n", (int)(fn.Length / sizeof(WCHAR)), 
fn.Buffer);
-        return STATUS_OBJECT_NAME_INVALID;
+        return Status;
     }
 
     if (!(flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE) && fileref->fcb->atts 
& FILE_ATTRIBUTE_READONLY) {
@@ -2468,9 +2537,6 @@ static NTSTATUS set_rename_information(device_extension* 
Vcb, PIRP Irp, PFILE_OB
     SECURITY_SUBJECT_CONTEXT subjcont;
     ACCESS_MASK access;
     ULONG flags;
-#ifdef __REACTOS__
-    unsigned int i;
-#endif
 
     InitializeListHead(&rollback);
 
@@ -2504,7 +2570,7 @@ static NTSTATUS set_rename_information(device_extension* 
Vcb, PIRP Irp, PFILE_OB
         for (i = fnlen - 1; i >= 0; i--) {
             if (fri->FileName[i] == '\\' || fri->FileName[i] == '/') {
                 fn = &fri->FileName[i+1];
-                fnlen = (fri->FileNameLength / sizeof(WCHAR)) - i - 1;
+                fnlen -= i + 1;
                 break;
             }
         }
@@ -2555,11 +2621,7 @@ static NTSTATUS set_rename_information(device_extension* 
Vcb, PIRP Irp, PFILE_OB
 
     TRACE("fnus = %.*S\n", (int)(fnus.Length / sizeof(WCHAR)), fnus.Buffer);
 
-#ifndef __REACTOS__
     for (unsigned int i = 0 ; i < fnus.Length / sizeof(WCHAR); i++) {
-#else
-    for (i = 0 ; i < fnus.Length / sizeof(WCHAR); i++) {
-#endif
         if (fnus.Buffer[i] == ':') {
             TRACE("colon in filename\n");
             Status = STATUS_OBJECT_NAME_INVALID;
diff --git a/drivers/filesystems/btrfs/free-space.c 
b/drivers/filesystems/btrfs/free-space.c
index c2fc0c1ae12..50b8141ee6f 100644
--- a/drivers/filesystems/btrfs/free-space.c
+++ b/drivers/filesystems/btrfs/free-space.c
@@ -1150,6 +1150,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* 
Vcb, chunk* c, bool* chan
         c->cache->subvol = Vcb->root_root;
 
         c->cache->inode = InterlockedIncrement64(&Vcb->root_root->lastinode);
+        c->cache->hash = calc_crc32c(0xffffffff, (uint8_t*)&c->cache->inode, 
sizeof(uint64_t));
 
         c->cache->type = BTRFS_TYPE_FILE;
         c->cache->created = true;
@@ -1214,6 +1215,8 @@ static NTSTATUS allocate_cache_chunk(device_extension* 
Vcb, chunk* c, bool* chan
         c->cache->extents_changed = true;
         InsertTailList(&Vcb->all_fcbs, &c->cache->list_entry_all);
 
+        add_fcb_to_subvol(c->cache);
+
         Status = flush_fcb(c->cache, true, batchlist, Irp);
         if (!NT_SUCCESS(Status)) {
             ERR("flush_fcb returned %08lx\n", Status);
diff --git a/drivers/filesystems/btrfs/fsctl.c 
b/drivers/filesystems/btrfs/fsctl.c
index f1bb68c22a0..8ad58df883f 100644
--- a/drivers/filesystems/btrfs/fsctl.c
+++ b/drivers/filesystems/btrfs/fsctl.c
@@ -601,8 +601,9 @@ static NTSTATUS create_snapshot(device_extension* Vcb, 
PFILE_OBJECT FileObject,
     if (is_subvol_readonly(fcb->subvol, Irp))
         return STATUS_ACCESS_DENIED;
 
-    if (!is_file_name_valid(&nameus, posix, false))
-        return STATUS_OBJECT_NAME_INVALID;
+    Status = check_file_name_valid(&nameus, posix, false);
+    if (!NT_SUCCESS(Status))
+        return Status;
 
     utf8.Buffer = NULL;
 
@@ -823,8 +824,9 @@ static NTSTATUS create_subvol(device_extension* Vcb, 
PFILE_OBJECT FileObject, vo
     nameus.Length = nameus.MaximumLength = bcs->namelen;
     nameus.Buffer = bcs->name;
 
-    if (!is_file_name_valid(&nameus, bcs->posix, false))
-        return STATUS_OBJECT_NAME_INVALID;
+    Status = check_file_name_valid(&nameus, bcs->posix, false);
+    if (!NT_SUCCESS(Status))
+        return Status;
 
     utf8.Buffer = NULL;
 
@@ -961,8 +963,9 @@ static NTSTATUS create_subvol(device_extension* Vcb, 
PFILE_OBJECT FileObject, vo
     rootfcb->Vcb = Vcb;
 
     rootfcb->subvol = r;
-    rootfcb->inode = SUBVOL_ROOT_INODE;
     rootfcb->type = BTRFS_TYPE_DIRECTORY;
+    rootfcb->inode = SUBVOL_ROOT_INODE;
+    rootfcb->hash = calc_crc32c(0xffffffff, (uint8_t*)&rootfcb->inode, 
sizeof(uint64_t)); // FIXME - we can hardcode this
 
     rootfcb->inode_item.generation = Vcb->superblock.generation;
     rootfcb->inode_item.transid = Vcb->superblock.generation;
@@ -1006,7 +1009,7 @@ static NTSTATUS create_subvol(device_extension* Vcb, 
PFILE_OBJECT FileObject, vo
     rootfcb->inode_item_changed = true;
 
     acquire_fcb_lock_exclusive(Vcb);
-    InsertTailList(&r->fcbs, &rootfcb->list_entry);
+    add_fcb_to_subvol(rootfcb);
     InsertTailList(&Vcb->all_fcbs, &rootfcb->list_entry_all);
     r->fcbs_version++;
     release_fcb_lock(Vcb);
@@ -3693,6 +3696,44 @@ end:
     return Status;
 }
 
+static NTSTATUS check_inode_used(_In_ 
_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb,
+                                 _In_ root* subvol, _In_ uint64_t inode, _In_ 
uint32_t hash, _In_opt_ PIRP Irp) {
+    KEY searchkey;
+    traverse_ptr tp;
+    NTSTATUS Status;
+    uint8_t c = hash >> 24;
+
+    if (subvol->fcbs_ptrs[c]) {
+        LIST_ENTRY* le = subvol->fcbs_ptrs[c];
+
+        while (le != &subvol->fcbs) {
+            struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry);
+
+            if (fcb2->inode == inode)
+                return STATUS_SUCCESS;
+            else if (fcb2->hash > hash)
+                break;
+
+            le = le->Flink;
+        }
+    }
+
+    searchkey.obj_id = inode;
+    searchkey.obj_type = TYPE_INODE_ITEM;
+    searchkey.offset = 0xffffffffffffffff;
+
+    Status = find_item(Vcb, subvol, &tp, &searchkey, false, Irp);
+    if (!NT_SUCCESS(Status)) {
+        ERR("find_item returned %08lx\n", Status);
+        return Status;
+    }
+
+    if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == 
searchkey.obj_type)
+        return STATUS_SUCCESS;
+
+    return STATUS_NOT_FOUND;
+}
+
 static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* 
data, ULONG datalen, PIRP Irp) {
     NTSTATUS Status;
     btrfs_mknod* bmn;
@@ -3705,7 +3746,6 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT 
FileObject, void* data
     dir_child* dc;
     LARGE_INTEGER time;
     BTRFS_TIME now;
-    LIST_ENTRY* lastle;
     ANSI_STRING utf8;
     ULONG len, i;
     SECURITY_SUBJECT_CONTEXT subjcont;
@@ -3925,35 +3965,33 @@ static NTSTATUS mknod(device_extension* Vcb, 
PFILE_OBJECT FileObject, void* data
     acquire_fcb_lock_exclusive(Vcb);
 
     if (bmn->inode == 0) {
-        inode = InterlockedIncrement64(&parfcb->subvol->lastinode);
-        lastle = parfcb->subvol->fcbs.Blink;
+        fcb->inode = InterlockedIncrement64(&parfcb->subvol->lastinode);
+        fcb->hash = calc_crc32c(0xffffffff, (uint8_t*)&fcb->inode, 
sizeof(uint64_t));
     } else {
         if (bmn->inode > (uint64_t)parfcb->subvol->lastinode) {
-            inode = parfcb->subvol->lastinode = bmn->inode;
-            lastle = parfcb->subvol->fcbs.Blink;
+            fcb->inode = parfcb->subvol->lastinode = bmn->inode;
+            fcb->hash = calc_crc32c(0xffffffff, (uint8_t*)&fcb->inode, 
sizeof(uint64_t));
         } else {
-            LIST_ENTRY* le = parfcb->subvol->fcbs.Flink;
+            uint32_t hash = calc_crc32c(0xffffffff, (uint8_t*)&bmn->inode, 
sizeof(uint64_t));
 
-            lastle = parfcb->subvol->fcbs.Blink;;
-            while (le != &parfcb->subvol->fcbs) {
-                struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, 
list_entry);
+            Status = check_inode_used(Vcb, subvol, bmn->inode, hash, Irp);
+            if (NT_SUCCESS(Status)) { // STATUS_SUCCESS means inode found
+                release_fcb_lock(Vcb);
+                ExReleaseResourceLite(&Vcb->fileref_lock);
 
-                if (fcb2->inode == bmn->inode && !fcb2->deleted) {
-                    release_fcb_lock(Vcb);
-                    ExReleaseResourceLite(&Vcb->fileref_lock);
-
-                    WARN("inode collision\n");
-                    Status = STATUS_INVALID_PARAMETER;
-                    goto end;
-                } else if (fcb2->inode > bmn->inode) {
-                    lastle = fcb2->list_entry.Blink;
-                    break;
-                }
+                WARN("inode collision\n");
+                Status = STATUS_INVALID_PARAMETER;
+                goto end;
+            } else if (Status != STATUS_NOT_FOUND) {
+                ERR("check_inode_used returned %08lx\n", Status);
 
-                le = le->Flink;
+                release_fcb_lock(Vcb);
+                ExReleaseResourceLite(&Vcb->fileref_lock);
+                goto end;
             }
 
-            inode = bmn->inode;
+            fcb->inode = bmn->inode;
+            fcb->hash = hash;
         }
     }
 
@@ -4025,7 +4063,7 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT 
FileObject, void* data
         RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
     }
 
-    InsertHeadList(lastle, &fcb->list_entry);
+    add_fcb_to_subvol(fcb);
     InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
 
     if (bmn->type == BTRFS_TYPE_DIRECTORY)
@@ -4924,10 +4962,10 @@ static NTSTATUS fsctl_oplock(device_extension* Vcb, 
PIRP* Pirp) {
 
     ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
 
+    ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
+
     if (fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_1 || fsctl == 
FSCTL_REQUEST_BATCH_OPLOCK || fsctl == FSCTL_REQUEST_FILTER_OPLOCK ||
         fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_2 || oplock_request) {
-        ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
-
         if (shared_request) {
             if (fcb->type == BTRFS_TYPE_FILE) {
                 if (fFsRtlCheckLockForOplockRequest)
@@ -4939,8 +4977,7 @@ static NTSTATUS fsctl_oplock(device_extension* Vcb, PIRP* 
Pirp) {
             }
         } else
             oplock_count = fileref->open_count;
-    } else
-        ExAcquireResourceSharedLite(fcb->Header.Resource, true);
+    }
 
 #if (NTDDI_VERSION >= NTDDI_WIN7)
     if ((fsctl == FSCTL_REQUEST_FILTER_OPLOCK || fsctl == 
FSCTL_REQUEST_BATCH_OPLOCK ||
diff --git a/drivers/filesystems/btrfs/pnp.c b/drivers/filesystems/btrfs/pnp.c
index 02314ba7a1f..54426102b9b 100644
--- a/drivers/filesystems/btrfs/pnp.c
+++ b/drivers/filesystems/btrfs/pnp.c
@@ -188,6 +188,18 @@ static NTSTATUS bus_pnp(bus_device_extension* bde, PIRP 
Irp) {
     bool handled = false;
 
     switch (IrpSp->MinorFunction) {
+        case IRP_MN_START_DEVICE:
+        case IRP_MN_CANCEL_REMOVE_DEVICE:
+        case IRP_MN_SURPRISE_REMOVAL:
+        case IRP_MN_REMOVE_DEVICE:
+            Status = STATUS_SUCCESS;
+            handled = true;
+            break;
+
+        case IRP_MN_QUERY_REMOVE_DEVICE:
+            Status = STATUS_UNSUCCESSFUL;
+            handled = true;
+            break;
         case IRP_MN_QUERY_CAPABILITIES:
             Status = bus_query_capabilities(Irp);
             handled = true;
diff --git a/drivers/filesystems/btrfs/reparse.c 
b/drivers/filesystems/btrfs/reparse.c
index 03708228d46..4e473149d26 100644
--- a/drivers/filesystems/btrfs/reparse.c
+++ b/drivers/filesystems/btrfs/reparse.c
@@ -317,6 +317,11 @@ NTSTATUS set_reparse_point2(fcb* fcb, REPARSE_DATA_BUFFER* 
rdb, ULONG buflen, cc
 
     // FIXME - die if not file or directory
 
+    if (fcb->type == BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size > 0) {
+        TRACE("directory not empty\n");
+        return STATUS_DIRECTORY_NOT_EMPTY;
+    }
+
     if (buflen < sizeof(ULONG)) {
         WARN("buffer was not long enough to hold tag\n");
         return STATUS_INVALID_BUFFER_SIZE;
@@ -328,7 +333,10 @@ NTSTATUS set_reparse_point2(fcb* fcb, REPARSE_DATA_BUFFER* 
rdb, ULONG buflen, cc
         return Status;
     }
 
-    RtlCopyMemory(&tag, rdb, sizeof(ULONG));
+    tag = *(ULONG*)rdb;
+
+    if (tag == IO_REPARSE_TAG_MOUNT_POINT && fcb->type != BTRFS_TYPE_DIRECTORY)
+        return STATUS_NOT_A_DIRECTORY;
 
     if (fcb->type == BTRFS_TYPE_FILE &&
         ((tag == IO_REPARSE_TAG_SYMLINK && 
rdb->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) || tag == 
IO_REPARSE_TAG_LX_SYMLINK)) {
diff --git a/drivers/filesystems/btrfs/search.c 
b/drivers/filesystems/btrfs/search.c
index c44e95f7c79..e604cc99814 100644
--- a/drivers/filesystems/btrfs/search.c
+++ b/drivers/filesystems/btrfs/search.c
@@ -903,7 +903,7 @@ void __stdcall mountmgr_thread(_In_ void* context) {
                 break;
             }
 
-            Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_QUERY_POINTS, &mmp, 
sizeof(MOUNTMGR_MOUNT_POINTS), mmps2, mmps.Size,
+            Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_QUERY_POINTS, &mmp, 
sizeof(MOUNTMGR_MOUNT_POINT), mmps2, mmps.Size,
                                false, NULL);
             if (!NT_SUCCESS(Status))
                 ERR("IOCTL_MOUNTMGR_QUERY_POINTS returned %08lx\n", Status);
diff --git a/drivers/filesystems/btrfs/security.c 
b/drivers/filesystems/btrfs/security.c
index 2761c63a915..c1183de2465 100644
--- a/drivers/filesystems/btrfs/security.c
+++ b/drivers/filesystems/btrfs/security.c
@@ -95,7 +95,7 @@ void add_user_mapping(WCHAR* sidstring, ULONG 
sidstringlength, uint32_t uid) {
     while (sidstringlength > 0) {
         val = 0;
         i = 0;
-        while (sidstring[i] != '-' && i < sidstringlength) {
+        while (i < sidstringlength && sidstring[i] != '-') {
             if (sidstring[i] >= '0' && sidstring[i] <= '9') {
                 val *= 10;
                 val += sidstring[i] - '0';
diff --git a/drivers/filesystems/btrfs/treefuncs.c 
b/drivers/filesystems/btrfs/treefuncs.c
index 4e5502fce2f..3b9483a7b08 100644
--- a/drivers/filesystems/btrfs/treefuncs.c
+++ b/drivers/filesystems/btrfs/treefuncs.c
@@ -2177,6 +2177,9 @@ static NTSTATUS 
commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tr
                     Status = handle_batch_collision(Vcb, bi, tp.tree, tp.item, 
td, &br->items, &ignore);
                     if (!NT_SUCCESS(Status)) {
                         ERR("handle_batch_collision returned %08lx\n", Status);
+#ifdef _DEBUG
+                        int3;
+#endif
 
                         if (td)
                             
ExFreeToPagedLookasideList(&Vcb->tree_data_lookaside, td);
@@ -2258,6 +2261,9 @@ static NTSTATUS 
commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tr
                                 Status = handle_batch_collision(Vcb, bi2, 
tp.tree, td2, td, &br->items, &ignore);
                                 if (!NT_SUCCESS(Status)) {
                                     ERR("handle_batch_collision returned 
%08lx\n", Status);
+#ifdef _DEBUG
+                                    int3;
+#endif
                                     return Status;
                                 }
                             }
diff --git a/drivers/filesystems/btrfs/write.c 
b/drivers/filesystems/btrfs/write.c
index 0d63ac01cec..f4661598400 100644
--- a/drivers/filesystems/btrfs/write.c
+++ b/drivers/filesystems/btrfs/write.c
@@ -3476,7 +3476,7 @@ NTSTATUS extend_file(fcb* fcb, file_ref* fileref, 
uint64_t end, bool prealloc, P
 
                         Status = insert_prealloc_extent(fcb, oldalloc, 
newalloc - oldalloc, rollback);
 
-                        if (!NT_SUCCESS(Status)) {
+                        if (!NT_SUCCESS(Status) && Status != STATUS_DISK_FULL) 
{
                             ERR("insert_prealloc_extent returned %08lx\n", 
Status);
                             return Status;
                         }
@@ -3503,7 +3503,7 @@ NTSTATUS extend_file(fcb* fcb, file_ref* fileref, 
uint64_t end, bool prealloc, P
                 if (prealloc) {
                     Status = insert_prealloc_extent(fcb, 0, newalloc, 
rollback);
 
-                    if (!NT_SUCCESS(Status)) {
+                    if (!NT_SUCCESS(Status) && Status != STATUS_DISK_FULL) {
                         ERR("insert_prealloc_extent returned %08lx\n", Status);
                         return Status;
                     }
@@ -4285,16 +4285,19 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, 
LARGE_INTEGER offset, void
                 Status = Irp->IoStatus.Status;
                 goto end;
             } else {
+                /* We have to wait in CcCopyWrite - if we return 
STATUS_PENDING and add this to the work queue,
+                 * it can result in CcFlushCache being called before the job 
has run. See ifstest ReadWriteTest. */
+
                 if (fCcCopyWriteEx) {
-                    TRACE("CcCopyWriteEx(%p, %I64x, %lx, %u, %p, %p)\n", 
FileObject, off64, *length, wait, buf, Irp->Tail.Overlay.Thread);
-                    if (!fCcCopyWriteEx(FileObject, &offset, *length, wait, 
buf, Irp->Tail.Overlay.Thread)) {
+                    TRACE("CcCopyWriteEx(%p, %I64x, %lx, %u, %p, %p)\n", 
FileObject, off64, *length, true, buf, Irp->Tail.Overlay.Thread);
+                    if (!fCcCopyWriteEx(FileObject, &offset, *length, true, 
buf, Irp->Tail.Overlay.Thread)) {
                         Status = STATUS_PENDING;
                         goto end;
                     }
                     TRACE("CcCopyWriteEx finished\n");
                 } else {
-                    TRACE("CcCopyWrite(%p, %I64x, %lx, %u, %p)\n", FileObject, 
off64, *length, wait, buf);
-                    if (!CcCopyWrite(FileObject, &offset, *length, wait, buf)) 
{
+                    TRACE("CcCopyWrite(%p, %I64x, %lx, %u, %p)\n", FileObject, 
off64, *length, true, buf);
+                    if (!CcCopyWrite(FileObject, &offset, *length, true, buf)) 
{
                         Status = STATUS_PENDING;
                         goto end;
                     }
diff --git a/sdk/lib/fslib/btrfslib/btrfslib.c 
b/sdk/lib/fslib/btrfslib/btrfslib.c
index d176204b2a2..7c07cdc1d63 100644
--- a/sdk/lib/fslib/btrfslib/btrfslib.c
+++ b/sdk/lib/fslib/btrfslib/btrfslib.c
@@ -1263,13 +1263,6 @@ static bool is_mounted_multi_device(HANDLE h, uint32_t 
sector_size) {
         bfs = malloc(bfssize);
 
         Status = NtDeviceIoControlFile(h2, NULL, NULL, NULL, &iosb, 
IOCTL_BTRFS_QUERY_FILESYSTEMS, NULL, 0, bfs, bfssize);
-        if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) {
-#ifdef __REACTOS__
-            if (bfs) free(bfs);
-#endif
-            NtClose(h2);
-            return false;
-        }
     } while (Status == STATUS_BUFFER_OVERFLOW);
 
     if (!NT_SUCCESS(Status))

Reply via email to