https://git.reactos.org/?p=reactos.git;a=commitdiff;h=eb7fbc253fcb0d2bc53441...
commit eb7fbc253fcb0d2bc534412b4965bf2f736eac05 Author: Pierre Schweitzer pierre@reactos.org AuthorDate: Sun Dec 16 12:03:16 2018 +0100 Commit: Pierre Schweitzer pierre@reactos.org CommitDate: Sun Dec 16 12:06:46 2018 +0100
[BTRFS] Upgrade to 1.1
CORE-15452 --- drivers/filesystems/btrfs/CMakeLists.txt | 16 + drivers/filesystems/btrfs/balance.c | 50 +- drivers/filesystems/btrfs/btrfs.c | 188 +- drivers/filesystems/btrfs/btrfs.h | 3 +- drivers/filesystems/btrfs/btrfs.rc | 8 +- drivers/filesystems/btrfs/btrfs_drv.h | 47 +- drivers/filesystems/btrfs/btrfsioctl.h | 20 + drivers/filesystems/btrfs/compress.c | 268 +- drivers/filesystems/btrfs/create.c | 420 +- drivers/filesystems/btrfs/dirctrl.c | 63 +- drivers/filesystems/btrfs/fastio.c | 21 +- drivers/filesystems/btrfs/fileinfo.c | 214 +- drivers/filesystems/btrfs/flushthread.c | 175 +- drivers/filesystems/btrfs/free-space.c | 26 +- drivers/filesystems/btrfs/fsctl.c | 112 +- drivers/filesystems/btrfs/pnp.c | 18 +- drivers/filesystems/btrfs/read.c | 49 +- drivers/filesystems/btrfs/registry.c | 51 +- drivers/filesystems/btrfs/reparse.c | 190 +- drivers/filesystems/btrfs/scrub.c | 4 +- drivers/filesystems/btrfs/search.c | 10 +- drivers/filesystems/btrfs/send.c | 50 +- drivers/filesystems/btrfs/treefuncs.c | 12 +- drivers/filesystems/btrfs/volume.c | 12 +- drivers/filesystems/btrfs/write.c | 67 +- drivers/filesystems/btrfs/zstd/bitstream.h | 455 +++ drivers/filesystems/btrfs/zstd/compiler.h | 133 + drivers/filesystems/btrfs/zstd/cpu.h | 215 ++ drivers/filesystems/btrfs/zstd/debug.h | 123 + drivers/filesystems/btrfs/zstd/entropy_common.c | 236 ++ drivers/filesystems/btrfs/zstd/error_private.c | 48 + drivers/filesystems/btrfs/zstd/error_private.h | 76 + drivers/filesystems/btrfs/zstd/fse.h | 708 ++++ drivers/filesystems/btrfs/zstd/fse_compress.c | 724 ++++ drivers/filesystems/btrfs/zstd/fse_decompress.c | 313 ++ drivers/filesystems/btrfs/zstd/hist.c | 195 + drivers/filesystems/btrfs/zstd/hist.h | 92 + drivers/filesystems/btrfs/zstd/huf.h | 334 ++ drivers/filesystems/btrfs/zstd/huf_compress.c | 796 ++++ drivers/filesystems/btrfs/zstd/huf_decompress.c | 1096 ++++++ drivers/filesystems/btrfs/zstd/mem.h | 376 ++ drivers/filesystems/btrfs/zstd/xxhash.c | 887 +++++ drivers/filesystems/btrfs/zstd/xxhash.h | 305 ++ drivers/filesystems/btrfs/zstd/zstd.h | 1526 ++++++++ drivers/filesystems/btrfs/zstd/zstd_common.c | 72 + drivers/filesystems/btrfs/zstd/zstd_compress.c | 4040 ++++++++++++++++++++ .../btrfs/zstd/zstd_compress_internal.h | 798 ++++ drivers/filesystems/btrfs/zstd/zstd_decompress.c | 3108 +++++++++++++++ drivers/filesystems/btrfs/zstd/zstd_double_fast.c | 499 +++ drivers/filesystems/btrfs/zstd/zstd_double_fast.h | 38 + drivers/filesystems/btrfs/zstd/zstd_errors.h | 92 + drivers/filesystems/btrfs/zstd/zstd_fast.c | 391 ++ drivers/filesystems/btrfs/zstd/zstd_fast.h | 37 + drivers/filesystems/btrfs/zstd/zstd_internal.h | 257 ++ drivers/filesystems/btrfs/zstd/zstd_lazy.c | 1099 ++++++ drivers/filesystems/btrfs/zstd/zstd_lazy.h | 67 + drivers/filesystems/btrfs/zstd/zstd_ldm.c | 646 ++++ drivers/filesystems/btrfs/zstd/zstd_ldm.h | 109 + drivers/filesystems/btrfs/zstd/zstd_opt.c | 1132 ++++++ drivers/filesystems/btrfs/zstd/zstd_opt.h | 48 + media/doc/README.FSD | 2 +- 61 files changed, 22588 insertions(+), 579 deletions(-)
diff --git a/drivers/filesystems/btrfs/CMakeLists.txt b/drivers/filesystems/btrfs/CMakeLists.txt index 65e61d255a..59fe9565e6 100644 --- a/drivers/filesystems/btrfs/CMakeLists.txt +++ b/drivers/filesystems/btrfs/CMakeLists.txt @@ -33,6 +33,22 @@ list(APPEND SOURCE volume.c worker-thread.c write.c + zstd/entropy_common.c + zstd/fse_compress.c + zstd/hist.c + zstd/huf_decompress.c + zstd/zstd_common.c + zstd/zstd_decompress.c + zstd/zstd_fast.c + zstd/zstd_ldm.c + zstd/error_private.c + zstd/fse_decompress.c + zstd/huf_compress.c + zstd/xxhash.c + zstd/zstd_compress.c + zstd/zstd_double_fast.c + zstd/zstd_lazy.c + zstd/zstd_opt.c btrfs_drv.h)
add_library(btrfs SHARED ${SOURCE} btrfs.rc) diff --git a/drivers/filesystems/btrfs/balance.c b/drivers/filesystems/btrfs/balance.c index 3e36489c31..fe641f4f41 100644 --- a/drivers/filesystems/btrfs/balance.c +++ b/drivers/filesystems/btrfs/balance.c @@ -107,13 +107,13 @@ static NTSTATUS add_metadata_reloc(_Requires_exclusive_lock_held_(_Curr_->tree_l c = get_chunk_from_address(Vcb, tp->item->key.obj_id);
if (c) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
c->used -= Vcb->superblock.node_size;
space_list_add(c, tp->item->key.obj_id, Vcb->superblock.node_size, rollback);
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); }
ei = (EXTENT_ITEM*)tp->item->data; @@ -747,7 +747,7 @@ static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree flags = Vcb->metadata_flags;
if (newchunk) { - ExAcquireResourceExclusiveLite(&newchunk->lock, TRUE); + acquire_chunk_lock(newchunk, Vcb);
if (newchunk->chunk_item->type == flags && find_metadata_address_in_chunk(Vcb, newchunk, &mr->new_address)) { newchunk->used += Vcb->superblock.node_size; @@ -755,7 +755,7 @@ static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree done = TRUE; }
- ExReleaseResourceLite(&newchunk->lock); + release_chunk_lock(newchunk, Vcb); }
if (!done) { @@ -766,20 +766,20 @@ static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree chunk* c2 = CONTAINING_RECORD(le2, chunk, list_entry);
if (!c2->readonly && !c2->reloc && c2 != newchunk && c2->chunk_item->type == flags) { - ExAcquireResourceExclusiveLite(&c2->lock, TRUE); + acquire_chunk_lock(c2, Vcb);
if ((c2->chunk_item->size - c2->used) >= Vcb->superblock.node_size) { if (find_metadata_address_in_chunk(Vcb, c2, &mr->new_address)) { c2->used += Vcb->superblock.node_size; space_list_subtract(c2, FALSE, mr->new_address, Vcb->superblock.node_size, rollback); - ExReleaseResourceLite(&c2->lock); + release_chunk_lock(c2, Vcb); newchunk = c2; done = TRUE; break; } }
- ExReleaseResourceLite(&c2->lock); + release_chunk_lock(c2, Vcb); }
le2 = le2->Flink; @@ -795,12 +795,12 @@ static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree goto end; }
- ExAcquireResourceExclusiveLite(&newchunk->lock, TRUE); + acquire_chunk_lock(newchunk, Vcb);
newchunk->balance_num = Vcb->balance.balance_num;
if (!find_metadata_address_in_chunk(Vcb, newchunk, &mr->new_address)) { - ExReleaseResourceLite(&newchunk->lock); + release_chunk_lock(newchunk, Vcb); ExReleaseResourceLite(&Vcb->chunk_lock); ERR("could not find address in new chunk\n"); Status = STATUS_DISK_FULL; @@ -810,7 +810,7 @@ static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree space_list_subtract(newchunk, FALSE, mr->new_address, Vcb->superblock.node_size, rollback); }
- ExReleaseResourceLite(&newchunk->lock); + release_chunk_lock(newchunk, Vcb); }
ExReleaseResourceLite(&Vcb->chunk_lock); @@ -1340,13 +1340,13 @@ static NTSTATUS add_data_reloc(_Requires_exclusive_lock_held_(_Curr_->tree_lock) c = get_chunk_from_address(Vcb, tp->item->key.obj_id);
if (c) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
c->used -= tp->item->key.offset;
space_list_add(c, tp->item->key.obj_id, tp->item->key.offset, rollback);
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); }
ei = (EXTENT_ITEM*)tp->item->data; @@ -1756,7 +1756,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, BOOL* change ULONG runlength, index, lastoff;
if (newchunk) { - ExAcquireResourceExclusiveLite(&newchunk->lock, TRUE); + acquire_chunk_lock(newchunk, Vcb);
if (find_data_address_in_chunk(Vcb, newchunk, dr->size, &dr->new_address)) { newchunk->used += dr->size; @@ -1764,7 +1764,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, BOOL* change done = TRUE; }
- ExReleaseResourceLite(&newchunk->lock); + release_chunk_lock(newchunk, Vcb); }
if (!done) { @@ -1775,20 +1775,20 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, BOOL* change chunk* c2 = CONTAINING_RECORD(le2, chunk, list_entry);
if (!c2->readonly && !c2->reloc && c2 != newchunk && c2->chunk_item->type == Vcb->data_flags) { - ExAcquireResourceExclusiveLite(&c2->lock, TRUE); + acquire_chunk_lock(c2, Vcb);
if ((c2->chunk_item->size - c2->used) >= dr->size) { if (find_data_address_in_chunk(Vcb, c2, dr->size, &dr->new_address)) { c2->used += dr->size; space_list_subtract(c2, FALSE, dr->new_address, dr->size, &rollback); - ExReleaseResourceLite(&c2->lock); + release_chunk_lock(c2, Vcb); newchunk = c2; done = TRUE; break; } }
- ExReleaseResourceLite(&c2->lock); + release_chunk_lock(c2, Vcb); }
le2 = le2->Flink; @@ -1804,12 +1804,12 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, BOOL* change goto end; }
- ExAcquireResourceExclusiveLite(&newchunk->lock, TRUE); + acquire_chunk_lock(newchunk, Vcb);
newchunk->balance_num = Vcb->balance.balance_num;
if (!find_data_address_in_chunk(Vcb, newchunk, dr->size, &dr->new_address)) { - ExReleaseResourceLite(&newchunk->lock); + release_chunk_lock(newchunk, Vcb); ExReleaseResourceLite(&Vcb->chunk_lock); ERR("could not find address in new chunk\n"); Status = STATUS_DISK_FULL; @@ -1819,7 +1819,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, BOOL* change space_list_subtract(newchunk, FALSE, dr->new_address, dr->size, &rollback); }
- ExReleaseResourceLite(&newchunk->lock); + release_chunk_lock(newchunk, Vcb); }
ExReleaseResourceLite(&Vcb->chunk_lock); @@ -2957,6 +2957,8 @@ static NTSTATUS try_consolidation(device_extension* Vcb, UINT64 flags, chunk** n ERR("do_write returned %08x\n", Status); return Status; } + + free_trees(Vcb); }
ExAcquireResourceExclusiveLite(&Vcb->chunk_lock, TRUE); @@ -3108,7 +3110,7 @@ void NTAPI balance_thread(void* context) { chunk* c = CONTAINING_RECORD(le, chunk, list_entry); UINT8 sort;
- ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
if (c->chunk_item->type & BLOCK_FLAG_DATA) sort = BALANCE_OPTS_DATA; @@ -3118,7 +3120,7 @@ void NTAPI balance_thread(void* context) { sort = BALANCE_OPTS_SYSTEM; else { ERR("unexpected chunk type %llx\n", c->chunk_item->type); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); break; }
@@ -3142,13 +3144,13 @@ void NTAPI balance_thread(void* context) { if (!NT_SUCCESS(Status)) { ERR("load_cache_chunk returned %08x\n", Status); Vcb->balance.status = Status; - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); ExReleaseResourceLite(&Vcb->chunk_lock); goto end; } }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb);
le = le->Flink; } diff --git a/drivers/filesystems/btrfs/btrfs.c b/drivers/filesystems/btrfs/btrfs.c index bdc2988145..2582ee0b3f 100644 --- a/drivers/filesystems/btrfs/btrfs.c +++ b/drivers/filesystems/btrfs/btrfs.c @@ -48,11 +48,12 @@
#define INCOMPAT_SUPPORTED (BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF | BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL | BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS | \ BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO | BTRFS_INCOMPAT_FLAGS_BIG_METADATA | BTRFS_INCOMPAT_FLAGS_RAID56 | \ - BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF | BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA | BTRFS_INCOMPAT_FLAGS_NO_HOLES) + BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF | BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA | BTRFS_INCOMPAT_FLAGS_NO_HOLES | \ + BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD) #define COMPAT_RO_SUPPORTED (BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE | BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID)
-static WCHAR device_name[] = {'\','B','t','r','f','s',0}; -static WCHAR dosdevice_name[] = {'\','D','o','s','D','e','v','i','c','e','s','\','B','t','r','f','s',0}; +static const WCHAR device_name[] = {'\','B','t','r','f','s',0}; +static const WCHAR dosdevice_name[] = {'\','D','o','s','D','e','v','i','c','e','s','\','B','t','r','f','s',0};
DEFINE_GUID(BtrfsBusInterface, 0x4d414874, 0x6865, 0x6761, 0x6d, 0x65, 0x83, 0x69, 0x17, 0x9a, 0x7d, 0x1d);
@@ -70,6 +71,7 @@ UINT32 mount_compress = 0; UINT32 mount_compress_force = 0; UINT32 mount_compress_type = 0; UINT32 mount_zlib_level = 3; +UINT32 mount_zstd_level = 3; UINT32 mount_flush_interval = 30; UINT32 mount_max_inline = 2048; UINT32 mount_skip_balance = 0; @@ -268,7 +270,7 @@ static void DriverUnload(_In_ PDRIVER_OBJECT DriverObject) { #endif UNICODE_STRING dosdevice_nameW;
- ERR("DriverUnload\n"); + TRACE("(%p)\n");
free_cache();
@@ -295,8 +297,8 @@ static void DriverUnload(_In_ PDRIVER_OBJECT DriverObject) { IoUnregisterPlugPlayNotificationEx(notification_entry); #endif
- dosdevice_nameW.Buffer = dosdevice_name; - dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = (USHORT)wcslen(dosdevice_name) * sizeof(WCHAR); + dosdevice_nameW.Buffer = (WCHAR*)dosdevice_name; + dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = sizeof(dosdevice_name) - sizeof(WCHAR);
IoDeleteSymbolicLink(&dosdevice_nameW); IoDeleteDevice(DriverObject->DeviceObject); @@ -621,22 +623,32 @@ static BOOL lie_about_fs_type() { PPEB peb; LIST_ENTRY* le; ULONG retlen; +#ifdef _AMD64_ + ULONG_PTR wow64info; +#endif
- static WCHAR mpr[] = L"MPR.DLL"; - static WCHAR cmd[] = L"CMD.EXE"; - static WCHAR fsutil[] = L"FSUTIL.EXE"; + static const WCHAR mpr[] = L"MPR.DLL"; + static const WCHAR cmd[] = L"CMD.EXE"; + static const WCHAR fsutil[] = L"FSUTIL.EXE"; UNICODE_STRING mprus, cmdus, fsutilus;
- mprus.Buffer = mpr; - mprus.Length = mprus.MaximumLength = (USHORT)(wcslen(mpr) * sizeof(WCHAR)); - cmdus.Buffer = cmd; - cmdus.Length = cmdus.MaximumLength = (USHORT)(wcslen(cmd) * sizeof(WCHAR)); - fsutilus.Buffer = fsutil; - fsutilus.Length = fsutilus.MaximumLength = (USHORT)(wcslen(fsutil) * sizeof(WCHAR)); + mprus.Buffer = (WCHAR*)mpr; + mprus.Length = mprus.MaximumLength = sizeof(mpr) - sizeof(WCHAR); + cmdus.Buffer = (WCHAR*)cmd; + cmdus.Length = cmdus.MaximumLength = sizeof(cmd) - sizeof(WCHAR); + fsutilus.Buffer = (WCHAR*)fsutil; + fsutilus.Length = fsutilus.MaximumLength = sizeof(fsutil) - sizeof(WCHAR);
if (!PsGetCurrentProcess()) return FALSE;
+#ifdef _AMD64_ + Status = ZwQueryInformationProcess(NtCurrentProcess(), ProcessWow64Information, &wow64info, sizeof(wow64info), NULL); + + if (NT_SUCCESS(Status) && wow64info != 0) + return TRUE; +#endif + Status = ZwQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), &retlen);
if (!NT_SUCCESS(Status)) { @@ -750,13 +762,24 @@ static NTSTATUS drv_query_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _ FILE_FS_ATTRIBUTE_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer; BOOL overflow = FALSE; #ifndef __REACTOS__ - WCHAR* fs_name = (Irp->RequestorMode == UserMode && lie_about_fs_type()) ? L"NTFS" : L"Btrfs"; - ULONG fs_name_len = (ULONG)wcslen(fs_name) * sizeof(WCHAR); + static const WCHAR ntfs[] = L"NTFS"; +#endif + static const WCHAR btrfs[] = L"Btrfs"; + const WCHAR* fs_name; + ULONG fs_name_len, orig_fs_name_len; + +#ifndef __REACTOS__ + if (Irp->RequestorMode == UserMode && lie_about_fs_type()) { + fs_name = ntfs; + orig_fs_name_len = fs_name_len = sizeof(ntfs) - sizeof(WCHAR); + } else { + fs_name = btrfs; + orig_fs_name_len = fs_name_len = sizeof(btrfs) - sizeof(WCHAR); + } #else - WCHAR* fs_name = L"Btrfs"; - ULONG fs_name_len = 5 * sizeof(WCHAR); + fs_name = btrfs; + orig_fs_name_len = fs_name_len = sizeof(btrfs) - sizeof(WCHAR); #endif - ULONG orig_fs_name_len = fs_name_len;
TRACE("FileFsAttributeInformation\n");
@@ -1705,7 +1728,7 @@ static NTSTATUS close_file(_In_ PFILE_OBJECT FileObject, _In_ PIRP Irp) { CcUninitializeCacheMap(FileObject, NULL, NULL);
if (open_files == 0 && fcb->Vcb->removing) { - uninit(fcb->Vcb, FALSE); + uninit(fcb->Vcb); return STATUS_SUCCESS; }
@@ -1726,8 +1749,9 @@ static NTSTATUS close_file(_In_ PFILE_OBJECT FileObject, _In_ PIRP Irp) { return STATUS_SUCCESS; }
-void uninit(_In_ device_extension* Vcb, _In_ BOOL flush) { +void uninit(_In_ device_extension* Vcb) { UINT64 i; + KIRQL irql; NTSTATUS Status; LIST_ENTRY* le; LARGE_INTEGER time; @@ -1738,6 +1762,11 @@ void uninit(_In_ device_extension* Vcb, _In_ BOOL flush) { ExReleaseResourceLite(&Vcb->tree_lock); }
+ IoAcquireVpbSpinLock(&irql); + Vcb->Vpb->Flags &= ~VPB_MOUNTED; + Vcb->Vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED; + IoReleaseVpbSpinLock(irql); + RemoveEntryList(&Vcb->list_entry);
if (Vcb->balance.thread) { @@ -1787,20 +1816,6 @@ void uninit(_In_ device_extension* Vcb, _In_ BOOL flush) { if (!NT_SUCCESS(Status) && Status != STATUS_TOO_LATE) WARN("registry_mark_volume_unmounted returned %08x\n", Status);
- if (flush) { - ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); - - if (Vcb->need_write && !Vcb->readonly) { - Status = do_write(Vcb, NULL); - if (!NT_SUCCESS(Status)) - ERR("do_write returned %08x\n", Status); - } - - free_trees(Vcb); - - ExReleaseResourceLite(&Vcb->tree_lock); - } - for (i = 0; i < Vcb->calcthreads.num_threads; i++) { Vcb->calcthreads.threads[i].quit = TRUE; } @@ -3599,7 +3614,7 @@ _Ret_maybenull_ static root* find_default_subvol(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_opt_ PIRP Irp) { LIST_ENTRY* le;
- static char fn[] = "default"; + static const char fn[] = "default"; static UINT32 crc32 = 0x8dbfc2d2;
if (Vcb->options.subvol_id != 0) { @@ -3764,8 +3779,8 @@ static BOOL is_btrfs_volume(_In_ PDEVICE_OBJECT DeviceObject) { return FALSE; }
- if (mdn2->NameLength > wcslen(BTRFS_VOLUME_PREFIX) * sizeof(WCHAR) && - RtlCompareMemory(mdn2->Name, BTRFS_VOLUME_PREFIX, wcslen(BTRFS_VOLUME_PREFIX) * sizeof(WCHAR)) == wcslen(BTRFS_VOLUME_PREFIX) * sizeof(WCHAR)) { + if (mdn2->NameLength > (sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)) && + RtlCompareMemory(mdn2->Name, BTRFS_VOLUME_PREFIX, sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)) == sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)) { ExFreePool(mdn2); return TRUE; } @@ -4773,7 +4788,7 @@ static NTSTATUS verify_volume(_In_ PDEVICE_OBJECT devobj) { ExReleaseResourceLite(&Vcb->tree_lock);
if (remove) { - uninit(Vcb, FALSE); + uninit(Vcb); return Status; }
@@ -4924,9 +4939,7 @@ static NTSTATUS drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { NTSTATUS Status; BOOL top_level; device_extension* Vcb = DeviceObject->DeviceExtension; -#ifdef __REACTOS__ - LIST_ENTRY *Vcble, *le; -#endif + LIST_ENTRY* le;
FsRtlEnterFileSystem();
@@ -4944,79 +4957,34 @@ static NTSTATUS drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { shutting_down = TRUE; KeSetEvent(&mountmgr_thread_event, 0, FALSE);
-#ifndef __REACTOS__ - while (!IsListEmpty(&VcbList)) { - Vcb = CONTAINING_RECORD(VcbList.Flink, device_extension, list_entry); + le = VcbList.Flink; + while (le != &VcbList) { + BOOL open_files; + LIST_ENTRY* le2 = le->Flink;
- TRACE("shutting down Vcb %p\n", Vcb); - - uninit(Vcb, TRUE); - } -#else - Vcble = VcbList.Flink; - while (Vcble != &VcbList) { - Vcb = CONTAINING_RECORD(Vcble, device_extension, list_entry); + Vcb = CONTAINING_RECORD(le, device_extension, list_entry);
TRACE("shutting down Vcb %p\n", Vcb);
- if (Vcb->balance.thread) { - Vcb->balance.paused = FALSE; - Vcb->balance.stopping = TRUE; - KeSetEvent(&Vcb->balance.event, 0, FALSE); - KeWaitForSingleObject(&Vcb->balance.finished, Executive, KernelMode, FALSE, NULL); - } - - if (Vcb->scrub.thread) { - Vcb->scrub.paused = FALSE; - Vcb->scrub.stopping = TRUE; - KeSetEvent(&Vcb->scrub.event, 0, FALSE); - KeWaitForSingleObject(&Vcb->scrub.finished, Executive, KernelMode, FALSE, NULL); - } - - if (Vcb->running_sends != 0) { - BOOL send_cancelled = FALSE; - - ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE); - - le = Vcb->send_ops.Flink; - while (le != &Vcb->send_ops) { - send_info* send = CONTAINING_RECORD(le, send_info, list_entry); - - if (!send->cancelling) { - send->cancelling = TRUE; - send_cancelled = TRUE; - send->ccb = NULL; - KeSetEvent(&send->cleared_event, 0, FALSE); - } - - le = le->Flink; - } - - ExReleaseResourceLite(&Vcb->send_load_lock); - - if (send_cancelled) { - while (Vcb->running_sends != 0) { - ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE); - ExReleaseResourceLite(&Vcb->send_load_lock); - } - } - } - ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); + Vcb->removing = TRUE; + open_files = Vcb->open_files > 0;
if (Vcb->need_write && !Vcb->readonly) { Status = do_write(Vcb, Irp); - if (!NT_SUCCESS(Status)) ERR("do_write returned %08x\n", Status); }
- Vcb->removing = TRUE; + free_trees(Vcb);
ExReleaseResourceLite(&Vcb->tree_lock); - Vcble = Vcble->Flink; + + if (!open_files) + uninit(Vcb); + + le = le2; } -#endif
#ifdef _DEBUG if (comfo) { @@ -5333,7 +5301,7 @@ static void init_logging() { FILE_STANDARD_INFORMATION fsi; FILE_POSITION_INFORMATION fpi;
- static char delim[] = "\n---\n"; + static const char delim[] = "\n---\n";
// move to end of file
@@ -5353,7 +5321,7 @@ static void init_logging() { goto end; }
- Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, delim, (ULONG)strlen(delim), NULL, NULL); + Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, (void*)delim, sizeof(delim) - 1, NULL, NULL);
if (!NT_SUCCESS(Status)) { ERR("ZwWriteFile returned %08x\n", Status); @@ -5453,7 +5421,7 @@ NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObj
ExAcquireResourceSharedLite(&pdode->child_lock, TRUE);
- volname.Length = volname.MaximumLength = (USHORT)((wcslen(BTRFS_VOLUME_PREFIX) + 36 + 1) * sizeof(WCHAR)); + volname.Length = volname.MaximumLength = (sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)) + ((36 + 1) * sizeof(WCHAR)); volname.Buffer = ExAllocatePoolWithTag(PagedPool, volname.MaximumLength, ALLOC_TAG); // FIXME - when do we free this?
if (!volname.Buffer) { @@ -5462,9 +5430,9 @@ NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObj goto end2; }
- RtlCopyMemory(volname.Buffer, BTRFS_VOLUME_PREFIX, wcslen(BTRFS_VOLUME_PREFIX) * sizeof(WCHAR)); + RtlCopyMemory(volname.Buffer, BTRFS_VOLUME_PREFIX, sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR));
- j = (ULONG)wcslen(BTRFS_VOLUME_PREFIX); + j = (sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1; for (i = 0; i < 16; i++) { volname.Buffer[j] = hex_digit(pdode->uuid.uuid[i] >> 4); j++; volname.Buffer[j] = hex_digit(pdode->uuid.uuid[i] & 0xf); j++; @@ -5670,10 +5638,10 @@ NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING Regi
init_fast_io_dispatch(&DriverObject->FastIoDispatch);
- device_nameW.Buffer = device_name; - device_nameW.Length = device_nameW.MaximumLength = (USHORT)wcslen(device_name) * sizeof(WCHAR); - dosdevice_nameW.Buffer = dosdevice_name; - dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = (USHORT)wcslen(dosdevice_name) * sizeof(WCHAR); + device_nameW.Buffer = (WCHAR*)device_name; + device_nameW.Length = device_nameW.MaximumLength = sizeof(device_name) - sizeof(WCHAR); + dosdevice_nameW.Buffer = (WCHAR*)dosdevice_name; + dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = sizeof(dosdevice_name) - sizeof(WCHAR);
Status = IoCreateDevice(DriverObject, sizeof(control_device_extension), &device_nameW, FILE_DEVICE_DISK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject); diff --git a/drivers/filesystems/btrfs/btrfs.h b/drivers/filesystems/btrfs/btrfs.h index 27e9b63f51..eede405985 100644 --- a/drivers/filesystems/btrfs/btrfs.h +++ b/drivers/filesystems/btrfs/btrfs.h @@ -58,6 +58,7 @@ static const UINT64 superblock_addrs[] = { 0x10000, 0x4000000, 0x4000000000, 0x4 #define BTRFS_COMPRESSION_NONE 0 #define BTRFS_COMPRESSION_ZLIB 1 #define BTRFS_COMPRESSION_LZO 2 +#define BTRFS_COMPRESSION_ZSTD 3
#define BTRFS_ENCRYPTION_NONE 0
@@ -103,7 +104,7 @@ static const UINT64 superblock_addrs[] = { 0x10000, 0x4000000, 0x4000000000, 0x4 #define BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL 0x0002 #define BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS 0x0004 #define BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO 0x0008 -#define BTRFS_INCOMPAT_FLAGS_COMPRESS_LZOV2 0x0010 +#define BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD 0x0010 #define BTRFS_INCOMPAT_FLAGS_BIG_METADATA 0x0020 #define BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF 0x0040 #define BTRFS_INCOMPAT_FLAGS_RAID56 0x0080 diff --git a/drivers/filesystems/btrfs/btrfs.rc b/drivers/filesystems/btrfs/btrfs.rc index 50f7463328..957792add5 100644 --- a/drivers/filesystems/btrfs/btrfs.rc +++ b/drivers/filesystems/btrfs/btrfs.rc @@ -53,8 +53,8 @@ END //
VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,2,0 - PRODUCTVERSION 1,0,2,0 + FILEVERSION 1,1,0,0 + PRODUCTVERSION 1,1,0,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -70,12 +70,12 @@ BEGIN BLOCK "080904b0" BEGIN VALUE "FileDescription", "WinBtrfs" - VALUE "FileVersion", "1.0.2" + VALUE "FileVersion", "1.1" VALUE "InternalName", "btrfs" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-18" VALUE "OriginalFilename", "btrfs.sys" VALUE "ProductName", "WinBtrfs" - VALUE "ProductVersion", "1.0.2" + VALUE "ProductVersion", "1.1" END END BLOCK "VarFileInfo" diff --git a/drivers/filesystems/btrfs/btrfs_drv.h b/drivers/filesystems/btrfs/btrfs_drv.h index 857555f755..e6ea5891f3 100644 --- a/drivers/filesystems/btrfs/btrfs_drv.h +++ b/drivers/filesystems/btrfs/btrfs_drv.h @@ -74,6 +74,7 @@ // #define DEBUG_LONG_MESSAGES // #define DEBUG_FLUSH_TIMES // #define DEBUG_STATS +// #define DEBUG_CHUNK_LOCKS #define DEBUG_PARANOID #endif
@@ -110,6 +111,11 @@
#define IO_REPARSE_TAG_LXSS_SYMLINK 0xa000001d // undocumented?
+#define IO_REPARSE_TAG_LXSS_SOCKET 0x80000023 +#define IO_REPARSE_TAG_LXSS_FIFO 0x80000024 +#define IO_REPARSE_TAG_LXSS_CHARDEV 0x80000025 +#define IO_REPARSE_TAG_LXSS_BLOCKDEV 0x80000026 + #define BTRFS_VOLUME_PREFIX L"\Device\Btrfs{"
#ifdef _MSC_VER @@ -234,7 +240,8 @@ typedef struct { enum prop_compression_type { PropCompression_None, PropCompression_Zlib, - PropCompression_LZO + PropCompression_LZO, + PropCompression_ZSTD };
typedef struct { @@ -606,6 +613,7 @@ typedef struct { UINT8 compress_type; BOOL readonly; UINT32 zlib_level; + UINT32 zstd_level; UINT32 flush_interval; UINT32 max_inline; UINT64 subvol_id; @@ -716,6 +724,9 @@ typedef struct _device_extension { LIST_ENTRY devices; #ifdef DEBUG_STATS debug_stats stats; +#endif +#ifdef DEBUG_CHUNK_LOCKS + LONG chunk_locks_held; #endif UINT64 devices_loaded; superblock superblock; @@ -955,10 +966,10 @@ static __inline UINT64 unix_time_to_win(BTRFS_TIME* t) { }
static __inline void win_time_to_unix(LARGE_INTEGER t, BTRFS_TIME* out) { - ULONGLONG l = t.QuadPart - 116444736000000000; + ULONGLONG l = (ULONGLONG)t.QuadPart - 116444736000000000;
out->seconds = l / 10000000; - out->nanoseconds = (l % 10000000) * 100; + out->nanoseconds = (UINT32)((l % 10000000) * 100); }
_Post_satisfies_(*stripe>=0&&*stripe<num_stripes) @@ -1083,13 +1094,21 @@ void protect_superblocks(_Inout_ chunk* c); BOOL is_top_level(_In_ PIRP Irp); NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ UINT64 id, _Out_ root** rootptr, _In_ BOOL no_tree, _In_ UINT64 offset, _In_opt_ PIRP Irp); -void uninit(_In_ device_extension* Vcb, _In_ BOOL flush); +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_ BOOLEAN Override, _Out_opt_ IO_STATUS_BLOCK* iosb); BOOL is_file_name_valid(_In_ PUNICODE_STRING us, _In_ BOOL posix); void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream); void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream);
+#ifdef DEBUG_CHUNK_LOCKS +#define acquire_chunk_lock(c, Vcb) { ExAcquireResourceExclusiveLite(&c->lock, TRUE); InterlockedIncrement(&Vcb->chunk_locks_held); } +#define release_chunk_lock(c, Vcb) { InterlockedDecrement(&Vcb->chunk_locks_held); ExReleaseResourceLite(&c->lock); } +#else +#define acquire_chunk_lock(c, Vcb) ExAcquireResourceExclusiveLite(&(c)->lock, TRUE) +#define release_chunk_lock(c, Vcb) ExReleaseResourceLite(&(c)->lock) +#endif + _Ret_z_ WCHAR* file_desc(_In_ PFILE_OBJECT FileObject); WCHAR* file_desc_fileref(_In_ file_ref* fileref); @@ -1123,6 +1142,7 @@ extern UINT32 mount_compress; extern UINT32 mount_compress_force; extern UINT32 mount_compress_type; extern UINT32 mount_zlib_level; +extern UINT32 mount_zstd_level; extern UINT32 mount_flush_interval; extern UINT32 mount_max_inline; extern UINT32 mount_skip_balance; @@ -1208,6 +1228,18 @@ typedef struct { LIST_ENTRY list_entry; } rollback_item;
+typedef struct { + ANSI_STRING name; + ANSI_STRING value; + UCHAR flags; + LIST_ENTRY list_entry; +} ea_item; + +static const char lxuid[] = "$LXUID"; +static const char lxgid[] = "$LXGID"; +static const char lxmod[] = "$LXMOD"; +static const char lxdev[] = "$LXDEV"; + // in treefuncs.c NTSTATUS find_item(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _Out_ traverse_ptr* tp, _In_ const KEY* searchkey, _In_ BOOL ignore, _In_opt_ PIRP Irp); @@ -1307,6 +1339,7 @@ _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI drv_directory_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
ULONG get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type, ULONG atts, BOOL lxss, PIRP Irp); +ULONG get_reparse_tag_fcb(fcb* fcb);
// in security.c
@@ -1353,6 +1386,7 @@ void remove_dir_child_from_hash_lists(fcb* fcb, dir_child* dc);
// in reparse.c NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, void* buffer, DWORD buflen, ULONG_PTR* retlen); +NTSTATUS set_reparse_point2(fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG buflen, ccb* ccb, file_ref* fileref, PIRP Irp, LIST_ENTRY* rollback); NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp); NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp);
@@ -1479,6 +1513,7 @@ void watch_registry(HANDLE regh); // in compress.c NTSTATUS zlib_decompress(UINT8* inbuf, UINT32 inlen, UINT8* outbuf, UINT32 outlen); NTSTATUS lzo_decompress(UINT8* inbuf, UINT32 inlen, UINT8* outbuf, UINT32 outlen, UINT32 inpageoff); +NTSTATUS zstd_decompress(UINT8* inbuf, UINT32 inlen, UINT8* outbuf, UINT32 outlen); NTSTATUS write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, BOOL* compressed, PIRP Irp, LIST_ENTRY* rollback);
// in galois.c @@ -1720,6 +1755,10 @@ static __inline void do_xor(UINT8* buf1, UINT8* buf2, UINT32 len) { #define S_ISVTX 0001000 #endif
+// based on functions in sys/sysmacros.h +#define major(rdev) ((((rdev) >> 8) & 0xFFF) | ((UINT32)((rdev) >> 32) & ~0xFFF)) +#define minor(rdev) (((rdev) & 0xFF) | ((UINT32)((rdev) >> 12) & ~0xFF)) + static __inline UINT64 fcb_alloc_size(fcb* fcb) { if (S_ISDIR(fcb->inode_item.st_mode)) return 0; diff --git a/drivers/filesystems/btrfs/btrfsioctl.h b/drivers/filesystems/btrfs/btrfsioctl.h index 9c57c9cb60..a7f53b3317 100644 --- a/drivers/filesystems/btrfs/btrfsioctl.h +++ b/drivers/filesystems/btrfs/btrfsioctl.h @@ -63,6 +63,7 @@ typedef struct { #define BTRFS_COMPRESSION_ANY 0 #define BTRFS_COMPRESSION_ZLIB 1 #define BTRFS_COMPRESSION_LZO 2 +#define BTRFS_COMPRESSION_ZSTD 3
typedef struct { UINT64 subvol; @@ -79,6 +80,25 @@ typedef struct { UINT8 compression_type; } btrfs_inode_info;
+typedef struct { + UINT64 subvol; + UINT64 inode; + BOOL top; + UINT8 type; + UINT32 st_uid; + UINT32 st_gid; + UINT32 st_mode; + UINT64 st_rdev; + UINT64 flags; + UINT32 inline_length; + UINT64 disk_size_uncompressed; + UINT64 disk_size_zlib; + UINT64 disk_size_lzo; + UINT8 compression_type; + UINT64 disk_size_zstd; + UINT64 sparse_size; +} btrfs_inode_info2; + typedef struct { UINT64 flags; BOOL flags_changed; diff --git a/drivers/filesystems/btrfs/compress.c b/drivers/filesystems/btrfs/compress.c index 0a8a1f7269..598171b678 100644 --- a/drivers/filesystems/btrfs/compress.c +++ b/drivers/filesystems/btrfs/compress.c @@ -39,6 +39,10 @@ #include <zlib.h> #endif
+#define ZSTD_STATIC_LINKING_ONLY + +#include "zstd/zstd.h" + #define LINUX_PAGE_SIZE 4096
typedef struct { @@ -82,6 +86,16 @@ typedef struct {
#define LZO_BYTE(x) ((unsigned char) (x))
+#define ZSTD_ALLOC_TAG 0x6474737a // "zstd" + +// needs to be the same as Linux (fs/btrfs/zstd.c) +#define ZSTD_BTRFS_MAX_WINDOWLOG 17 + +static void* zstd_malloc(void* opaque, size_t size); +static void zstd_free(void* opaque, void* address); + +ZSTD_customMem zstd_mem = { .customAlloc = zstd_malloc, .customFree = zstd_free, .opaque = NULL }; + static UINT8 lzo_nextbyte(lzo_stream* stream) { UINT8 c;
@@ -449,7 +463,7 @@ static NTSTATUS zlib_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 en c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly && !c->reloc) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == fcb->Vcb->data_flags && (c->chunk_item->size - c->used) >= comp_length) { if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, Irp, rollback, compression, end_data - start_data, FALSE, 0)) { @@ -462,7 +476,7 @@ static NTSTATUS zlib_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 en } }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, fcb->Vcb); }
le = le->Flink; @@ -486,7 +500,7 @@ static NTSTATUS zlib_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 en }
if (c) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == fcb->Vcb->data_flags && (c->chunk_item->size - c->used) >= comp_length) { if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, Irp, rollback, compression, end_data - start_data, FALSE, 0)) { @@ -497,7 +511,7 @@ static NTSTATUS zlib_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 en } }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, fcb->Vcb); }
WARN("couldn't find any data chunks with %llx bytes free\n", comp_length); @@ -847,7 +861,7 @@ static NTSTATUS lzo_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly && !c->reloc) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == fcb->Vcb->data_flags && (c->chunk_item->size - c->used) >= comp_length) { if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, Irp, rollback, compression, end_data - start_data, FALSE, 0)) { @@ -860,7 +874,7 @@ static NTSTATUS lzo_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end } }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, fcb->Vcb); }
le = le->Flink; @@ -884,7 +898,7 @@ static NTSTATUS lzo_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end }
if (c) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == fcb->Vcb->data_flags && (c->chunk_item->size - c->used) >= comp_length) { if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, Irp, rollback, compression, end_data - start_data, FALSE, 0)) { @@ -895,7 +909,173 @@ static NTSTATUS lzo_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end } }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, fcb->Vcb); + } + + WARN("couldn't find any data chunks with %llx bytes free\n", comp_length); + + if (compression != BTRFS_COMPRESSION_NONE) + ExFreePool(comp_data); + + return STATUS_DISK_FULL; +} + +static NTSTATUS zstd_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, BOOL* compressed, PIRP Irp, LIST_ENTRY* rollback) { + NTSTATUS Status; + UINT8 compression; + UINT32 comp_length; + UINT8* comp_data; + UINT32 out_left; + LIST_ENTRY* le; + chunk* c; + ZSTD_CStream* stream; + size_t init_res, written; + ZSTD_inBuffer input; + ZSTD_outBuffer output; + ZSTD_parameters params; + + comp_data = ExAllocatePoolWithTag(PagedPool, (UINT32)(end_data - start_data), ALLOC_TAG); + if (!comp_data) { + ERR("out of memory\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Status = excise_extents(fcb->Vcb, fcb, start_data, end_data, Irp, rollback); + if (!NT_SUCCESS(Status)) { + ERR("excise_extents returned %08x\n", Status); + ExFreePool(comp_data); + return Status; + } + + stream = ZSTD_createCStream_advanced(zstd_mem); + + if (!stream) { + ERR("ZSTD_createCStream failed.\n"); + ExFreePool(comp_data); + return STATUS_INTERNAL_ERROR; + } + + params = ZSTD_getParams(fcb->Vcb->options.zstd_level, (UINT32)(end_data - start_data), 0); + + if (params.cParams.windowLog > ZSTD_BTRFS_MAX_WINDOWLOG) + params.cParams.windowLog = ZSTD_BTRFS_MAX_WINDOWLOG; + + init_res = ZSTD_initCStream_advanced(stream, NULL, 0, params, (UINT32)(end_data - start_data)); + + if (ZSTD_isError(init_res)) { + ERR("ZSTD_initCStream_advanced failed: %s\n", ZSTD_getErrorName(init_res)); + ZSTD_freeCStream(stream); + ExFreePool(comp_data); + return STATUS_INTERNAL_ERROR; + } + + input.src = data; + input.size = (UINT32)(end_data - start_data); + input.pos = 0; + + output.dst = comp_data; + output.size = (UINT32)(end_data - start_data); + output.pos = 0; + + while (input.pos < input.size && output.pos < output.size) { + written = ZSTD_compressStream(stream, &output, &input); + + if (ZSTD_isError(written)) { + ERR("ZSTD_compressStream failed: %s\n", ZSTD_getErrorName(written)); + ZSTD_freeCStream(stream); + ExFreePool(comp_data); + return STATUS_INTERNAL_ERROR; + } + } + + written = ZSTD_endStream(stream, &output); + if (ZSTD_isError(written)) { + ERR("ZSTD_endStream failed: %s\n", ZSTD_getErrorName(written)); + ZSTD_freeCStream(stream); + ExFreePool(comp_data); + return STATUS_INTERNAL_ERROR; + } + + ZSTD_freeCStream(stream); + + out_left = output.size - output.pos; + + if (out_left < fcb->Vcb->superblock.sector_size) { // compressed extent would be larger than or same size as uncompressed extent + ExFreePool(comp_data); + + comp_length = (UINT32)(end_data - start_data); + comp_data = data; + compression = BTRFS_COMPRESSION_NONE; + + *compressed = FALSE; + } else { + UINT32 cl; + + compression = BTRFS_COMPRESSION_ZSTD; + cl = (UINT32)(end_data - start_data - out_left); + comp_length = (UINT32)sector_align(cl, fcb->Vcb->superblock.sector_size); + + RtlZeroMemory(comp_data + cl, comp_length - cl); + + *compressed = TRUE; + } + + ExAcquireResourceSharedLite(&fcb->Vcb->chunk_lock, TRUE); + + le = fcb->Vcb->chunks.Flink; + while (le != &fcb->Vcb->chunks) { + c = CONTAINING_RECORD(le, chunk, list_entry); + + if (!c->readonly && !c->reloc) { + acquire_chunk_lock(c, fcb->Vcb); + + if (c->chunk_item->type == fcb->Vcb->data_flags && (c->chunk_item->size - c->used) >= comp_length) { + if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, Irp, rollback, compression, end_data - start_data, FALSE, 0)) { + ExReleaseResourceLite(&fcb->Vcb->chunk_lock); + + if (compression != BTRFS_COMPRESSION_NONE) + ExFreePool(comp_data); + + return STATUS_SUCCESS; + } + } + + release_chunk_lock(c, fcb->Vcb); + } + + le = le->Flink; + } + + ExReleaseResourceLite(&fcb->Vcb->chunk_lock); + + ExAcquireResourceExclusiveLite(&fcb->Vcb->chunk_lock, TRUE); + + Status = alloc_chunk(fcb->Vcb, fcb->Vcb->data_flags, &c, FALSE); + + ExReleaseResourceLite(&fcb->Vcb->chunk_lock); + + if (!NT_SUCCESS(Status)) { + ERR("alloc_chunk returned %08x\n", Status); + + if (compression != BTRFS_COMPRESSION_NONE) + ExFreePool(comp_data); + + return Status; + } + + if (c) { + acquire_chunk_lock(c, fcb->Vcb); + + if (c->chunk_item->type == fcb->Vcb->data_flags && (c->chunk_item->size - c->used) >= comp_length) { + if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, Irp, rollback, compression, end_data - start_data, FALSE, 0)) { + if (compression != BTRFS_COMPRESSION_NONE) + ExFreePool(comp_data); + + return STATUS_SUCCESS; + } + } + + release_chunk_lock(c, fcb->Vcb); }
WARN("couldn't find any data chunks with %llx bytes free\n", comp_length); @@ -912,18 +1092,82 @@ NTSTATUS write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void if (fcb->Vcb->options.compress_type != 0 && fcb->prop_compression == PropCompression_None) type = fcb->Vcb->options.compress_type; else { - if (!(fcb->Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO) && fcb->prop_compression == PropCompression_LZO) { - fcb->Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO; + if (!(fcb->Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD) && fcb->prop_compression == PropCompression_ZSTD) + type = BTRFS_COMPRESSION_ZSTD; + else if (fcb->Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD && fcb->prop_compression != PropCompression_Zlib && fcb->prop_compression != PropCompression_LZO) + type = BTRFS_COMPRESSION_ZSTD; + else if (!(fcb->Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO) && fcb->prop_compression == PropCompression_LZO) type = BTRFS_COMPRESSION_LZO; - } else if (fcb->Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO && fcb->prop_compression != PropCompression_Zlib) + else if (fcb->Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO && fcb->prop_compression != PropCompression_Zlib) type = BTRFS_COMPRESSION_LZO; else type = BTRFS_COMPRESSION_ZLIB; }
- if (type == BTRFS_COMPRESSION_LZO) { + if (type == BTRFS_COMPRESSION_ZSTD) { + fcb->Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD; + return zstd_write_compressed_bit(fcb, start_data, end_data, data, compressed, Irp, rollback); + } else if (type == BTRFS_COMPRESSION_LZO) { fcb->Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO; return lzo_write_compressed_bit(fcb, start_data, end_data, data, compressed, Irp, rollback); } else return zlib_write_compressed_bit(fcb, start_data, end_data, data, compressed, Irp, rollback); } + +static void* zstd_malloc(void* opaque, size_t size) { + UNUSED(opaque); + + return ExAllocatePoolWithTag(PagedPool, size, ZSTD_ALLOC_TAG); +} + +static void zstd_free(void* opaque, void* address) { + UNUSED(opaque); + + ExFreePool(address); +} + +NTSTATUS zstd_decompress(UINT8* inbuf, UINT32 inlen, UINT8* outbuf, UINT32 outlen) { + NTSTATUS Status; + ZSTD_DStream* stream; + size_t init_res, read; + ZSTD_inBuffer input; + ZSTD_outBuffer output; + + stream = ZSTD_createDStream_advanced(zstd_mem); + + if (!stream) { + ERR("ZSTD_createDStream failed.\n"); + return STATUS_INTERNAL_ERROR; + } + + init_res = ZSTD_initDStream(stream); + + if (ZSTD_isError(init_res)) { + ERR("ZSTD_initDStream failed: %s\n", ZSTD_getErrorName(init_res)); + Status = STATUS_INTERNAL_ERROR; + goto end; + } + + input.src = inbuf; + input.size = inlen; + input.pos = 0; + + output.dst = outbuf; + output.size = outlen; + output.pos = 0; + + read = ZSTD_decompressStream(stream, &output, &input); + + if (ZSTD_isError(read)) { + ERR("ZSTD_decompressStream failed: %s\n", ZSTD_getErrorName(read)); + Status = STATUS_INTERNAL_ERROR; + goto end; + } + + Status = STATUS_SUCCESS; + +end: + ZSTD_freeDStream(stream); + + return Status; +} diff --git a/drivers/filesystems/btrfs/create.c b/drivers/filesystems/btrfs/create.c index 4c4c5dd984..1b4417e802 100644 --- a/drivers/filesystems/btrfs/create.c +++ b/drivers/filesystems/btrfs/create.c @@ -23,7 +23,24 @@
extern PDEVICE_OBJECT master_devobj;
-static WCHAR datastring[] = L"::$DATA"; +static const WCHAR datastring[] = L"::$DATA"; + +// Windows 10 +#define ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED 0x0002 +#define ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT 0x0100 +#define ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET 0x0002 + +typedef struct _ATOMIC_CREATE_ECP_CONTEXT { + USHORT Size; + USHORT InFlags; + USHORT OutFlags; + USHORT ReparseBufferLength; + PREPARSE_DATA_BUFFER ReparseBuffer; + LONGLONG FileSize; + LONGLONG ValidDataLength; +} ATOMIC_CREATE_ECP_CONTEXT, *PATOMIC_CREATE_ECP_CONTEXT; + +static const GUID GUID_ECP_ATOMIC_CREATE = { 0x4720bd83, 0x52ac, 0x4104, { 0xa1, 0x30, 0xd1, 0xec, 0x6a, 0x8c, 0xc8, 0xe5 } };
fcb* create_fcb(device_extension* Vcb, POOL_TYPE pool_type) { fcb* fcb; @@ -308,11 +325,11 @@ static NTSTATUS split_path(device_extension* Vcb, PUNICODE_STRING path, LIST_ENT InsertTailList(parts, &nb->list_entry);
if (has_stream) { - static WCHAR datasuf[] = {':','$','D','A','T','A',0}; + static const WCHAR datasuf[] = {':','$','D','A','T','A',0}; UNICODE_STRING dsus;
- dsus.Buffer = datasuf; - dsus.Length = dsus.MaximumLength = (UINT16)wcslen(datasuf) * sizeof(WCHAR); + dsus.Buffer = (WCHAR*)datasuf; + dsus.Length = dsus.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
for (i = 0; i < nb->us.Length / sizeof(WCHAR); i++) { if (nb->us.Buffer[i] == ':') { @@ -799,7 +816,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo ULONG len; DIR_ITEM* di;
- static char xapref[] = "user."; + static const char xapref[] = "user.";
if (tp.item->size < offsetof(DIR_ITEM, name[0])) { ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, offsetof(DIR_ITEM, name[0])); @@ -813,7 +830,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo if (len < offsetof(DIR_ITEM, name[0]) + di->m + di->n) break;
- if (tp.item->key.offset == EA_REPARSE_HASH && di->n == strlen(EA_REPARSE) && RtlCompareMemory(EA_REPARSE, di->name, di->n) == di->n) { + if (tp.item->key.offset == EA_REPARSE_HASH && di->n == sizeof(EA_REPARSE) - 1 && RtlCompareMemory(EA_REPARSE, di->name, di->n) == di->n) { if (di->m > 0) { fcb->reparse_xattr.Buffer = ExAllocatePoolWithTag(PagedPool, di->m, ALLOC_TAG); if (!fcb->reparse_xattr.Buffer) { @@ -827,7 +844,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo fcb->reparse_xattr.Buffer = NULL;
fcb->reparse_xattr.Length = fcb->reparse_xattr.MaximumLength = di->m; - } else if (tp.item->key.offset == EA_EA_HASH && di->n == strlen(EA_EA) && RtlCompareMemory(EA_EA, di->name, di->n) == di->n) { + } else if (tp.item->key.offset == EA_EA_HASH && di->n == sizeof(EA_EA) - 1 && RtlCompareMemory(EA_EA, di->name, di->n) == di->n) { if (di->m > 0) { ULONG offset;
@@ -863,7 +880,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo } while (TRUE); } } - } else if (tp.item->key.offset == EA_DOSATTRIB_HASH && di->n == strlen(EA_DOSATTRIB) && RtlCompareMemory(EA_DOSATTRIB, di->name, di->n) == di->n) { + } else if (tp.item->key.offset == EA_DOSATTRIB_HASH && di->n == sizeof(EA_DOSATTRIB) - 1 && RtlCompareMemory(EA_DOSATTRIB, di->name, di->n) == di->n) { if (di->m > 0) { if (get_file_attributes_from_xattr(&di->name[di->n], di->m, &fcb->atts)) { atts_set = TRUE; @@ -884,7 +901,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo } } } - } else if (tp.item->key.offset == EA_NTACL_HASH && di->n == strlen(EA_NTACL) && RtlCompareMemory(EA_NTACL, di->name, di->n) == di->n) { + } else if (tp.item->key.offset == EA_NTACL_HASH && di->n == sizeof(EA_NTACL) - 1 && RtlCompareMemory(EA_NTACL, di->name, di->n) == di->n) { if (di->m > 0) { fcb->sd = ExAllocatePoolWithTag(PagedPool, di->m, ALLOC_TAG); if (!fcb->sd) { @@ -902,23 +919,26 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo else sd_set = TRUE; } - } else if (tp.item->key.offset == EA_PROP_COMPRESSION_HASH && di->n == strlen(EA_PROP_COMPRESSION) && RtlCompareMemory(EA_PROP_COMPRESSION, di->name, di->n) == di->n) { + } else if (tp.item->key.offset == EA_PROP_COMPRESSION_HASH && di->n == sizeof(EA_PROP_COMPRESSION) - 1 && RtlCompareMemory(EA_PROP_COMPRESSION, di->name, di->n) == di->n) { if (di->m > 0) { - const char lzo[] = "lzo"; - const char zlib[] = "zlib"; + static const char lzo[] = "lzo"; + static const char zlib[] = "zlib"; + static const char zstd[] = "zstd";
- if (di->m == strlen(lzo) && RtlCompareMemory(&di->name[di->n], lzo, di->m) == di->m) + if (di->m == sizeof(lzo) - 1 && RtlCompareMemory(&di->name[di->n], lzo, di->m) == di->m) fcb->prop_compression = PropCompression_LZO; - else if (di->m == strlen(zlib) && RtlCompareMemory(&di->name[di->n], zlib, di->m) == di->m) + else if (di->m == sizeof(zlib) - 1 && RtlCompareMemory(&di->name[di->n], zlib, di->m) == di->m) fcb->prop_compression = PropCompression_Zlib; + else if (di->m == sizeof(zstd) - 1 && RtlCompareMemory(&di->name[di->n], zstd, di->m) == di->m) + fcb->prop_compression = PropCompression_ZSTD; else fcb->prop_compression = PropCompression_None; } - } else if (di->n > strlen(xapref) && RtlCompareMemory(xapref, di->name, strlen(xapref)) == strlen(xapref)) { + } else if (di->n > sizeof(xapref) - 1 && RtlCompareMemory(xapref, di->name, sizeof(xapref) - 1) == sizeof(xapref) - 1) { dir_child* dc; ULONG utf16len;
- Status = RtlUTF8ToUnicodeN(NULL, 0, &utf16len, &di->name[strlen(xapref)], di->n - (ULONG)strlen(xapref)); + Status = RtlUTF8ToUnicodeN(NULL, 0, &utf16len, &di->name[sizeof(xapref) - 1], di->n + 1 - sizeof(xapref)); if (!NT_SUCCESS(Status)) { ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status); free_fcb(Vcb, fcb); @@ -934,7 +954,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo
RtlZeroMemory(dc, sizeof(dir_child));
- dc->utf8.MaximumLength = dc->utf8.Length = di->n - (UINT16)strlen(xapref); + dc->utf8.MaximumLength = dc->utf8.Length = di->n + 1 - sizeof(xapref); dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, dc->utf8.MaximumLength, ALLOC_TAG); if (!dc->utf8.Buffer) { ERR("out of memory\n"); @@ -943,7 +963,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo return STATUS_INSUFFICIENT_RESOURCES; }
- RtlCopyMemory(dc->utf8.Buffer, &di->name[strlen(xapref)], dc->utf8.Length); + RtlCopyMemory(dc->utf8.Buffer, &di->name[sizeof(xapref) - 1], dc->utf8.Length);
dc->name.MaximumLength = dc->name.Length = (UINT16)utf16len; dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, dc->name.MaximumLength, ALLOC_TAG); @@ -1113,11 +1133,11 @@ static NTSTATUS open_fcb_stream(_Requires_lock_held_(_Curr_->tree_lock) _Require NTSTATUS Status; KEY searchkey; traverse_ptr tp; - static char xapref[] = "user."; + static const char xapref[] = "user."; ANSI_STRING xattr; UINT32 crc32;
- xattr.Length = (UINT16)strlen(xapref) + dc->utf8.Length; + xattr.Length = sizeof(xapref) - 1 + dc->utf8.Length; xattr.MaximumLength = xattr.Length + 1; xattr.Buffer = ExAllocatePoolWithTag(PagedPool, xattr.MaximumLength, ALLOC_TAG); if (!xattr.Buffer) { @@ -1125,8 +1145,8 @@ static NTSTATUS open_fcb_stream(_Requires_lock_held_(_Curr_->tree_lock) _Require return STATUS_INSUFFICIENT_RESOURCES; }
- RtlCopyMemory(xattr.Buffer, xapref, strlen(xapref)); - RtlCopyMemory(&xattr.Buffer[strlen(xapref)], dc->utf8.Buffer, dc->utf8.Length); + RtlCopyMemory(xattr.Buffer, xapref, sizeof(xapref) - 1); + RtlCopyMemory(&xattr.Buffer[sizeof(xapref) - 1], dc->utf8.Buffer, dc->utf8.Length); xattr.Buffer[xattr.Length] = 0;
fcb = create_fcb(Vcb, PagedPool); @@ -1454,7 +1474,7 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusiv InitializeListHead(&parts);
if (fnus->Length != 0 && - (fnus->Length != wcslen(datastring) * sizeof(WCHAR) || RtlCompareMemory(fnus->Buffer, datastring, wcslen(datastring) * sizeof(WCHAR)) != wcslen(datastring) * sizeof(WCHAR))) { + (fnus->Length != sizeof(datastring) - sizeof(WCHAR) || RtlCompareMemory(fnus->Buffer, datastring, sizeof(datastring) - sizeof(WCHAR)) != sizeof(datastring) - sizeof(WCHAR))) { Status = split_path(Vcb, &fnus2, &parts, &has_stream); if (!NT_SUCCESS(Status)) { ERR("split_path returned %08x\n", Status); @@ -1649,6 +1669,218 @@ UINT32 inherit_mode(fcb* parfcb, BOOL is_dir) { return mode; }
+static NTSTATUS file_create_parse_ea(fcb* fcb, FILE_FULL_EA_INFORMATION* ea) { + NTSTATUS Status; + LIST_ENTRY ealist, *le; + UINT16 size = 0; + char* buf; + + InitializeListHead(&ealist); + + do { + STRING s; + BOOL found = FALSE; + + s.Length = s.MaximumLength = ea->EaNameLength; + s.Buffer = ea->EaName; + + RtlUpperString(&s, &s); + + le = ealist.Flink; + while (le != &ealist) { + ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry); + + if (item->name.Length == s.Length && RtlCompareMemory(item->name.Buffer, s.Buffer, s.Length) == s.Length) { + item->flags = ea->Flags; + item->value.Length = item->value.MaximumLength = ea->EaValueLength; + item->value.Buffer = &ea->EaName[ea->EaNameLength + 1]; + found = TRUE; + break; + } + + le = le->Flink; + } + + if (!found) { + ea_item* item = ExAllocatePoolWithTag(PagedPool, sizeof(ea_item), ALLOC_TAG); + if (!item) { + ERR("out of memory\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto end; + } + + item->name.Length = item->name.MaximumLength = ea->EaNameLength; + item->name.Buffer = ea->EaName; + + item->value.Length = item->value.MaximumLength = ea->EaValueLength; + item->value.Buffer = &ea->EaName[ea->EaNameLength + 1]; + + item->flags = ea->Flags; + + InsertTailList(&ealist, &item->list_entry); + } + + if (ea->NextEntryOffset == 0) + break; + + ea = (FILE_FULL_EA_INFORMATION*)(((UINT8*)ea) + ea->NextEntryOffset); + } while (TRUE); + + // handle LXSS values + le = ealist.Flink; + while (le != &ealist) { + LIST_ENTRY* le2 = le->Flink; + ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry); + + if (item->name.Length == sizeof(lxuid) - 1 && RtlCompareMemory(item->name.Buffer, lxuid, item->name.Length) == item->name.Length) { + if (item->value.Length < sizeof(UINT32)) { + ERR("uid value was shorter than expected\n"); + Status = STATUS_INVALID_PARAMETER; + goto end; + } + + RtlCopyMemory(&fcb->inode_item.st_uid, item->value.Buffer, sizeof(UINT32)); + fcb->sd_dirty = TRUE; + fcb->sd_deleted = FALSE; + + RemoveEntryList(&item->list_entry); + ExFreePool(item); + } else if (item->name.Length == sizeof(lxgid) - 1 && RtlCompareMemory(item->name.Buffer, lxgid, item->name.Length) == item->name.Length) { + if (item->value.Length < sizeof(UINT32)) { + ERR("gid value was shorter than expected\n"); + Status = STATUS_INVALID_PARAMETER; + goto end; + } + + RtlCopyMemory(&fcb->inode_item.st_gid, item->value.Buffer, sizeof(UINT32)); + + RemoveEntryList(&item->list_entry); + ExFreePool(item); + } else if (item->name.Length == sizeof(lxmod) - 1 && RtlCompareMemory(item->name.Buffer, lxmod, item->name.Length) == item->name.Length) { + UINT32 allowed = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH | S_ISGID | S_ISVTX | S_ISUID; + UINT32 val; + + if (item->value.Length < sizeof(UINT32)) { + ERR("mode value was shorter than expected\n"); + Status = STATUS_INVALID_PARAMETER; + goto end; + } + + RtlCopyMemory(&val, item->value.Buffer, sizeof(UINT32)); + + if (fcb->type != BTRFS_TYPE_DIRECTORY) + allowed |= __S_IFIFO | __S_IFCHR | __S_IFBLK | __S_IFSOCK; + + fcb->inode_item.st_mode &= ~allowed; + fcb->inode_item.st_mode |= val & allowed; + + if (fcb->type != BTRFS_TYPE_DIRECTORY) { + if ((fcb->inode_item.st_mode & __S_IFCHR) == __S_IFCHR) + fcb->type = BTRFS_TYPE_CHARDEV; + else if ((fcb->inode_item.st_mode & __S_IFBLK) == __S_IFBLK) + fcb->type = BTRFS_TYPE_BLOCKDEV; + else if ((fcb->inode_item.st_mode & __S_IFIFO) == __S_IFIFO) + fcb->type = BTRFS_TYPE_FIFO; + else if ((fcb->inode_item.st_mode & __S_IFSOCK) == __S_IFSOCK) + fcb->type = BTRFS_TYPE_SOCKET; + } + + RemoveEntryList(&item->list_entry); + ExFreePool(item); + } else if (item->name.Length == sizeof(lxdev) - 1 && RtlCompareMemory(item->name.Buffer, lxdev, item->name.Length) == item->name.Length) { + UINT32 major, minor; + + if (item->value.Length < sizeof(UINT64)) { + ERR("dev value was shorter than expected\n"); + Status = STATUS_INVALID_PARAMETER; + goto end; + } + + major = *(UINT32*)item->value.Buffer; + minor = *(UINT32*)&item->value.Buffer[sizeof(UINT32)]; + + fcb->inode_item.st_rdev = (minor & 0xFFFFF) | ((major & 0xFFFFFFFFFFF) << 20); + + RemoveEntryList(&item->list_entry); + ExFreePool(item); + } + + le = le2; + } + + if (fcb->type != BTRFS_TYPE_CHARDEV && fcb->type != BTRFS_TYPE_BLOCKDEV) + fcb->inode_item.st_rdev = 0; + + if (IsListEmpty(&ealist)) + return STATUS_SUCCESS; + + le = ealist.Flink; + while (le != &ealist) { + ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry); + + if (size % 4 > 0) + size += 4 - (size % 4); + + size += (UINT16)offsetof(FILE_FULL_EA_INFORMATION, EaName[0]) + item->name.Length + 1 + item->value.Length; + + le = le->Flink; + } + + buf = ExAllocatePoolWithTag(PagedPool, size, ALLOC_TAG); + if (!buf) { + ERR("out of memory\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto end; + } + + fcb->ea_xattr.Length = fcb->ea_xattr.MaximumLength = size; + fcb->ea_xattr.Buffer = buf; + + fcb->ealen = 4; + ea = NULL; + + le = ealist.Flink; + while (le != &ealist) { + ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry); + + if (ea) { + ea->NextEntryOffset = (ULONG)offsetof(FILE_FULL_EA_INFORMATION, EaName[0]) + ea->EaNameLength + ea->EaValueLength; + + if (ea->NextEntryOffset % 4 > 0) + ea->NextEntryOffset += 4 - (ea->NextEntryOffset % 4); + + ea = (FILE_FULL_EA_INFORMATION*)(((UINT8*)ea) + ea->NextEntryOffset); + } else + ea = (FILE_FULL_EA_INFORMATION*)fcb->ea_xattr.Buffer; + + ea->NextEntryOffset = 0; + ea->Flags = item->flags; + ea->EaNameLength = (UCHAR)item->name.Length; + ea->EaValueLength = item->value.Length; + + RtlCopyMemory(ea->EaName, item->name.Buffer, item->name.Length); + ea->EaName[item->name.Length] = 0; + RtlCopyMemory(&ea->EaName[item->name.Length + 1], item->value.Buffer, item->value.Length); + + fcb->ealen += 5 + item->name.Length + item->value.Length; + + le = le->Flink; + } + + fcb->ea_changed = TRUE; + + Status = STATUS_SUCCESS; + +end: + while (!IsListEmpty(&ealist)) { + ea_item* item = CONTAINING_RECORD(RemoveHeadList(&ealist), ea_item, list_entry); + + ExFreePool(item); + } + + return Status; +} + static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _In_ PUNICODE_STRING fpus, _In_ file_ref* parfileref, _In_ ULONG options, _In_reads_bytes_opt_(ealen) FILE_FULL_EA_INFORMATION* ea, _In_ ULONG ealen, _Out_ file_ref** pfr, _In_ LIST_ENTRY* rollback) { @@ -1843,44 +2075,17 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr fcb->sd_dirty = TRUE;
if (ea && ealen > 0) { - FILE_FULL_EA_INFORMATION* eainfo; - - fcb->ealen = 4; - - // capitalize EA names - eainfo = ea; - do { - STRING s; - - s.Length = s.MaximumLength = eainfo->EaNameLength; - s.Buffer = eainfo->EaName; - - RtlUpperString(&s, &s); - - fcb->ealen += 5 + eainfo->EaNameLength + eainfo->EaValueLength; - - if (eainfo->NextEntryOffset == 0) - break; - - eainfo = (FILE_FULL_EA_INFORMATION*)(((UINT8*)eainfo) + eainfo->NextEntryOffset); - } while (TRUE); - - fcb->ea_xattr.Buffer = ExAllocatePoolWithTag(pool_type, ealen, ALLOC_TAG); - if (!fcb->ea_xattr.Buffer) { - ERR("out of memory\n"); + Status = file_create_parse_ea(fcb, ea); + if (!NT_SUCCESS(Status)) { + ERR("file_create_parse_ea returned %08x\n", Status); free_fcb(Vcb, fcb);
ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE); parfileref->fcb->inode_item.st_size -= utf8len * 2; ExReleaseResourceLite(parfileref->fcb->Header.Resource);
- return STATUS_INSUFFICIENT_RESOURCES; + return Status; } - - fcb->ea_xattr.Length = fcb->ea_xattr.MaximumLength = (UINT16)ealen; - RtlCopyMemory(fcb->ea_xattr.Buffer, ea, fcb->ea_xattr.Length); - - fcb->ea_changed = TRUE; }
fileref = create_fileref(Vcb); @@ -1989,11 +2194,10 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); file_ref *fileref, *newpar, *parfileref; fcb* fcb; - static char xapref[] = "user."; - static WCHAR DOSATTRIB[] = L"DOSATTRIB"; - static WCHAR EA[] = L"EA"; - static WCHAR reparse[] = L"reparse"; - UINT16 xapreflen = (UINT16)strlen(xapref); + static const char xapref[] = "user."; + static const WCHAR DOSATTRIB[] = L"DOSATTRIB"; + static const WCHAR EA[] = L"EA"; + static const WCHAR reparse[] = L"reparse"; LARGE_INTEGER time; BTRFS_TIME now; ULONG utf8len, overhead; @@ -2086,9 +2290,9 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
- if ((stream->Length == wcslen(DOSATTRIB) * sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, DOSATTRIB, stream->Length) == stream->Length) || - (stream->Length == wcslen(EA) * sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, EA, stream->Length) == stream->Length) || - (stream->Length == wcslen(reparse) * sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, reparse, stream->Length) == stream->Length)) { + if ((stream->Length == sizeof(DOSATTRIB) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, DOSATTRIB, stream->Length) == stream->Length) || + (stream->Length == sizeof(EA) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, EA, stream->Length) == stream->Length) || + (stream->Length == sizeof(reparse) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, reparse, stream->Length) == stream->Length)) { return STATUS_OBJECT_NAME_INVALID; }
@@ -2124,7 +2328,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ return Status; }
- fcb->adsxattr.Length = (UINT16)utf8len + xapreflen; + fcb->adsxattr.Length = (UINT16)utf8len + sizeof(xapref) - 1; fcb->adsxattr.MaximumLength = fcb->adsxattr.Length + 1; fcb->adsxattr.Buffer = ExAllocatePoolWithTag(pool_type, fcb->adsxattr.MaximumLength, ALLOC_TAG); if (!fcb->adsxattr.Buffer) { @@ -2133,9 +2337,9 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ return STATUS_INSUFFICIENT_RESOURCES; }
- RtlCopyMemory(fcb->adsxattr.Buffer, xapref, xapreflen); + RtlCopyMemory(fcb->adsxattr.Buffer, xapref, sizeof(xapref) - 1);
- Status = RtlUnicodeToUTF8N(&fcb->adsxattr.Buffer[xapreflen], utf8len, &utf8len, stream->Buffer, stream->Length); + Status = RtlUnicodeToUTF8N(&fcb->adsxattr.Buffer[sizeof(xapref) - 1], utf8len, &utf8len, stream->Buffer, stream->Length); if (!NT_SUCCESS(Status)) { ERR("RtlUnicodeToUTF8N 2 returned %08x\n", Status); free_fcb(Vcb, fcb); @@ -2167,12 +2371,12 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
fcb->adsmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - (sizeof(DIR_ITEM) - 1);
- if (utf8len + xapreflen + overhead > fcb->adsmaxlen) { - WARN("not enough room for new DIR_ITEM (%u + %u > %u)", utf8len + xapreflen, overhead, fcb->adsmaxlen); + if (utf8len + sizeof(xapref) - 1 + overhead > fcb->adsmaxlen) { + WARN("not enough room for new DIR_ITEM (%u + %u > %u)", utf8len + sizeof(xapref) - 1, overhead, fcb->adsmaxlen); free_fcb(Vcb, fcb); return STATUS_DISK_FULL; } else - fcb->adsmaxlen -= overhead + utf8len + xapreflen; + fcb->adsmaxlen -= overhead + utf8len + sizeof(xapref) - 1;
fileref = create_fileref(Vcb); if (!fileref) { @@ -2192,7 +2396,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
RtlZeroMemory(dc, sizeof(dir_child));
- dc->utf8.MaximumLength = dc->utf8.Length = fcb->adsxattr.Length - xapreflen; + dc->utf8.MaximumLength = dc->utf8.Length = fcb->adsxattr.Length + 1 - sizeof(xapref); dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, dc->utf8.MaximumLength, ALLOC_TAG); if (!dc->utf8.Buffer) { ERR("out of memory\n"); @@ -2201,7 +2405,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ return STATUS_INSUFFICIENT_RESOURCES; }
- RtlCopyMemory(dc->utf8.Buffer, &fcb->adsxattr.Buffer[xapreflen], fcb->adsxattr.Length - xapreflen); + RtlCopyMemory(dc->utf8.Buffer, &fcb->adsxattr.Buffer[sizeof(xapref) - 1], fcb->adsxattr.Length + 1 - sizeof(xapref));
dc->name.MaximumLength = dc->name.Length = stream->Length; dc->name.Buffer = ExAllocatePoolWithTag(pool_type, dc->name.MaximumLength, ALLOC_TAG); @@ -2302,10 +2506,14 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R file_ref *fileref, *parfileref = NULL; ULONG i, j; ccb* ccb; - static WCHAR datasuf[] = {':','$','D','A','T','A',0}; + static const WCHAR datasuf[] = {':','$','D','A','T','A',0}; UNICODE_STRING dsus, fpus, stream; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); POOL_TYPE pool_type = IrpSp->Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : PagedPool; +#ifndef __REACTOS__ + ECP_LIST* ecp_list; + ATOMIC_CREATE_ECP_CONTEXT* acec = NULL; +#endif #ifdef DEBUG_FCB_REFCOUNTS LONG oc; #endif @@ -2318,8 +2526,27 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R if (options & FILE_DELETE_ON_CLOSE && IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_READONLY) return STATUS_CANNOT_DELETE;
- dsus.Buffer = datasuf; - dsus.Length = dsus.MaximumLength = (USHORT)wcslen(datasuf) * sizeof(WCHAR); +#ifndef __REACTOS__ + if (NT_SUCCESS(FsRtlGetEcpListFromIrp(Irp, &ecp_list)) && ecp_list) { + void* ctx = NULL; + GUID type; + ULONG ctxsize; + + do { + Status = FsRtlGetNextExtraCreateParameter(ecp_list, ctx, &type, &ctx, &ctxsize); + + if (NT_SUCCESS(Status)) { + if (RtlCompareMemory(&type, &GUID_ECP_ATOMIC_CREATE, sizeof(GUID)) == sizeof(GUID) && ctxsize >= sizeof(ATOMIC_CREATE_ECP_CONTEXT)) { + acec = ctx; + break; + } + } + } while (NT_SUCCESS(Status)); + } +#endif + + dsus.Buffer = (WCHAR*)datasuf; + dsus.Length = dsus.MaximumLength = sizeof(datasuf) - sizeof(WCHAR); fpus.Buffer = NULL;
if (!loaded_related) { @@ -2451,6 +2678,15 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R if (!ccb) { ERR("out of memory\n"); Status = STATUS_INSUFFICIENT_RESOURCES; + fileref->deleted = TRUE; + fileref->fcb->deleted = TRUE; + + if (stream.Length == 0) { + ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE); + parfileref->fcb->inode_item.st_size -= fileref->dc->utf8.Length * 2; + ExReleaseResourceLite(parfileref->fcb->Header.Resource); + } + free_fileref(Vcb, fileref); goto end; } @@ -2484,6 +2720,41 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R
FileObject->SectionObjectPointer = &fileref->fcb->nonpaged->segment_object;
+#ifndef __REACTOS__ + // FIXME - ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT + if (acec && acec->InFlags & ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED) { + if (acec->ReparseBufferLength > sizeof(UINT32) && *(UINT32*)acec->ReparseBuffer == IO_REPARSE_TAG_SYMLINK) { + fileref->fcb->inode_item.st_mode &= ~(__S_IFIFO | __S_IFCHR | __S_IFBLK | __S_IFSOCK); + fileref->fcb->type = BTRFS_TYPE_FILE; + } + + if (fileref->fcb->type == BTRFS_TYPE_SOCKET || fileref->fcb->type == BTRFS_TYPE_FIFO || + fileref->fcb->type == BTRFS_TYPE_CHARDEV || fileref->fcb->type == BTRFS_TYPE_BLOCKDEV) { + // NOP. If called from LXSS, humour it - we hardcode the values elsewhere. + } else { + Status = set_reparse_point2(fileref->fcb, acec->ReparseBuffer, acec->ReparseBufferLength, NULL, NULL, Irp, rollback); + if (!NT_SUCCESS(Status)) { + ERR("set_reparse_point2 returned %08x\n", Status); + fileref->deleted = TRUE; + fileref->fcb->deleted = TRUE; + + if (stream.Length == 0) { + ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE); + parfileref->fcb->inode_item.st_size -= fileref->dc->utf8.Length * 2; + ExReleaseResourceLite(parfileref->fcb->Header.Resource); + } + + free_fileref(Vcb, fileref); + return Status; + } + } + + acec->OutFlags |= ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET; + } +#endif + + fileref->dc->type = fileref->fcb->type; + goto end2;
end: @@ -2738,7 +3009,8 @@ static NTSTATUS get_reparse_block(fcb* fcb, UINT8** data) { }
RtlCopyMemory(*data, fcb->reparse_xattr.Buffer, fcb->reparse_xattr.Length); - } + } else + return STATUS_INVALID_PARAMETER;
return STATUS_SUCCESS; } diff --git a/drivers/filesystems/btrfs/dirctrl.c b/drivers/filesystems/btrfs/dirctrl.c index 64ab60f15a..4d8df559d0 100644 --- a/drivers/filesystems/btrfs/dirctrl.c +++ b/drivers/filesystems/btrfs/dirctrl.c @@ -31,16 +31,46 @@ typedef struct { dir_child* dc; } dir_entry;
+ULONG get_reparse_tag_fcb(fcb* fcb) { + ULONG tag; + + if (fcb->type == BTRFS_TYPE_SYMLINK) + return IO_REPARSE_TAG_SYMLINK; + else if (fcb->type == BTRFS_TYPE_DIRECTORY) { + if (!fcb->reparse_xattr.Buffer || fcb->reparse_xattr.Length < sizeof(ULONG)) + return 0; + + RtlCopyMemory(&tag, fcb->reparse_xattr.Buffer, sizeof(ULONG)); + } else { + NTSTATUS Status; + ULONG br; + + Status = read_file(fcb, (UINT8*)&tag, 0, sizeof(ULONG), &br, NULL); + if (!NT_SUCCESS(Status)) { + ERR("read_file returned %08x\n", Status); + return 0; + } + } + + return tag; +} + ULONG get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type, ULONG atts, BOOL lxss, PIRP Irp) { fcb* fcb; - ULONG tag = 0, br; + ULONG tag = 0; NTSTATUS Status;
- if (type == BTRFS_TYPE_SYMLINK) { - if (lxss) - return IO_REPARSE_TAG_LXSS_SYMLINK; - else - return IO_REPARSE_TAG_SYMLINK; + if (type == BTRFS_TYPE_SYMLINK) + return IO_REPARSE_TAG_SYMLINK; + else if (lxss) { + if (type == BTRFS_TYPE_SOCKET) + return IO_REPARSE_TAG_LXSS_SOCKET; + else if (type == BTRFS_TYPE_FIFO) + return IO_REPARSE_TAG_LXSS_FIFO; + else if (type == BTRFS_TYPE_CHARDEV) + return IO_REPARSE_TAG_LXSS_CHARDEV; + else if (type == BTRFS_TYPE_BLOCKDEV) + return IO_REPARSE_TAG_LXSS_BLOCKDEV; }
if (type != BTRFS_TYPE_FILE && type != BTRFS_TYPE_DIRECTORY) @@ -57,23 +87,8 @@ ULONG get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 t
ExAcquireResourceSharedLite(fcb->Header.Resource, TRUE);
- if (type == BTRFS_TYPE_DIRECTORY) { - if (!fcb->reparse_xattr.Buffer || fcb->reparse_xattr.Length < sizeof(ULONG)) - goto end; - - RtlCopyMemory(&tag, fcb->reparse_xattr.Buffer, sizeof(ULONG)); - } else { - Status = read_file(fcb, (UINT8*)&tag, 0, sizeof(ULONG), &br, NULL); - if (!NT_SUCCESS(Status)) { - ERR("read_file returned %08x\n", Status); - goto end; - } - - if (br < sizeof(ULONG)) - goto end; - } + tag = get_reparse_tag_fcb(fcb);
-end: ExReleaseResourceLite(fcb->Header.Resource);
free_fcb(Vcb, fcb); @@ -675,11 +690,7 @@ static NTSTATUS query_directory(PIRP Irp) { if (IrpSp->Parameters.QueryDirectory.FileName && IrpSp->Parameters.QueryDirectory.FileName->Length > 1) { TRACE("QD filename: %.*S\n", IrpSp->Parameters.QueryDirectory.FileName->Length / sizeof(WCHAR), IrpSp->Parameters.QueryDirectory.FileName->Buffer);
-#ifndef __REACTOS__ - if (IrpSp->Parameters.QueryDirectory.FileName->Buffer[0] != '*') { -#else if (IrpSp->Parameters.QueryDirectory.FileName->Length > sizeof(WCHAR) || IrpSp->Parameters.QueryDirectory.FileName->Buffer[0] != L'*') { -#endif specific_file = TRUE;
if (FsRtlDoesNameContainWildCards(IrpSp->Parameters.QueryDirectory.FileName)) { diff --git a/drivers/filesystems/btrfs/fastio.c b/drivers/filesystems/btrfs/fastio.c index 9f4c504a12..9ee282d04c 100644 --- a/drivers/filesystems/btrfs/fastio.c +++ b/drivers/filesystems/btrfs/fastio.c @@ -296,11 +296,21 @@ static NTSTATUS fast_io_acquire_for_mod_write(PFILE_OBJECT FileObject, PLARGE_IN if (!fcb) return STATUS_INVALID_PARAMETER;
- *ResourceToRelease = fcb->Header.PagingIoResource; + // Make sure we don't get interrupted by the flush thread, which can cause a deadlock
- if (!ExAcquireResourceSharedLite(*ResourceToRelease, FALSE)) + if (!ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, FALSE)) return STATUS_CANT_WAIT;
+ // Ideally this would be PagingIoResource, but that doesn't play well with copy-on-write, + // as we can't guarantee that we won't need to do any reallocations. + + *ResourceToRelease = fcb->Header.Resource; + + if (!ExAcquireResourceExclusiveLite(*ResourceToRelease, FALSE)) { + ExReleaseResourceLite(&fcb->Vcb->tree_lock); + return STATUS_CANT_WAIT; + } + return STATUS_SUCCESS; }
@@ -310,11 +320,16 @@ static NTSTATUS NTAPI fast_io_release_for_mod_write(PFILE_OBJECT FileObject, str #else static NTSTATUS fast_io_release_for_mod_write(PFILE_OBJECT FileObject, struct _ERESOURCE *ResourceToRelease, PDEVICE_OBJECT DeviceObject) { #endif - UNUSED(FileObject); + fcb* fcb; + UNUSED(DeviceObject);
+ fcb = FileObject->FsContext; + ExReleaseResourceLite(ResourceToRelease);
+ ExReleaseResourceLite(&fcb->Vcb->tree_lock); + return STATUS_SUCCESS; }
diff --git a/drivers/filesystems/btrfs/fileinfo.c b/drivers/filesystems/btrfs/fileinfo.c index 1d03a669f4..1c342b0f55 100644 --- a/drivers/filesystems/btrfs/fileinfo.c +++ b/drivers/filesystems/btrfs/fileinfo.c @@ -21,6 +21,34 @@ // not currently in mingw - introduced with Windows 10 #ifndef FileIdInformation #define FileIdInformation (enum _FILE_INFORMATION_CLASS)59 +#define FileStatLxInformation (enum _FILE_INFORMATION_CLASS)70 + +typedef struct _FILE_STAT_LX_INFORMATION { + LARGE_INTEGER FileId; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; + ULONG ReparseTag; + ULONG NumberOfLinks; + ACCESS_MASK EffectiveAccess; + ULONG LxFlags; + ULONG LxUid; + ULONG LxGid; + ULONG LxMode; + ULONG LxDeviceIdMajor; + ULONG LxDeviceIdMinor; +} FILE_STAT_LX_INFORMATION, *PFILE_STAT_LX_INFORMATION; + +#define LX_FILE_METADATA_HAS_UID 0x01 +#define LX_FILE_METADATA_HAS_GID 0x02 +#define LX_FILE_METADATA_HAS_MODE 0x04 +#define LX_FILE_METADATA_HAS_DEVICE_ID 0x08 +#define LX_FILE_CASE_SENSITIVE_DIR 0x10 + #endif #endif
@@ -70,6 +98,20 @@ static NTSTATUS set_basic_information(device_extension* Vcb, PIRP Irp, PFILE_OBJ goto end; }
+ // times of -2 are some sort of undocumented behaviour to do with LXSS + + if (fbi->CreationTime.QuadPart == -2) + fbi->CreationTime.QuadPart = 0; + + if (fbi->LastAccessTime.QuadPart == -2) + fbi->LastAccessTime.QuadPart = 0; + + if (fbi->LastWriteTime.QuadPart == -2) + fbi->LastWriteTime.QuadPart = 0; + + if (fbi->ChangeTime.QuadPart == -2) + fbi->ChangeTime.QuadPart = 0; + if (fbi->CreationTime.QuadPart == -1) ccb->user_set_creation_time = TRUE; else if (fbi->CreationTime.QuadPart != 0) { @@ -2946,8 +2988,8 @@ static NTSTATUS fill_in_file_name_information(FILE_NAME_INFORMATION* fni, fcb* f ULONG reqlen; UNICODE_STRING fn; NTSTATUS Status; - static WCHAR datasuf[] = {':','$','D','A','T','A',0}; - UINT16 datasuflen = (UINT16)wcslen(datasuf) * sizeof(WCHAR); + static const WCHAR datasuf[] = {':','$','D','A','T','A',0}; + UINT16 datasuflen = sizeof(datasuf) - sizeof(WCHAR);
if (!fileref) { ERR("called without fileref\n"); @@ -2999,7 +3041,7 @@ static NTSTATUS fill_in_file_name_information(FILE_NAME_INFORMATION* fni, fcb* f return Status; }
-static NTSTATUS fill_in_file_attribute_information(FILE_ATTRIBUTE_TAG_INFORMATION* ati, fcb* fcb, ccb* ccb, PIRP Irp, LONG* length) { +static NTSTATUS fill_in_file_attribute_information(FILE_ATTRIBUTE_TAG_INFORMATION* ati, fcb* fcb, ccb* ccb, LONG* length) { *length -= sizeof(FILE_ATTRIBUTE_TAG_INFORMATION);
if (fcb->ads) { @@ -3015,7 +3057,7 @@ static NTSTATUS fill_in_file_attribute_information(FILE_ATTRIBUTE_TAG_INFORMATIO if (!(ati->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) ati->ReparseTag = 0; else - ati->ReparseTag = get_reparse_tag(fcb->Vcb, fcb->subvol, fcb->inode, fcb->type, fcb->atts, ccb->lxss, Irp); + ati->ReparseTag = get_reparse_tag_fcb(fcb);
return STATUS_SUCCESS; } @@ -3026,7 +3068,7 @@ static NTSTATUS fill_in_file_stream_information(FILE_STREAM_INFORMATION* fsi, fi FILE_STREAM_INFORMATION *entry, *lastentry; NTSTATUS Status;
- static WCHAR datasuf[] = L":$DATA"; + static const WCHAR datasuf[] = L":$DATA"; UNICODE_STRING suf;
if (!fileref) { @@ -3034,8 +3076,8 @@ static NTSTATUS fill_in_file_stream_information(FILE_STREAM_INFORMATION* fsi, fi return STATUS_INVALID_PARAMETER; }
- suf.Buffer = datasuf; - suf.Length = suf.MaximumLength = (UINT16)wcslen(datasuf) * sizeof(WCHAR); + suf.Buffer = (WCHAR*)datasuf; + suf.Length = suf.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
if (fileref->fcb->type != BTRFS_TYPE_DIRECTORY) reqsize = sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR) + suf.Length + sizeof(WCHAR); @@ -3606,6 +3648,80 @@ static NTSTATUS fill_in_file_id_information(FILE_ID_INFORMATION* fii, fcb* fcb, } #endif
+#ifndef __REACTOS__ +static NTSTATUS fill_in_file_stat_lx_information(FILE_STAT_LX_INFORMATION* fsli, fcb* fcb, ccb* ccb, LONG* length) { + INODE_ITEM* ii; + + fsli->FileId.LowPart = (UINT32)fcb->inode; + fsli->FileId.HighPart = (UINT32)fcb->subvol->id; + + if (fcb->ads) + ii = &ccb->fileref->parent->fcb->inode_item; + else + ii = &fcb->inode_item; + + if (fcb == fcb->Vcb->dummy_fcb) { + LARGE_INTEGER time; + + KeQuerySystemTime(&time); + fsli->CreationTime = fsli->LastAccessTime = fsli->LastWriteTime = fsli->ChangeTime = time; + } else { + fsli->CreationTime.QuadPart = unix_time_to_win(&ii->otime); + fsli->LastAccessTime.QuadPart = unix_time_to_win(&ii->st_atime); + fsli->LastWriteTime.QuadPart = unix_time_to_win(&ii->st_mtime); + fsli->ChangeTime.QuadPart = unix_time_to_win(&ii->st_ctime); + } + + if (fcb->ads) { + fsli->AllocationSize.QuadPart = fsli->EndOfFile.QuadPart = fcb->adsdata.Length; + fsli->FileAttributes = ccb->fileref->parent->fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : ccb->fileref->parent->fcb->atts; + } else { + fsli->AllocationSize.QuadPart = fcb_alloc_size(fcb); + fsli->EndOfFile.QuadPart = S_ISDIR(fcb->inode_item.st_mode) ? 0 : fcb->inode_item.st_size; + fsli->FileAttributes = fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : fcb->atts; + } + + if (fcb->type == BTRFS_TYPE_SOCKET) + fsli->ReparseTag = IO_REPARSE_TAG_LXSS_SOCKET; + else if (fcb->type == BTRFS_TYPE_FIFO) + fsli->ReparseTag = IO_REPARSE_TAG_LXSS_FIFO; + else if (fcb->type == BTRFS_TYPE_CHARDEV) + fsli->ReparseTag = IO_REPARSE_TAG_LXSS_CHARDEV; + else if (fcb->type == BTRFS_TYPE_BLOCKDEV) + fsli->ReparseTag = IO_REPARSE_TAG_LXSS_BLOCKDEV; + else if (!(fsli->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) + fsli->ReparseTag = 0; + else + fsli->ReparseTag = get_reparse_tag_fcb(fcb); + + if (fcb->type == BTRFS_TYPE_SOCKET || fcb->type == BTRFS_TYPE_FIFO || fcb->type == BTRFS_TYPE_CHARDEV || fcb->type == BTRFS_TYPE_BLOCKDEV) + fsli->FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT; + + if (fcb->ads) + fsli->NumberOfLinks = ccb->fileref->parent->fcb->inode_item.st_nlink; + else + fsli->NumberOfLinks = fcb->inode_item.st_nlink; + + fsli->EffectiveAccess = ccb->access; + fsli->LxFlags = LX_FILE_METADATA_HAS_UID | LX_FILE_METADATA_HAS_GID | LX_FILE_METADATA_HAS_MODE | LX_FILE_METADATA_HAS_DEVICE_ID; // FIXME - LX_FILE_CASE_SENSITIVE_DIR + fsli->LxUid = ii->st_uid; + fsli->LxGid = ii->st_gid; + fsli->LxMode = ii->st_mode; + + if (ii->st_mode & __S_IFBLK || ii->st_mode & __S_IFCHR) { + fsli->LxDeviceIdMajor = (ii->st_rdev & 0xFFFFFFFFFFF00000) >> 20; + fsli->LxDeviceIdMinor = (ii->st_rdev & 0xFFFFF); + } else { + fsli->LxDeviceIdMajor = 0; + fsli->LxDeviceIdMinor = 0; + } + + *length -= sizeof(FILE_STAT_LX_INFORMATION); + + return STATUS_SUCCESS; +} +#endif + static NTSTATUS query_info(device_extension* Vcb, PFILE_OBJECT FileObject, PIRP Irp) { PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); LONG length = IrpSp->Parameters.QueryFile.Length; @@ -3694,7 +3810,7 @@ static NTSTATUS query_info(device_extension* Vcb, PFILE_OBJECT FileObject, PIRP }
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE); - Status = fill_in_file_attribute_information(ati, fcb, ccb, Irp, &length); + Status = fill_in_file_attribute_information(ati, fcb, ccb, &length); ExReleaseResourceLite(&Vcb->tree_lock);
break; @@ -3893,6 +4009,23 @@ static NTSTATUS query_info(device_extension* Vcb, PFILE_OBJECT FileObject, PIRP
break; } + + case FileStatLxInformation: + { + FILE_STAT_LX_INFORMATION* fsli = Irp->AssociatedIrp.SystemBuffer; + + if (IrpSp->Parameters.QueryFile.Length < sizeof(FILE_STAT_LX_INFORMATION)) { + WARN("overflow\n"); + Status = STATUS_BUFFER_OVERFLOW; + goto exit; + } + + TRACE("FileStatLxInformation\n"); + + Status = fill_in_file_stat_lx_information(fsli, fcb, ccb, &length); + + break; + } #ifndef _MSC_VER #pragma GCC diagnostic pop #endif @@ -4194,13 +4327,6 @@ end: return Status; }
-typedef struct { - ANSI_STRING name; - ANSI_STRING value; - UCHAR flags; - LIST_ENTRY list_entry; -} ea_item; - _Dispatch_type_(IRP_MJ_SET_EA) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI drv_set_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { @@ -4386,6 +4512,64 @@ NTSTATUS NTAPI drv_set_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { le = le2; }
+ // handle LXSS values + le = ealist.Flink; + while (le != &ealist) { + LIST_ENTRY* le2 = le->Flink; + + item = CONTAINING_RECORD(le, ea_item, list_entry); + + if (item->name.Length == sizeof(lxuid) - 1 && RtlCompareMemory(item->name.Buffer, lxuid, item->name.Length) == item->name.Length) { + if (item->value.Length < sizeof(UINT32)) { + ERR("uid value was shorter than expected\n"); + Status = STATUS_INVALID_PARAMETER; + goto end2; + } + + if (Irp->RequestorMode == KernelMode) { + RtlCopyMemory(&fcb->inode_item.st_uid, item->value.Buffer, sizeof(UINT32)); + fcb->sd_dirty = TRUE; + fcb->sd_deleted = FALSE; + } + + RemoveEntryList(&item->list_entry); + ExFreePool(item); + } else if (item->name.Length == sizeof(lxgid) - 1 && RtlCompareMemory(item->name.Buffer, lxgid, item->name.Length) == item->name.Length) { + if (item->value.Length < sizeof(UINT32)) { + ERR("gid value was shorter than expected\n"); + Status = STATUS_INVALID_PARAMETER; + goto end2; + } + + if (Irp->RequestorMode == KernelMode) + RtlCopyMemory(&fcb->inode_item.st_gid, item->value.Buffer, sizeof(UINT32)); + + RemoveEntryList(&item->list_entry); + ExFreePool(item); + } else if (item->name.Length == sizeof(lxmod) - 1 && RtlCompareMemory(item->name.Buffer, lxmod, item->name.Length) == item->name.Length) { + if (item->value.Length < sizeof(UINT32)) { + ERR("mode value was shorter than expected\n"); + Status = STATUS_INVALID_PARAMETER; + goto end2; + } + + if (Irp->RequestorMode == KernelMode) { + UINT32 allowed = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH | S_ISGID | S_ISVTX | S_ISUID; + UINT32 val; + + RtlCopyMemory(&val, item->value.Buffer, sizeof(UINT32)); + + fcb->inode_item.st_mode &= ~allowed; + fcb->inode_item.st_mode |= val & allowed; + } + + RemoveEntryList(&item->list_entry); + ExFreePool(item); + } + + le = le2; + } + if (IsListEmpty(&ealist)) { fcb->ealen = 0;
diff --git a/drivers/filesystems/btrfs/flushthread.c b/drivers/filesystems/btrfs/flushthread.c index 9e95f82834..6353abb583 100644 --- a/drivers/filesystems/btrfs/flushthread.c +++ b/drivers/filesystems/btrfs/flushthread.c @@ -316,14 +316,14 @@ static void clean_space_cache(device_extension* Vcb) { c = CONTAINING_RECORD(le, chunk, list_entry);
if (c->space_changed) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
if (c->space_changed) clean_space_cache_chunk(Vcb, c);
c->space_changed = FALSE;
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); }
le = le->Flink; @@ -599,11 +599,11 @@ static BOOL insert_tree_extent_skinny(device_extension* Vcb, UINT8 level, UINT64 return FALSE; }
- ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
space_list_subtract(c, FALSE, address, Vcb->superblock.node_size, rollback);
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb);
add_parents_to_cache(insert_tp.tree);
@@ -731,11 +731,11 @@ static BOOL insert_tree_extent(device_extension* Vcb, UINT8 level, UINT64 root_i return FALSE; }
- ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
space_list_subtract(c, FALSE, address, Vcb->superblock.node_size, rollback);
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb);
add_parents_to_cache(insert_tp.tree);
@@ -773,11 +773,11 @@ NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, PIRP Irp, LIST_ENT c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly && !c->reloc) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
if (c != origchunk && c->chunk_item->type == flags && (c->chunk_item->size - c->used) >= Vcb->superblock.node_size) { if (insert_tree_extent(Vcb, t->header.level, t->root->id, c, &addr, Irp, rollback)) { - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); ExReleaseResourceLite(&Vcb->chunk_lock); t->new_address = addr; t->has_new_address = TRUE; @@ -785,7 +785,7 @@ NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, PIRP Irp, LIST_ENT } }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); }
le = le->Flink; @@ -801,11 +801,11 @@ NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, PIRP Irp, LIST_ENT return Status; }
- ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
if ((c->chunk_item->size - c->used) >= Vcb->superblock.node_size) { if (insert_tree_extent(Vcb, t->header.level, t->root->id, c, &addr, Irp, rollback)) { - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); ExReleaseResourceLite(&Vcb->chunk_lock); t->new_address = addr; t->has_new_address = TRUE; @@ -813,7 +813,7 @@ NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, PIRP Irp, LIST_ENT } }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb);
ExReleaseResourceLite(&Vcb->chunk_lock);
@@ -849,14 +849,14 @@ static NTSTATUS reduce_tree_extent(device_extension* Vcb, UINT64 address, tree* chunk* c = get_chunk_from_address(Vcb, address);
if (c) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
if (!c->cache_loaded) { Status = load_cache_chunk(Vcb, c, NULL);
if (!NT_SUCCESS(Status)) { ERR("load_cache_chunk returned %08x\n", Status); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); return Status; } } @@ -865,7 +865,7 @@ static NTSTATUS reduce_tree_extent(device_extension* Vcb, UINT64 address, tree*
space_list_add(c, address, Vcb->superblock.node_size, rollback);
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); } else ERR("could not find chunk for address %llx\n", address); } @@ -1351,19 +1351,19 @@ static NTSTATUS allocate_tree_extents(device_extension* Vcb, PIRP Irp, LIST_ENTR
if (c) { if (!c->cache_loaded) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
if (!c->cache_loaded) { Status = load_cache_chunk(Vcb, c, NULL);
if (!NT_SUCCESS(Status)) { ERR("load_cache_chunk returned %08x\n", Status); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); return Status; } }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); } } } @@ -2644,14 +2644,14 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp, LIST_ENTRY* while (le != &Vcb->chunks) { c = CONTAINING_RECORD(le, chunk, list_entry);
- ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
if (!c->cache_loaded && (!IsListEmpty(&c->changed_extents) || c->used != c->oldused)) { Status = load_cache_chunk(Vcb, c, NULL);
if (!NT_SUCCESS(Status)) { ERR("load_cache_chunk returned %08x\n", Status); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); goto end; } } @@ -2664,7 +2664,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp, LIST_ENTRY* Status = flush_changed_extent(Vcb, c, ce, Irp, rollback); if (!NT_SUCCESS(Status)) { ERR("flush_changed_extent returned %08x\n", Status); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); goto end; }
@@ -2677,7 +2677,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp, LIST_ENTRY* Status = create_chunk(Vcb, c, Irp); if (!NT_SUCCESS(Status)) { ERR("create_chunk returned %08x\n", Status); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); goto end; } } @@ -2691,7 +2691,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp, LIST_ENTRY* Status = flush_fcb(c->old_cache, FALSE, &batchlist, Irp); if (!NT_SUCCESS(Status)) { ERR("flush_fcb returned %08x\n", Status); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); clear_batch_list(Vcb, &batchlist); goto end; } @@ -2699,7 +2699,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp, LIST_ENTRY* Status = commit_batch_list(Vcb, &batchlist, Irp); if (!NT_SUCCESS(Status)) { ERR("commit_batch_list returned %08x\n", Status); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); goto end; } } @@ -2716,21 +2716,21 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp, LIST_ENTRY* Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp); if (!NT_SUCCESS(Status)) { ERR("error - find_item returned %08x\n", Status); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); goto end; }
if (keycmp(searchkey, tp.item->key)) { ERR("could not find (%llx,%x,%llx) in extent_root\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset); Status = STATUS_INTERNAL_ERROR; - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); goto end; }
if (tp.item->size < sizeof(BLOCK_GROUP_ITEM)) { ERR("(%llx,%x,%llx) was %u bytes, expected %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(BLOCK_GROUP_ITEM)); Status = STATUS_INTERNAL_ERROR; - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); goto end; }
@@ -2738,7 +2738,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp, LIST_ENTRY* if (!bgi) { ERR("out of memory\n"); Status = STATUS_INSUFFICIENT_RESOURCES; - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); goto end; }
@@ -2751,7 +2751,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp, LIST_ENTRY* if (!NT_SUCCESS(Status)) { ERR("delete_tree_item returned %08x\n", Status); ExFreePool(bgi); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); goto end; }
@@ -2759,7 +2759,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp, LIST_ENTRY* if (!NT_SUCCESS(Status)) { ERR("insert_tree_item returned %08x\n", Status); ExFreePool(bgi); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); goto end; }
@@ -2772,7 +2772,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp, LIST_ENTRY* c->oldused = c->used; }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb);
le = le->Flink; } @@ -4414,14 +4414,14 @@ cont: if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) add_checksum_entry(fcb->Vcb, er->address, (ULONG)(er->skip_start / fcb->Vcb->superblock.sector_size), NULL, NULL);
- ExAcquireResourceExclusiveLite(&er->chunk->lock, TRUE); + acquire_chunk_lock(er->chunk, fcb->Vcb);
if (!er->chunk->cache_loaded) { NTSTATUS Status = load_cache_chunk(fcb->Vcb, er->chunk, NULL);
if (!NT_SUCCESS(Status)) { ERR("load_cache_chunk returned %08x\n", Status); - ExReleaseResourceLite(&er->chunk->lock); + release_chunk_lock(er->chunk, fcb->Vcb); goto end; } } @@ -4430,7 +4430,7 @@ cont:
space_list_add(er->chunk, er->address, er->skip_start, NULL);
- ExReleaseResourceLite(&er->chunk->lock); + release_chunk_lock(er->chunk, fcb->Vcb);
er->address += er->skip_start; er->length -= er->skip_start; @@ -4468,14 +4468,14 @@ cont: if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) add_checksum_entry(fcb->Vcb, er->address + er->length - er->skip_end, (ULONG)(er->skip_end / fcb->Vcb->superblock.sector_size), NULL, NULL);
- ExAcquireResourceExclusiveLite(&er->chunk->lock, TRUE); + acquire_chunk_lock(er->chunk, fcb->Vcb);
if (!er->chunk->cache_loaded) { NTSTATUS Status = load_cache_chunk(fcb->Vcb, er->chunk, NULL);
if (!NT_SUCCESS(Status)) { ERR("load_cache_chunk returned %08x\n", Status); - ExReleaseResourceLite(&er->chunk->lock); + release_chunk_lock(er->chunk, fcb->Vcb); goto end; } } @@ -4484,7 +4484,7 @@ cont:
space_list_add(er->chunk, er->address + er->length - er->skip_end, er->skip_end, NULL);
- ExReleaseResourceLite(&er->chunk->lock); + release_chunk_lock(er->chunk, fcb->Vcb);
er->length -= er->skip_end; } @@ -4924,14 +4924,14 @@ NTSTATUS flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* batchlist, PIRP Irp) {
if (fcb->sd_dirty) { if (!fcb->sd_deleted) { - Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_NTACL, (UINT16)strlen(EA_NTACL), + Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_NTACL, sizeof(EA_NTACL) - 1, EA_NTACL_HASH, (UINT8*)fcb->sd, (UINT16)RtlLengthSecurityDescriptor(fcb->sd)); if (!NT_SUCCESS(Status)) { ERR("set_xattr returned %08x\n", Status); goto end; } } else { - Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_NTACL, (UINT16)strlen(EA_NTACL), EA_NTACL_HASH); + Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_NTACL, sizeof(EA_NTACL) - 1, EA_NTACL_HASH); if (!NT_SUCCESS(Status)) { ERR("delete_xattr returned %08x\n", Status); goto end; @@ -4966,14 +4966,14 @@ NTSTATUS flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* batchlist, PIRP Irp) { val2--; *val2 = '0';
- Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_DOSATTRIB, (UINT16)strlen(EA_DOSATTRIB), + Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_DOSATTRIB, sizeof(EA_DOSATTRIB) - 1, EA_DOSATTRIB_HASH, val2, (UINT16)(val + sizeof(val) - val2)); if (!NT_SUCCESS(Status)) { ERR("set_xattr returned %08x\n", Status); goto end; } } else { - Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_DOSATTRIB, (UINT16)strlen(EA_DOSATTRIB), EA_DOSATTRIB_HASH); + Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_DOSATTRIB, sizeof(EA_DOSATTRIB) - 1, EA_DOSATTRIB_HASH); if (!NT_SUCCESS(Status)) { ERR("delete_xattr returned %08x\n", Status); goto end; @@ -4986,14 +4986,14 @@ NTSTATUS flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* batchlist, PIRP Irp) {
if (fcb->reparse_xattr_changed) { if (fcb->reparse_xattr.Buffer && fcb->reparse_xattr.Length > 0) { - Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_REPARSE, (UINT16)strlen(EA_REPARSE), + Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_REPARSE, sizeof(EA_REPARSE) - 1, EA_REPARSE_HASH, (UINT8*)fcb->reparse_xattr.Buffer, (UINT16)fcb->reparse_xattr.Length); if (!NT_SUCCESS(Status)) { ERR("set_xattr returned %08x\n", Status); goto end; } } else { - Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_REPARSE, (UINT16)strlen(EA_REPARSE), EA_REPARSE_HASH); + Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_REPARSE, sizeof(EA_REPARSE) - 1, EA_REPARSE_HASH); if (!NT_SUCCESS(Status)) { ERR("delete_xattr returned %08x\n", Status); goto end; @@ -5005,14 +5005,14 @@ NTSTATUS flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* batchlist, PIRP Irp) {
if (fcb->ea_changed) { if (fcb->ea_xattr.Buffer && fcb->ea_xattr.Length > 0) { - Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_EA, (UINT16)strlen(EA_EA), + Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_EA, sizeof(EA_EA) - 1, EA_EA_HASH, (UINT8*)fcb->ea_xattr.Buffer, (UINT16)fcb->ea_xattr.Length); if (!NT_SUCCESS(Status)) { ERR("set_xattr returned %08x\n", Status); goto end; } } else { - Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_EA, (UINT16)strlen(EA_EA), EA_EA_HASH); + Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_EA, sizeof(EA_EA) - 1, EA_EA_HASH); if (!NT_SUCCESS(Status)) { ERR("delete_xattr returned %08x\n", Status); goto end; @@ -5024,25 +5024,34 @@ NTSTATUS flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* batchlist, PIRP Irp) {
if (fcb->prop_compression_changed) { if (fcb->prop_compression == PropCompression_None) { - Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_PROP_COMPRESSION, (UINT16)strlen(EA_PROP_COMPRESSION), EA_PROP_COMPRESSION_HASH); + Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_PROP_COMPRESSION, sizeof(EA_PROP_COMPRESSION) - 1, EA_PROP_COMPRESSION_HASH); if (!NT_SUCCESS(Status)) { ERR("delete_xattr returned %08x\n", Status); goto end; } } else if (fcb->prop_compression == PropCompression_Zlib) { - const char zlib[] = "zlib"; + static const char zlib[] = "zlib";
- Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_PROP_COMPRESSION, (UINT16)strlen(EA_PROP_COMPRESSION), - EA_PROP_COMPRESSION_HASH, (UINT8*)zlib, (UINT16)strlen(zlib)); + Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_PROP_COMPRESSION, sizeof(EA_PROP_COMPRESSION) - 1, + EA_PROP_COMPRESSION_HASH, (UINT8*)zlib, sizeof(zlib) - 1); if (!NT_SUCCESS(Status)) { ERR("set_xattr returned %08x\n", Status); goto end; } } else if (fcb->prop_compression == PropCompression_LZO) { - const char lzo[] = "lzo"; + static const char lzo[] = "lzo";
- Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_PROP_COMPRESSION, (UINT16)strlen(EA_PROP_COMPRESSION), - EA_PROP_COMPRESSION_HASH, (UINT8*)lzo, (UINT16)strlen(lzo)); + Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_PROP_COMPRESSION, sizeof(EA_PROP_COMPRESSION) - 1, + EA_PROP_COMPRESSION_HASH, (UINT8*)lzo, sizeof(lzo) - 1); + if (!NT_SUCCESS(Status)) { + ERR("set_xattr returned %08x\n", Status); + goto end; + } + } else if (fcb->prop_compression == PropCompression_ZSTD) { + static const char zstd[] = "zstd"; + + Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_PROP_COMPRESSION, sizeof(EA_PROP_COMPRESSION) - 1, + EA_PROP_COMPRESSION_HASH, (UINT8*)zstd, sizeof(zstd) - 1); if (!NT_SUCCESS(Status)) { ERR("set_xattr returned %08x\n", Status); goto end; @@ -5282,29 +5291,26 @@ static NTSTATUS drop_chunk(device_extension* Vcb, chunk* c, LIST_ENTRY* batchlis return Status; }
- if (keycmp(tp.item->key, searchkey)) { - ERR("error - could not find DEV_ITEM for device %llx\n", searchkey.offset); - return STATUS_INTERNAL_ERROR; - } - - Status = delete_tree_item(Vcb, &tp); - if (!NT_SUCCESS(Status)) { - ERR("delete_tree_item returned %08x\n", Status); - return Status; - } + if (!keycmp(tp.item->key, searchkey)) { + Status = delete_tree_item(Vcb, &tp); + if (!NT_SUCCESS(Status)) { + ERR("delete_tree_item returned %08x\n", Status); + return Status; + }
- di = ExAllocatePoolWithTag(PagedPool, sizeof(DEV_ITEM), ALLOC_TAG); - if (!di) { - ERR("out of memory\n"); - return STATUS_INSUFFICIENT_RESOURCES; - } + di = ExAllocatePoolWithTag(PagedPool, sizeof(DEV_ITEM), ALLOC_TAG); + if (!di) { + ERR("out of memory\n"); + return STATUS_INSUFFICIENT_RESOURCES; + }
- RtlCopyMemory(di, &c->devices[i]->devitem, sizeof(DEV_ITEM)); + RtlCopyMemory(di, &c->devices[i]->devitem, sizeof(DEV_ITEM));
- Status = insert_tree_item(Vcb, Vcb->chunk_root, 1, TYPE_DEV_ITEM, c->devices[i]->devitem.dev_id, di, sizeof(DEV_ITEM), NULL, Irp); - if (!NT_SUCCESS(Status)) { - ERR("insert_tree_item returned %08x\n", Status); - return Status; + Status = insert_tree_item(Vcb, Vcb->chunk_root, 1, TYPE_DEV_ITEM, c->devices[i]->devitem.dev_id, di, sizeof(DEV_ITEM), NULL, Irp); + if (!NT_SUCCESS(Status)) { + ERR("insert_tree_item returned %08x\n", Status); + return Status; + } }
for (j = i + 1; j < c->chunk_item->num_stripes; j++) { @@ -5404,6 +5410,8 @@ static NTSTATUS drop_chunk(device_extension* Vcb, chunk* c, LIST_ENTRY* batchlis ExFreePool(s); }
+ release_chunk_lock(c, Vcb); + ExDeleteResourceLite(&c->partial_stripes_lock); ExDeleteResourceLite(&c->range_locks_lock); ExDeleteResourceLite(&c->lock); @@ -5718,7 +5726,7 @@ static NTSTATUS update_chunks(device_extension* Vcb, LIST_ENTRY* batchlist, PIRP le2 = le->Flink;
if (c->changed) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
// flush partial stripes if (!Vcb->readonly && (c->chunk_item->type & BLOCK_FLAG_RAID5 || c->chunk_item->type & BLOCK_FLAG_RAID6)) { @@ -5737,7 +5745,7 @@ static NTSTATUS update_chunks(device_extension* Vcb, LIST_ENTRY* batchlist, PIRP if (!NT_SUCCESS(Status)) { ERR("flush_partial_stripe returned %08x\n", Status); ExReleaseResourceLite(&c->partial_stripes_lock); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); ExReleaseResourceLite(&Vcb->chunk_lock); return Status; } @@ -5747,12 +5755,14 @@ static NTSTATUS update_chunks(device_extension* Vcb, LIST_ENTRY* batchlist, PIRP }
if (c->list_entry_balance.Flink) { - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); le = le2; continue; }
if (c->space_changed || c->created) { + BOOL created = c->created; + used_minus_cache = c->used;
// subtract self-hosted cache @@ -5781,23 +5791,28 @@ static NTSTATUS update_chunks(device_extension* Vcb, LIST_ENTRY* batchlist, PIRP Status = drop_chunk(Vcb, c, batchlist, Irp, rollback); if (!NT_SUCCESS(Status)) { ERR("drop_chunk returned %08x\n", Status); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); ExReleaseResourceLite(&Vcb->chunk_lock); return Status; } + + // c is now freed, so avoid releasing non-existent lock + le = le2; + continue; } else if (c->created) { Status = create_chunk(Vcb, c, Irp); if (!NT_SUCCESS(Status)) { ERR("create_chunk returned %08x\n", Status); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); ExReleaseResourceLite(&Vcb->chunk_lock); return Status; } }
- if (used_minus_cache > 0) - ExReleaseResourceLite(&c->lock); - } + if (used_minus_cache > 0 || created) + release_chunk_lock(c, Vcb); + } else + release_chunk_lock(c, Vcb); }
le = le2; diff --git a/drivers/filesystems/btrfs/free-space.c b/drivers/filesystems/btrfs/free-space.c index 1ed2da9361..f6248e9038 100644 --- a/drivers/filesystems/btrfs/free-space.c +++ b/drivers/filesystems/btrfs/free-space.c @@ -161,12 +161,12 @@ NTSTATUS clear_free_space_cache(device_extension* Vcb, LIST_ENTRY* batchlist, PI chunk* c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->cache_loaded) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
Status = load_cache_chunk(Vcb, c, NULL); if (!NT_SUCCESS(Status)) { ERR("load_cache_chunk(%llx) returned %08x\n", c->offset, Status); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); ExReleaseResourceLite(&Vcb->chunk_lock); return Status; } @@ -174,7 +174,7 @@ NTSTATUS clear_free_space_cache(device_extension* Vcb, LIST_ENTRY* batchlist, PI c->changed = TRUE; c->space_changed = TRUE;
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); }
le = le->Flink; @@ -975,14 +975,14 @@ static NTSTATUS insert_cache_extent(fcb* fcb, UINT64 start, UINT64 length, LIST_ c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly && !c->reloc) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == flags && (c->chunk_item->size - c->used) >= length) { if (insert_extent_chunk(fcb->Vcb, fcb, c, start, length, FALSE, NULL, NULL, rollback, BTRFS_COMPRESSION_NONE, length, FALSE, 0)) return STATUS_SUCCESS; }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, fcb->Vcb); }
le = le->Flink; @@ -995,14 +995,14 @@ static NTSTATUS insert_cache_extent(fcb* fcb, UINT64 start, UINT64 length, LIST_ return Status; }
- ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == flags && (c->chunk_item->size - c->used) >= length) { if (insert_extent_chunk(fcb->Vcb, fcb, c, start, length, FALSE, NULL, NULL, rollback, BTRFS_COMPRESSION_NONE, length, FALSE, 0)) return STATUS_SUCCESS; }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, fcb->Vcb);
return STATUS_DISK_FULL; } @@ -1360,9 +1360,9 @@ NTSTATUS allocate_cache(device_extension* Vcb, BOOL* changed, PIRP Irp, LIST_ENT if (c->space_changed) { BOOL b;
- ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb); Status = allocate_cache_chunk(Vcb, c, &b, &batchlist, Irp, rollback); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb);
if (b) *changed = TRUE; @@ -1828,9 +1828,9 @@ NTSTATUS update_chunk_caches(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollba c = CONTAINING_RECORD(le, chunk, list_entry);
if (c->space_changed) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb); Status = update_chunk_cache(Vcb, c, &now, &batchlist, Irp, rollback); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb);
if (!NT_SUCCESS(Status)) { ERR("update_chunk_cache(%llx) returned %08x\n", c->offset, Status); @@ -1897,9 +1897,9 @@ NTSTATUS update_chunk_caches_tree(device_extension* Vcb, PIRP Irp) { c = CONTAINING_RECORD(le, chunk, list_entry);
if (c->space_changed) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb); Status = update_chunk_cache_tree(Vcb, c, &batchlist); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb);
if (!NT_SUCCESS(Status)) { ERR("update_chunk_cache_tree(%llx) returned %08x\n", c->offset, Status); diff --git a/drivers/filesystems/btrfs/fsctl.c b/drivers/filesystems/btrfs/fsctl.c index 6cc0f45ab1..3b13e89766 100644 --- a/drivers/filesystems/btrfs/fsctl.c +++ b/drivers/filesystems/btrfs/fsctl.c @@ -1024,7 +1024,7 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT FileObject, vo
// add INODE_REF
- irsize = (UINT16)(offsetof(INODE_REF, name[0]) + strlen(DOTDOT)); + irsize = (UINT16)(offsetof(INODE_REF, name[0]) + sizeof(DOTDOT) - 1); ir = ExAllocatePoolWithTag(PagedPool, irsize, ALLOC_TAG); if (!ir) { ERR("out of memory\n"); @@ -1033,7 +1033,7 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT FileObject, vo }
ir->index = 0; - ir->n = (USHORT)strlen(DOTDOT); + ir->n = sizeof(DOTDOT) - 1; RtlCopyMemory(ir->name, DOTDOT, ir->n);
Status = insert_tree_item(Vcb, r, r->root_item.objid, TYPE_INODE_REF, r->root_item.objid, ir, irsize, NULL, Irp); @@ -1164,9 +1164,10 @@ end2: }
static NTSTATUS get_inode_info(PFILE_OBJECT FileObject, void* data, ULONG length) { - btrfs_inode_info* bii = data; + btrfs_inode_info2* bii = data; fcb* fcb; ccb* ccb; + BOOL old_style;
if (length < sizeof(btrfs_inode_info)) return STATUS_BUFFER_OVERFLOW; @@ -1192,6 +1193,8 @@ static NTSTATUS get_inode_info(PFILE_OBJECT FileObject, void* data, ULONG length if (fcb->ads) fcb = ccb->fileref->parent->fcb;
+ old_style = length < sizeof(btrfs_inode_info2); + ExAcquireResourceSharedLite(fcb->Header.Resource, TRUE);
bii->subvol = fcb->subvol->id; @@ -1210,52 +1213,84 @@ static NTSTATUS get_inode_info(PFILE_OBJECT FileObject, void* data, ULONG length bii->flags = fcb->inode_item.flags;
bii->inline_length = 0; - bii->disk_size[0] = 0; - bii->disk_size[1] = 0; - bii->disk_size[2] = 0; + bii->disk_size_uncompressed = 0; + bii->disk_size_zlib = 0; + bii->disk_size_lzo = 0; + + if (!old_style) { + bii->disk_size_zstd = 0; + bii->sparse_size = 0; + }
if (fcb->type != BTRFS_TYPE_DIRECTORY) { + UINT64 last_end = 0; LIST_ENTRY* le; + BOOL extents_inline = FALSE;
le = fcb->extents.Flink; while (le != &fcb->extents) { extent* ext = CONTAINING_RECORD(le, extent, list_entry);
if (!ext->ignore) { + if (!old_style && ext->offset > last_end) + bii->sparse_size += ext->offset - last_end; + if (ext->extent_data.type == EXTENT_TYPE_INLINE) { bii->inline_length += ext->datalen - (UINT16)offsetof(EXTENT_DATA, data[0]); + last_end = ext->offset + ext->extent_data.decoded_size; + extents_inline = TRUE; } else { EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ext->extent_data.data;
// FIXME - compressed extents with a hole in them are counted more than once if (ed2->size != 0) { - if (ext->extent_data.compression == BTRFS_COMPRESSION_NONE) { - bii->disk_size[0] += ed2->num_bytes; - } else if (ext->extent_data.compression == BTRFS_COMPRESSION_ZLIB) { - bii->disk_size[1] += ed2->size; - } else if (ext->extent_data.compression == BTRFS_COMPRESSION_LZO) { - bii->disk_size[2] += ed2->size; + switch (ext->extent_data.compression) { + case BTRFS_COMPRESSION_NONE: + bii->disk_size_uncompressed += ed2->num_bytes; + break; + + case BTRFS_COMPRESSION_ZLIB: + bii->disk_size_zlib += ed2->size; + break; + + case BTRFS_COMPRESSION_LZO: + bii->disk_size_lzo += ed2->size; + break; + + case BTRFS_COMPRESSION_ZSTD: + if (!old_style) + bii->disk_size_zstd += ed2->size; + break; } } + + last_end = ext->offset + ed2->num_bytes; } }
le = le->Flink; } + + if (!extents_inline && !old_style && sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size) > last_end) + bii->sparse_size += sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size) - last_end; }
switch (fcb->prop_compression) { case PropCompression_Zlib: bii->compression_type = BTRFS_COMPRESSION_ZLIB; - break; + break;
case PropCompression_LZO: bii->compression_type = BTRFS_COMPRESSION_LZO; - break; + break; + + case PropCompression_ZSTD: + bii->compression_type = BTRFS_COMPRESSION_ZSTD; + break;
default: bii->compression_type = BTRFS_COMPRESSION_ANY; - break; + break; }
ExReleaseResourceLite(fcb->Header.Resource); @@ -1295,7 +1330,7 @@ static NTSTATUS set_inode_info(PFILE_OBJECT FileObject, void* data, ULONG length return STATUS_ACCESS_DENIED; }
- if (bsii->compression_type_changed && bsii->compression_type > BTRFS_COMPRESSION_LZO) + if (bsii->compression_type_changed && bsii->compression_type > BTRFS_COMPRESSION_ZSTD) return STATUS_INVALID_PARAMETER;
if (fcb->ads) @@ -1358,6 +1393,10 @@ static NTSTATUS set_inode_info(PFILE_OBJECT FileObject, void* data, ULONG length case BTRFS_COMPRESSION_LZO: fcb->prop_compression = PropCompression_LZO; break; + + case BTRFS_COMPRESSION_ZSTD: + fcb->prop_compression = PropCompression_ZSTD; + break; }
fcb->prop_compression_changed = TRUE; @@ -2351,10 +2390,6 @@ static NTSTATUS invalidate_volumes(PIRP Irp) {
RtlZeroMemory(newvpb, sizeof(VPB));
- IoAcquireVpbSpinLock(&irql); - devobj->Vpb->Flags &= ~VPB_MOUNTED; - IoReleaseVpbSpinLock(irql); - ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
Vcb->removing = TRUE; @@ -2403,7 +2438,7 @@ static NTSTATUS invalidate_volumes(PIRP Irp) { ExFreePool(newvpb);
if (Vcb->open_files == 0) - uninit(Vcb, FALSE); + uninit(Vcb); }
break; @@ -2517,7 +2552,6 @@ static void update_volumes(device_extension* Vcb) {
static NTSTATUS dismount_volume(device_extension* Vcb, PIRP Irp) { NTSTATUS Status; - KIRQL irql;
TRACE("FSCTL_DISMOUNT_VOLUME\n");
@@ -2558,11 +2592,6 @@ static NTSTATUS dismount_volume(device_extension* Vcb, PIRP Irp) {
ExReleaseResourceLite(&Vcb->tree_lock);
- IoAcquireVpbSpinLock(&irql); - Vcb->Vpb->Flags &= ~VPB_MOUNTED; - Vcb->Vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED; - IoReleaseVpbSpinLock(irql); - return STATUS_SUCCESS; }
@@ -3631,10 +3660,6 @@ end: return Status; }
-// based on functions in sys/sysmacros.h -#define major(rdev) ((((rdev) >> 8) & 0xFFF) | ((UINT32)((rdev) >> 32) & ~0xFFF)) -#define minor(rdev) (((rdev) & 0xFF) | ((UINT32)((rdev) >> 12) & ~0xFF)) - static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data, ULONG datalen, PIRP Irp) { NTSTATUS Status; btrfs_mknod* bmn; @@ -4161,7 +4186,7 @@ static NTSTATUS fsctl_set_xattr(device_extension* Vcb, PFILE_OBJECT FileObject,
ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
- if (bsxa->namelen == strlen(EA_NTACL) && RtlCompareMemory(bsxa->data, EA_NTACL, strlen(EA_NTACL)) == strlen(EA_NTACL)) { + if (bsxa->namelen == sizeof(EA_NTACL) - 1 && RtlCompareMemory(bsxa->data, EA_NTACL, sizeof(EA_NTACL) - 1) == sizeof(EA_NTACL) - 1) { if ((!(ccb->access & WRITE_DAC) || !(ccb->access & WRITE_OWNER)) && Irp->RequestorMode == UserMode) { WARN("insufficient privileges\n"); Status = STATUS_ACCESS_DENIED; @@ -4199,7 +4224,7 @@ static NTSTATUS fsctl_set_xattr(device_extension* Vcb, PFILE_OBJECT FileObject,
Status = STATUS_SUCCESS; goto end; - } else if (bsxa->namelen == strlen(EA_DOSATTRIB) && RtlCompareMemory(bsxa->data, EA_DOSATTRIB, strlen(EA_DOSATTRIB)) == strlen(EA_DOSATTRIB)) { + } else if (bsxa->namelen == sizeof(EA_DOSATTRIB) - 1 && RtlCompareMemory(bsxa->data, EA_DOSATTRIB, sizeof(EA_DOSATTRIB) - 1) == sizeof(EA_DOSATTRIB) - 1) { ULONG atts;
if (bsxa->valuelen > 0 && get_file_attributes_from_xattr(bsxa->data + bsxa->namelen, bsxa->valuelen, &atts)) { @@ -4230,7 +4255,7 @@ static NTSTATUS fsctl_set_xattr(device_extension* Vcb, PFILE_OBJECT FileObject,
Status = STATUS_SUCCESS; goto end; - } else if (bsxa->namelen == strlen(EA_REPARSE) && RtlCompareMemory(bsxa->data, EA_REPARSE, strlen(EA_REPARSE)) == strlen(EA_REPARSE)) { + } else if (bsxa->namelen == sizeof(EA_REPARSE) - 1 && RtlCompareMemory(bsxa->data, EA_REPARSE, sizeof(EA_REPARSE) - 1) == sizeof(EA_REPARSE) - 1) { if (fcb->reparse_xattr.Buffer) { ExFreePool(fcb->reparse_xattr.Buffer); fcb->reparse_xattr.Buffer = NULL; @@ -4254,7 +4279,7 @@ static NTSTATUS fsctl_set_xattr(device_extension* Vcb, PFILE_OBJECT FileObject,
Status = STATUS_SUCCESS; goto end; - } else if (bsxa->namelen == strlen(EA_EA) && RtlCompareMemory(bsxa->data, EA_EA, strlen(EA_EA)) == strlen(EA_EA)) { + } else if (bsxa->namelen == sizeof(EA_EA) - 1 && RtlCompareMemory(bsxa->data, EA_EA, sizeof(EA_EA) - 1) == sizeof(EA_EA) - 1) { if (!(ccb->access & FILE_WRITE_EA) && Irp->RequestorMode == UserMode) { WARN("insufficient privileges\n"); Status = STATUS_ACCESS_DENIED; @@ -4310,13 +4335,16 @@ static NTSTATUS fsctl_set_xattr(device_extension* Vcb, PFILE_OBJECT FileObject,
Status = STATUS_SUCCESS; goto end; - } else if (bsxa->namelen == strlen(EA_PROP_COMPRESSION) && RtlCompareMemory(bsxa->data, EA_PROP_COMPRESSION, strlen(EA_PROP_COMPRESSION)) == strlen(EA_PROP_COMPRESSION)) { - const char lzo[] = "lzo"; - const char zlib[] = "zlib"; - - if (bsxa->valuelen == strlen(lzo) && RtlCompareMemory(bsxa->data + bsxa->namelen, lzo, bsxa->valuelen) == bsxa->valuelen) + } else if (bsxa->namelen == sizeof(EA_PROP_COMPRESSION) - 1 && RtlCompareMemory(bsxa->data, EA_PROP_COMPRESSION, sizeof(EA_PROP_COMPRESSION) - 1) == sizeof(EA_PROP_COMPRESSION) - 1) { + static const char lzo[] = "lzo"; + static const char zlib[] = "zlib"; + static const char zstd[] = "zstd"; + + if (bsxa->valuelen == sizeof(zstd) - 1 && RtlCompareMemory(bsxa->data + bsxa->namelen, zstd, bsxa->valuelen) == bsxa->valuelen) + fcb->prop_compression = PropCompression_ZSTD; + else if (bsxa->valuelen == sizeof(lzo) - 1 && RtlCompareMemory(bsxa->data + bsxa->namelen, lzo, bsxa->valuelen) == bsxa->valuelen) fcb->prop_compression = PropCompression_LZO; - else if (bsxa->valuelen == strlen(zlib) && RtlCompareMemory(bsxa->data + bsxa->namelen, zlib, bsxa->valuelen) == bsxa->valuelen) + else if (bsxa->valuelen == sizeof(zlib) - 1 && RtlCompareMemory(bsxa->data + bsxa->namelen, zlib, bsxa->valuelen) == bsxa->valuelen) fcb->prop_compression = PropCompression_Zlib; else fcb->prop_compression = PropCompression_None; @@ -4331,7 +4359,7 @@ static NTSTATUS fsctl_set_xattr(device_extension* Vcb, PFILE_OBJECT FileObject,
Status = STATUS_SUCCESS; goto end; - } else if (bsxa->namelen >= strlen(stream_pref) && RtlCompareMemory(bsxa->data, stream_pref, strlen(stream_pref)) == strlen(stream_pref)) { + } else if (bsxa->namelen >= (sizeof(stream_pref) - 1) && RtlCompareMemory(bsxa->data, stream_pref, sizeof(stream_pref) - 1) == sizeof(stream_pref) - 1) { // don't allow xattrs beginning with user., as these appear as streams instead Status = STATUS_OBJECT_NAME_INVALID; goto end; diff --git a/drivers/filesystems/btrfs/pnp.c b/drivers/filesystems/btrfs/pnp.c index 5a7e91b410..fbb535f070 100644 --- a/drivers/filesystems/btrfs/pnp.c +++ b/drivers/filesystems/btrfs/pnp.c @@ -247,12 +247,10 @@ static NTSTATUS pnp_remove_device(PDEVICE_OBJECT DeviceObject) {
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); Vcb->removing = TRUE; - Vcb->Vpb->Flags &= ~VPB_MOUNTED; - Vcb->Vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED; ExReleaseResourceLite(&Vcb->tree_lock);
if (Vcb->open_files == 0) - uninit(Vcb, FALSE); + uninit(Vcb); }
return STATUS_SUCCESS; @@ -270,13 +268,11 @@ NTSTATUS pnp_surprise_removal(PDEVICE_OBJECT DeviceObject, PIRP Irp) { Vcb->vde->mounted_device = NULL;
Vcb->removing = TRUE; - Vcb->Vpb->Flags &= ~VPB_MOUNTED; - Vcb->Vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED;
ExReleaseResourceLite(&Vcb->tree_lock);
if (Vcb->open_files == 0) - uninit(Vcb, FALSE); + uninit(Vcb); }
return STATUS_SUCCESS; @@ -349,7 +345,7 @@ end: static NTSTATUS bus_query_hardware_ids(PIRP Irp) { WCHAR* out;
- static WCHAR ids[] = L"ROOT\btrfs\0"; + static const WCHAR ids[] = L"ROOT\btrfs\0";
out = ExAllocatePoolWithTag(PagedPool, sizeof(ids), ALLOC_TAG); if (!out) { @@ -402,11 +398,11 @@ static NTSTATUS pdo_query_device_id(pdo_device_extension* pdode, PIRP Irp) { WCHAR name[100], *noff, *out; int i;
- static WCHAR pref[] = L"Btrfs\"; + static const WCHAR pref[] = L"Btrfs\";
- RtlCopyMemory(name, pref, wcslen(pref) * sizeof(WCHAR)); + RtlCopyMemory(name, pref, sizeof(pref) - sizeof(WCHAR));
- noff = &name[wcslen(pref)]; + noff = &name[(sizeof(pref) / sizeof(WCHAR)) - 1]; for (i = 0; i < 16; i++) { *noff = hex_digit(pdode->uuid.uuid[i] >> 4); noff++; *noff = hex_digit(pdode->uuid.uuid[i] & 0xf); noff++; @@ -434,7 +430,7 @@ static NTSTATUS pdo_query_device_id(pdo_device_extension* pdode, PIRP Irp) { static NTSTATUS pdo_query_hardware_ids(PIRP Irp) { WCHAR* out;
- static WCHAR ids[] = L"BtrfsVolume\0"; + static const WCHAR ids[] = L"BtrfsVolume\0";
out = ExAllocatePoolWithTag(PagedPool, sizeof(ids), ALLOC_TAG); if (!out) { diff --git a/drivers/filesystems/btrfs/read.c b/drivers/filesystems/btrfs/read.c index 4384d65784..2eb19b1a80 100644 --- a/drivers/filesystems/btrfs/read.c +++ b/drivers/filesystems/btrfs/read.c @@ -1645,6 +1645,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr, _In_ UINT32 len
if (!context.stripes[i].mdl) { ERR("IoAllocateMdl failed\n"); + MmUnlockPages(master_mdl); + IoFreeMdl(master_mdl); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } @@ -1654,6 +1656,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr, _In_ UINT32 len stripeoff = ExAllocatePoolWithTag(NonPagedPool, sizeof(UINT32) * ci->num_stripes, ALLOC_TAG); if (!stripeoff) { ERR("out of memory\n"); + MmUnlockPages(master_mdl); + IoFreeMdl(master_mdl); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } @@ -1760,6 +1764,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr, _In_ UINT32 len stripes = ExAllocatePoolWithTag(NonPagedPool, sizeof(read_data_stripe*) * ci->num_stripes / ci->sub_stripes, ALLOC_TAG); if (!stripes) { ERR("out of memory\n"); + MmUnlockPages(master_mdl); + IoFreeMdl(master_mdl); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } @@ -1795,6 +1801,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr, _In_ UINT32 len
if (!context.stripes[i+j].mdl) { ERR("IoAllocateMdl failed\n"); + MmUnlockPages(master_mdl); + IoFreeMdl(master_mdl); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } @@ -1818,6 +1826,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr, _In_ UINT32 len
if (!context.stripes[i+j].mdl) { ERR("IoAllocateMdl failed\n"); + MmUnlockPages(master_mdl); + IoFreeMdl(master_mdl); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } @@ -1839,6 +1849,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr, _In_ UINT32 len stripeoff = ExAllocatePoolWithTag(NonPagedPool, sizeof(UINT32) * ci->num_stripes / ci->sub_stripes, ALLOC_TAG); if (!stripeoff) { ERR("out of memory\n"); + MmUnlockPages(master_mdl); + IoFreeMdl(master_mdl); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } @@ -2075,6 +2087,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr, _In_ UINT32 len
if (!context.stripes[i].mdl) { ERR("IoAllocateMdl failed\n"); + MmUnlockPages(master_mdl); + IoFreeMdl(master_mdl); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } @@ -2085,6 +2099,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr, _In_ UINT32 len dummypage = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, ALLOC_TAG); if (!dummypage) { ERR("out of memory\n"); + MmUnlockPages(master_mdl); + IoFreeMdl(master_mdl); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } @@ -2092,6 +2108,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr, _In_ UINT32 len dummy_mdl = IoAllocateMdl(dummypage, PAGE_SIZE, FALSE, FALSE, NULL); if (!dummy_mdl) { ERR("IoAllocateMdl failed\n"); + MmUnlockPages(master_mdl); + IoFreeMdl(master_mdl); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } @@ -2104,6 +2122,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr, _In_ UINT32 len stripeoff = ExAllocatePoolWithTag(NonPagedPool, sizeof(UINT32) * ci->num_stripes, ALLOC_TAG); if (!stripeoff) { ERR("out of memory\n"); + MmUnlockPages(master_mdl); + IoFreeMdl(master_mdl); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } @@ -2328,6 +2348,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr, _In_ UINT32 len
if (!context.stripes[i].mdl) { ERR("IoAllocateMdl failed\n"); + MmUnlockPages(master_mdl); + IoFreeMdl(master_mdl); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } @@ -2338,6 +2360,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr, _In_ UINT32 len dummypage = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, ALLOC_TAG); if (!dummypage) { ERR("out of memory\n"); + MmUnlockPages(master_mdl); + IoFreeMdl(master_mdl); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } @@ -2345,6 +2369,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr, _In_ UINT32 len dummy_mdl = IoAllocateMdl(dummypage, PAGE_SIZE, FALSE, FALSE, NULL); if (!dummy_mdl) { ERR("IoAllocateMdl failed\n"); + MmUnlockPages(master_mdl); + IoFreeMdl(master_mdl); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } @@ -2357,6 +2383,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr, _In_ UINT32 len stripeoff = ExAllocatePoolWithTag(NonPagedPool, sizeof(UINT32) * ci->num_stripes, ALLOC_TAG); if (!stripeoff) { ERR("out of memory\n"); + MmUnlockPages(master_mdl); + IoFreeMdl(master_mdl); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } @@ -2785,7 +2813,7 @@ NTSTATUS read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64 length, ULONG* pb read = (UINT32)min(min(len, ext->datalen) - off, length);
RtlCopyMemory(data + bytes_read, &ed->data[off], read); - } else if (ed->compression == BTRFS_COMPRESSION_ZLIB || ed->compression == BTRFS_COMPRESSION_LZO) { + } else if (ed->compression == BTRFS_COMPRESSION_ZLIB || ed->compression == BTRFS_COMPRESSION_LZO || ed->compression == BTRFS_COMPRESSION_ZSTD) { UINT8* decomp; BOOL decomp_alloc; UINT16 inlen = ext->datalen - (UINT16)offsetof(EXTENT_DATA, data[0]); @@ -2834,6 +2862,13 @@ NTSTATUS read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64 length, ULONG* pb if (decomp_alloc) ExFreePool(decomp); goto exit; } + } else if (ed->compression == BTRFS_COMPRESSION_ZSTD) { + Status = zstd_decompress(ed->data, inlen, decomp, (UINT32)(read + off)); + if (!NT_SUCCESS(Status)) { + ERR("zstd_decompress returned %08x\n", Status); + if (decomp_alloc) ExFreePool(decomp); + goto exit; + } }
if (decomp_alloc) { @@ -3000,6 +3035,18 @@ NTSTATUS read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64 length, ULONG* pb ERR("lzo_decompress returned %08x\n", Status); ExFreePool(buf);
+ if (decomp) + ExFreePool(decomp); + + goto exit; + } + } else if (ed->compression == BTRFS_COMPRESSION_ZSTD) { + Status = zstd_decompress(buf2, inlen, decomp ? decomp : (data + bytes_read), outlen); + + if (!NT_SUCCESS(Status)) { + ERR("zstd_decompress returned %08x\n", Status); + ExFreePool(buf); + if (decomp) ExFreePool(decomp);
diff --git a/drivers/filesystems/btrfs/registry.c b/drivers/filesystems/btrfs/registry.c index 05f66f5df2..84196df002 100644 --- a/drivers/filesystems/btrfs/registry.c +++ b/drivers/filesystems/btrfs/registry.c @@ -16,6 +16,7 @@ * along with WinBtrfs. If not, see http://www.gnu.org/licenses/. */
#include "btrfs_drv.h" +#include "zstd/zstd.h"
extern UNICODE_STRING log_device, log_file, registry_path; extern LIST_ENTRY uid_map_list, gid_map_list; @@ -30,13 +31,13 @@ extern PDEVICE_OBJECT comdo;
WORK_QUEUE_ITEM wqi;
-static WCHAR option_mounted[] = L"Mounted"; +static const WCHAR option_mounted[] = L"Mounted";
NTSTATUS registry_load_volume_options(device_extension* Vcb) { BTRFS_UUID* uuid = &Vcb->superblock.uuid; mount_options* options = &Vcb->options; UNICODE_STRING path, ignoreus, compressus, compressforceus, compresstypeus, readonlyus, zliblevelus, flushintervalus, - maxinlineus, subvolidus, skipbalanceus, nobarrierus, notrimus, clearcacheus, allowdegradedus; + maxinlineus, subvolidus, skipbalanceus, nobarrierus, notrimus, clearcacheus, allowdegradedus, zstdlevelus; OBJECT_ATTRIBUTES oa; NTSTATUS Status; ULONG i, j, kvfilen, index, retlen; @@ -45,9 +46,10 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
options->compress = mount_compress; options->compress_force = mount_compress_force; - options->compress_type = mount_compress_type > BTRFS_COMPRESSION_LZO ? 0 : mount_compress_type; + options->compress_type = mount_compress_type > BTRFS_COMPRESSION_ZSTD ? 0 : mount_compress_type; options->readonly = mount_readonly; options->zlib_level = mount_zlib_level; + options->zstd_level = mount_zstd_level; options->flush_interval = mount_flush_interval; options->max_inline = min(mount_max_inline, Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - sizeof(EXTENT_DATA) + 1); options->skip_balance = mount_skip_balance; @@ -118,6 +120,7 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) { RtlInitUnicodeString(¬rimus, L"NoTrim"); RtlInitUnicodeString(&clearcacheus, L"ClearCache"); RtlInitUnicodeString(&allowdegradedus, L"AllowDegraded"); + RtlInitUnicodeString(&zstdlevelus, L"ZstdLevel");
do { Status = ZwEnumerateValueKey(h, index, KeyValueFullInformation, kvfi, kvfilen, &retlen); @@ -145,7 +148,7 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) { } else if (FsRtlAreNamesEqual(&compresstypeus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) { DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
- options->compress_type = (UINT8)(*val > BTRFS_COMPRESSION_LZO ? 0 : *val); + options->compress_type = (UINT8)(*val > BTRFS_COMPRESSION_ZSTD ? 0 : *val); } else if (FsRtlAreNamesEqual(&readonlyus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) { DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
@@ -186,6 +189,10 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) { DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
options->allow_degraded = *val; + } else if (FsRtlAreNamesEqual(&zstdlevelus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) { + DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset); + + options->zstd_level = *val; } } else if (Status != STATUS_NO_MORE_ENTRIES) { ERR("ZwEnumerateValueKey returned %08x\n", Status); @@ -199,6 +206,9 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) { if (options->zlib_level > 9) options->zlib_level = 9;
+ if (options->zstd_level > (UINT32)ZSTD_maxCLevel()) + options->zstd_level = ZSTD_maxCLevel(); + if (options->flush_interval == 0) options->flush_interval = mount_flush_interval;
@@ -258,8 +268,8 @@ NTSTATUS registry_mark_volume_mounted(BTRFS_UUID* uuid) { goto end; }
- mountedus.Buffer = option_mounted; - mountedus.Length = mountedus.MaximumLength = (USHORT)wcslen(option_mounted) * sizeof(WCHAR); + mountedus.Buffer = (WCHAR*)option_mounted; + mountedus.Length = mountedus.MaximumLength = sizeof(option_mounted) - sizeof(WCHAR);
data = 1;
@@ -308,8 +318,8 @@ static NTSTATUS registry_mark_volume_unmounted_path(PUNICODE_STRING path) {
index = 0;
- mountedus.Buffer = option_mounted; - mountedus.Length = mountedus.MaximumLength = (USHORT)wcslen(option_mounted) * sizeof(WCHAR); + mountedus.Buffer = (WCHAR*)option_mounted; + mountedus.Length = mountedus.MaximumLength = sizeof(option_mounted) - sizeof(WCHAR);
do { Status = ZwEnumerateValueKey(h, index, KeyValueBasicInformation, kvbi, kvbilen, &retlen); @@ -526,7 +536,7 @@ static void read_mappings(PUNICODE_STRING regpath) { ULONG dispos; NTSTATUS Status;
- const WCHAR mappings[] = L"\Mappings"; + static const WCHAR mappings[] = L"\Mappings";
while (!IsListEmpty(&uid_map_list)) { uid_map* um = CONTAINING_RECORD(RemoveHeadList(&uid_map_list), uid_map, listentry); @@ -535,17 +545,17 @@ static void read_mappings(PUNICODE_STRING regpath) { ExFreePool(um); }
- path = ExAllocatePoolWithTag(PagedPool, regpath->Length + (wcslen(mappings) * sizeof(WCHAR)), ALLOC_TAG); + path = ExAllocatePoolWithTag(PagedPool, regpath->Length + sizeof(mappings) - sizeof(WCHAR), ALLOC_TAG); if (!path) { ERR("out of memory\n"); return; }
RtlCopyMemory(path, regpath->Buffer, regpath->Length); - RtlCopyMemory((UINT8*)path + regpath->Length, mappings, wcslen(mappings) * sizeof(WCHAR)); + RtlCopyMemory((UINT8*)path + regpath->Length, mappings, sizeof(mappings) - sizeof(WCHAR));
us.Buffer = path; - us.Length = us.MaximumLength = regpath->Length + ((USHORT)wcslen(mappings) * sizeof(WCHAR)); + us.Length = us.MaximumLength = regpath->Length + sizeof(mappings) - sizeof(WCHAR);
InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
@@ -604,7 +614,7 @@ static void read_group_mappings(PUNICODE_STRING regpath) { ULONG dispos; NTSTATUS Status;
- const WCHAR mappings[] = L"\GroupMappings"; + static const WCHAR mappings[] = L"\GroupMappings";
while (!IsListEmpty(&gid_map_list)) { gid_map* gm = CONTAINING_RECORD(RemoveHeadList(&gid_map_list), gid_map, listentry); @@ -613,17 +623,17 @@ static void read_group_mappings(PUNICODE_STRING regpath) { ExFreePool(gm); }
- path = ExAllocatePoolWithTag(PagedPool, regpath->Length + (wcslen(mappings) * sizeof(WCHAR)), ALLOC_TAG); + path = ExAllocatePoolWithTag(PagedPool, regpath->Length + sizeof(mappings) - sizeof(WCHAR), ALLOC_TAG); if (!path) { ERR("out of memory\n"); return; }
RtlCopyMemory(path, regpath->Buffer, regpath->Length); - RtlCopyMemory((UINT8*)path + regpath->Length, mappings, wcslen(mappings) * sizeof(WCHAR)); + RtlCopyMemory((UINT8*)path + regpath->Length, mappings, sizeof(mappings) - sizeof(WCHAR));
us.Buffer = path; - us.Length = us.MaximumLength = regpath->Length + ((USHORT)wcslen(mappings) * sizeof(WCHAR)); + us.Length = us.MaximumLength = regpath->Length + sizeof(mappings) - sizeof(WCHAR);
InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
@@ -676,7 +686,7 @@ static void read_group_mappings(PUNICODE_STRING regpath) { // If we're creating the key for the first time, we add a default mapping of // BUILTIN\Users to gid 100, which ought to correspond to the "users" group on Linux.
- us2.Length = us2.MaximumLength = (USHORT)wcslen(builtin_users) * sizeof(WCHAR); + us2.Length = us2.MaximumLength = sizeof(builtin_users) - sizeof(WCHAR); us2.Buffer = ExAllocatePoolWithTag(PagedPool, us2.MaximumLength, ALLOC_TAG);
if (us2.Buffer) { @@ -760,7 +770,7 @@ void read_registry(PUNICODE_STRING regpath, BOOL refresh) { ULONG kvfilen, old_debug_log_level = debug_log_level; UNICODE_STRING us, old_log_file, old_log_device;
- static WCHAR def_log_file[] = L"\??\C:\btrfs.log"; + static const WCHAR def_log_file[] = L"\??\C:\btrfs.log"; #endif
ExAcquireResourceExclusiveLite(&mapping_lock, TRUE); @@ -794,6 +804,7 @@ void read_registry(PUNICODE_STRING regpath, BOOL refresh) { get_registry_value(h, L"ClearCache", REG_DWORD, &mount_clear_cache, sizeof(mount_clear_cache)); get_registry_value(h, L"AllowDegraded", REG_DWORD, &mount_allow_degraded, sizeof(mount_allow_degraded)); get_registry_value(h, L"Readonly", REG_DWORD, &mount_readonly, sizeof(mount_readonly)); + get_registry_value(h, L"ZstdLevel", REG_DWORD, &mount_zstd_level, sizeof(mount_zstd_level));
if (!refresh) get_registry_value(h, L"NoPNP", REG_DWORD, &no_pnp, sizeof(no_pnp)); @@ -935,7 +946,7 @@ void read_registry(PUNICODE_STRING regpath, BOOL refresh) {
ExFreePool(kvfi); } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { - Status = ZwSetValueKey(h, &us, 0, REG_SZ, def_log_file, (ULONG)(wcslen(def_log_file) + 1) * sizeof(WCHAR)); + Status = ZwSetValueKey(h, &us, 0, REG_SZ, (void*)def_log_file, sizeof(def_log_file));
if (!NT_SUCCESS(Status)) ERR("ZwSetValueKey returned %08x\n", Status); @@ -947,7 +958,7 @@ void read_registry(PUNICODE_STRING regpath, BOOL refresh) { }
if (log_file.Length == 0) { - log_file.Length = log_file.MaximumLength = (UINT16)wcslen(def_log_file) * sizeof(WCHAR); + log_file.Length = log_file.MaximumLength = sizeof(def_log_file) - sizeof(WCHAR); log_file.Buffer = ExAllocatePoolWithTag(PagedPool, log_file.MaximumLength, ALLOC_TAG);
if (!log_file.Buffer) { diff --git a/drivers/filesystems/btrfs/reparse.c b/drivers/filesystems/btrfs/reparse.c index 8e8d319b58..957ad07305 100644 --- a/drivers/filesystems/btrfs/reparse.c +++ b/drivers/filesystems/btrfs/reparse.c @@ -169,7 +169,7 @@ end: return Status; }
-static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, ccb* ccb, REPARSE_DATA_BUFFER* rdb, ULONG buflen, BOOL write, LIST_ENTRY* rollback) { +static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, fcb* fcb, ccb* ccb, REPARSE_DATA_BUFFER* rdb, ULONG buflen, BOOL write, LIST_ENTRY* rollback) { NTSTATUS Status; ULONG minlen; ULONG tlength; @@ -197,15 +197,15 @@ static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, ccb* ccb, REPARSE_DATA_ TRACE("substitute name = %.*S\n", subname.Length / sizeof(WCHAR), subname.Buffer); }
- fileref->fcb->type = BTRFS_TYPE_SYMLINK; - fileref->fcb->inode_item.st_mode |= __S_IFLNK; - fileref->fcb->inode_item.generation = fileref->fcb->Vcb->superblock.generation; // so we don't confuse btrfs send on Linux + fcb->type = BTRFS_TYPE_SYMLINK; + fcb->inode_item.st_mode |= __S_IFLNK; + fcb->inode_item.generation = fcb->Vcb->superblock.generation; // so we don't confuse btrfs send on Linux
- if (fileref->dc) - fileref->dc->type = fileref->fcb->type; + if (fileref && fileref->dc) + fileref->dc->type = fcb->type;
if (write) { - Status = truncate_file(fileref->fcb, 0, Irp, rollback); + Status = truncate_file(fcb, 0, Irp, rollback); if (!NT_SUCCESS(Status)) { ERR("truncate_file returned %08x\n", Status); return Status; @@ -238,7 +238,7 @@ static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, ccb* ccb, REPARSE_DATA_
offset.QuadPart = 0; tlength = target.Length; - Status = write_file2(fileref->fcb->Vcb, Irp, offset, target.Buffer, &tlength, FALSE, TRUE, + Status = write_file2(fcb->Vcb, Irp, offset, target.Buffer, &tlength, FALSE, TRUE, TRUE, FALSE, FALSE, rollback); ExFreePool(target.Buffer); } else @@ -247,86 +247,34 @@ static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, ccb* ccb, REPARSE_DATA_ KeQuerySystemTime(&time); win_time_to_unix(time, &now);
- fileref->fcb->inode_item.transid = fileref->fcb->Vcb->superblock.generation; - fileref->fcb->inode_item.sequence++; + fcb->inode_item.transid = fcb->Vcb->superblock.generation; + fcb->inode_item.sequence++;
- if (!ccb->user_set_change_time) - fileref->fcb->inode_item.st_ctime = now; + if (!ccb || !ccb->user_set_change_time) + fcb->inode_item.st_ctime = now;
- if (!ccb->user_set_write_time) - fileref->fcb->inode_item.st_mtime = now; + if (!ccb || !ccb->user_set_write_time) + fcb->inode_item.st_mtime = now;
- fileref->fcb->subvol->root_item.ctransid = fileref->fcb->Vcb->superblock.generation; - fileref->fcb->subvol->root_item.ctime = now; + fcb->subvol->root_item.ctransid = fcb->Vcb->superblock.generation; + fcb->subvol->root_item.ctime = now;
- fileref->fcb->inode_item_changed = TRUE; - mark_fcb_dirty(fileref->fcb); + fcb->inode_item_changed = TRUE; + mark_fcb_dirty(fcb);
- mark_fileref_dirty(fileref); + if (fileref) + mark_fileref_dirty(fileref);
return Status; }
-NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) { - PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); - PFILE_OBJECT FileObject = IrpSp->FileObject; - void* buffer = Irp->AssociatedIrp.SystemBuffer; - REPARSE_DATA_BUFFER* rdb = buffer; - DWORD buflen = IrpSp->Parameters.DeviceIoControl.InputBufferLength; - NTSTATUS Status = STATUS_SUCCESS; - fcb* fcb; - ccb* ccb; - file_ref* fileref; +NTSTATUS set_reparse_point2(fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG buflen, ccb* ccb, file_ref* fileref, PIRP Irp, LIST_ENTRY* rollback) { + NTSTATUS Status; ULONG tag; - LIST_ENTRY rollback; - - TRACE("(%p, %p)\n", DeviceObject, Irp); - - InitializeListHead(&rollback); - - if (!FileObject) { - ERR("FileObject was NULL\n"); - return STATUS_INVALID_PARAMETER; - } - - // IFSTest insists on this, for some reason... - if (Irp->UserBuffer) - return STATUS_INVALID_PARAMETER; - - fcb = FileObject->FsContext; - ccb = FileObject->FsContext2; - - if (!ccb) { - ERR("ccb was NULL\n"); - return STATUS_INVALID_PARAMETER; - } - - if (Irp->RequestorMode == UserMode && !(ccb->access & (FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA))) { - WARN("insufficient privileges\n"); - return STATUS_ACCESS_DENIED; - } - - fileref = ccb->fileref; - - if (!fileref) { - ERR("fileref was NULL\n"); - return STATUS_INVALID_PARAMETER; - } - - if (fcb->ads) { - fileref = fileref->parent; - fcb = fileref->fcb; - } - - TRACE("%S\n", file_desc(FileObject)); - - ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE); - ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
if (fcb->type == BTRFS_TYPE_SYMLINK) { WARN("tried to set a reparse point on an existing symlink\n"); - Status = STATUS_INVALID_PARAMETER; - goto end; + return STATUS_INVALID_PARAMETER; }
// FIXME - fail if we already have the attribute FILE_ATTRIBUTE_REPARSE_POINT @@ -335,34 +283,32 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
if (buflen < sizeof(ULONG)) { WARN("buffer was not long enough to hold tag\n"); - Status = STATUS_INVALID_BUFFER_SIZE; - goto end; + return STATUS_INVALID_BUFFER_SIZE; }
Status = FsRtlValidateReparsePointBuffer(buflen, rdb); if (!NT_SUCCESS(Status)) { ERR("FsRtlValidateReparsePointBuffer returned %08x\n", Status); - goto end; + return Status; }
- RtlCopyMemory(&tag, buffer, sizeof(ULONG)); + RtlCopyMemory(&tag, rdb, sizeof(ULONG));
if (fcb->type == BTRFS_TYPE_FILE && ((tag == IO_REPARSE_TAG_SYMLINK && rdb->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) || tag == IO_REPARSE_TAG_LXSS_SYMLINK)) { - Status = set_symlink(Irp, fileref, ccb, rdb, buflen, tag == IO_REPARSE_TAG_SYMLINK, &rollback); + Status = set_symlink(Irp, fileref, fcb, ccb, rdb, buflen, tag == IO_REPARSE_TAG_SYMLINK, rollback); fcb->atts |= FILE_ATTRIBUTE_REPARSE_POINT; } else { LARGE_INTEGER offset, time; BTRFS_TIME now;
- if (fcb->type == BTRFS_TYPE_DIRECTORY) { // for directories, store as xattr + if (fcb->type == BTRFS_TYPE_DIRECTORY || fcb->type == BTRFS_TYPE_CHARDEV || fcb->type == BTRFS_TYPE_BLOCKDEV) { // store as xattr ANSI_STRING buf;
buf.Buffer = ExAllocatePoolWithTag(PagedPool, buflen, ALLOC_TAG); if (!buf.Buffer) { ERR("out of memory\n"); - Status = STATUS_INSUFFICIENT_RESOURCES; - goto end; + return STATUS_INSUFFICIENT_RESOURCES; } buf.Length = buf.MaximumLength = (UINT16)buflen;
@@ -370,24 +316,24 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) { ExFreePool(fcb->reparse_xattr.Buffer);
fcb->reparse_xattr = buf; - RtlCopyMemory(buf.Buffer, buffer, buflen); + RtlCopyMemory(buf.Buffer, rdb, buflen);
fcb->reparse_xattr_changed = TRUE;
Status = STATUS_SUCCESS; } else { // otherwise, store as file data - Status = truncate_file(fcb, 0, Irp, &rollback); + Status = truncate_file(fcb, 0, Irp, rollback); if (!NT_SUCCESS(Status)) { ERR("truncate_file returned %08x\n", Status); - goto end; + return Status; }
offset.QuadPart = 0;
- Status = write_file2(fcb->Vcb, Irp, offset, buffer, &buflen, FALSE, TRUE, TRUE, FALSE, FALSE, &rollback); + Status = write_file2(fcb->Vcb, Irp, offset, rdb, &buflen, FALSE, TRUE, TRUE, FALSE, FALSE, rollback); if (!NT_SUCCESS(Status)) { ERR("write_file2 returned %08x\n", Status); - goto end; + return Status; } }
@@ -397,10 +343,10 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) { fcb->inode_item.transid = fcb->Vcb->superblock.generation; fcb->inode_item.sequence++;
- if (!ccb->user_set_change_time) + if (!ccb || !ccb->user_set_change_time) fcb->inode_item.st_ctime = now;
- if (!ccb->user_set_write_time) + if (!ccb || !ccb->user_set_write_time) fcb->inode_item.st_mtime = now;
fcb->atts |= FILE_ATTRIBUTE_REPARSE_POINT; @@ -413,6 +359,70 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) { mark_fcb_dirty(fcb); }
+ return STATUS_SUCCESS; +} + +NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) { + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + PFILE_OBJECT FileObject = IrpSp->FileObject; + void* buffer = Irp->AssociatedIrp.SystemBuffer; + REPARSE_DATA_BUFFER* rdb = buffer; + DWORD buflen = IrpSp->Parameters.DeviceIoControl.InputBufferLength; + NTSTATUS Status = STATUS_SUCCESS; + fcb* fcb; + ccb* ccb; + file_ref* fileref; + LIST_ENTRY rollback; + + TRACE("(%p, %p)\n", DeviceObject, Irp); + + InitializeListHead(&rollback); + + if (!FileObject) { + ERR("FileObject was NULL\n"); + return STATUS_INVALID_PARAMETER; + } + + // IFSTest insists on this, for some reason... + if (Irp->UserBuffer) + return STATUS_INVALID_PARAMETER; + + fcb = FileObject->FsContext; + ccb = FileObject->FsContext2; + + if (!ccb) { + ERR("ccb was NULL\n"); + return STATUS_INVALID_PARAMETER; + } + + if (Irp->RequestorMode == UserMode && !(ccb->access & (FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA))) { + WARN("insufficient privileges\n"); + return STATUS_ACCESS_DENIED; + } + + fileref = ccb->fileref; + + if (!fileref) { + ERR("fileref was NULL\n"); + return STATUS_INVALID_PARAMETER; + } + + if (fcb->ads) { + fileref = fileref->parent; + fcb = fileref->fcb; + } + + TRACE("%S\n", file_desc(FileObject)); + + ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE); + ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE); + + Status = set_reparse_point2(fcb, rdb, buflen, ccb, fileref, Irp, &rollback); + if (!NT_SUCCESS(Status)) { + ERR("set_reparse_point2 returned %08x\n", Status); + goto end; + } + send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL);
end: diff --git a/drivers/filesystems/btrfs/scrub.c b/drivers/filesystems/btrfs/scrub.c index 9dd7c2008d..f2d3d5e9ed 100644 --- a/drivers/filesystems/btrfs/scrub.c +++ b/drivers/filesystems/btrfs/scrub.c @@ -3190,7 +3190,7 @@ static void scrub_thread(void* context) { while (le != &Vcb->chunks) { chunk* c = CONTAINING_RECORD(le, chunk, list_entry);
- ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
if (!c->readonly) { InsertTailList(&chunks, &c->list_entry_balance); @@ -3198,7 +3198,7 @@ static void scrub_thread(void* context) { Vcb->scrub.chunks_left++; }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb);
le = le->Flink; } diff --git a/drivers/filesystems/btrfs/search.c b/drivers/filesystems/btrfs/search.c index bec1aba420..7333a1e1df 100644 --- a/drivers/filesystems/btrfs/search.c +++ b/drivers/filesystems/btrfs/search.c @@ -496,7 +496,7 @@ void remove_volume_child(_Inout_ _Requires_exclusive_lock_held_(_Curr_->child_lo pdo = vde->pdo; IoDeleteDevice(vde->device);
- if (no_pnp) + if (!no_pnp) IoDeleteDevice(pdo); } } else @@ -540,7 +540,7 @@ void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { TRACE("DeviceType = %u, DeviceNumber = %u, PartitionNumber = %u\n", sdn.DeviceType, sdn.DeviceNumber, sdn.PartitionNumber);
// If we've just added a partition to a whole-disk filesystem, unmount it - if (sdn.DeviceNumber != 0xffffffff) { + if (sdn.DeviceNumber != 0xffffffff && sdn.PartitionNumber != 0) { LIST_ENTRY* le;
ExAcquireResourceExclusiveLite(&pdo_list_lock, TRUE); @@ -823,7 +823,7 @@ static void mountmgr_process_drive(PDEVICE_OBJECT mountmgr, PUNICODE_STRING devi static void mountmgr_updated(PDEVICE_OBJECT mountmgr, MOUNTMGR_MOUNT_POINTS* mmps) { ULONG i;
- static WCHAR pref[] = L"\DosDevices\"; + static const WCHAR pref[] = L"\DosDevices\";
for (i = 0; i < mmps->NumberOfMountPoints; i++) { UNICODE_STRING symlink, device_name; @@ -844,8 +844,8 @@ static void mountmgr_updated(PDEVICE_OBJECT mountmgr, MOUNTMGR_MOUNT_POINTS* mmp device_name.Length = device_name.MaximumLength = 0; }
- if (symlink.Length > wcslen(pref) * sizeof(WCHAR) && - RtlCompareMemory(symlink.Buffer, pref, wcslen(pref) * sizeof(WCHAR)) == wcslen(pref) * sizeof(WCHAR)) + if (symlink.Length > sizeof(pref) - sizeof(WCHAR) && + RtlCompareMemory(symlink.Buffer, pref, sizeof(pref) - sizeof(WCHAR)) == sizeof(pref) - sizeof(WCHAR)) mountmgr_process_drive(mountmgr, &device_name); } } diff --git a/drivers/filesystems/btrfs/send.c b/drivers/filesystems/btrfs/send.c index a865c62c3e..260612a155 100644 --- a/drivers/filesystems/btrfs/send.c +++ b/drivers/filesystems/btrfs/send.c @@ -1648,7 +1648,7 @@ static NTSTATUS wait_for_flush(send_context* context, traverse_ptr* tp1, travers return STATUS_SUCCESS; }
-static NTSTATUS add_ext_holes(LIST_ENTRY* exts, UINT64 size) { +static NTSTATUS add_ext_holes(device_extension* Vcb, LIST_ENTRY* exts, UINT64 size) { UINT64 lastoff = 0; LIST_ENTRY* le;
@@ -1699,7 +1699,7 @@ static NTSTATUS add_ext_holes(LIST_ENTRY* exts, UINT64 size) {
ext2->offset = lastoff; ext2->datalen = offsetof(EXTENT_DATA, data) + sizeof(EXTENT_DATA2); - ext2->data.decoded_size = ed2->num_bytes = size - lastoff; + ext2->data.decoded_size = ed2->num_bytes = sector_align(size - lastoff, Vcb->superblock.sector_size); ext2->data.type = EXTENT_TYPE_REGULAR; ed2->address = ed2->size = ed2->offset = 0;
@@ -2130,13 +2130,13 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr* tp1, traverse return STATUS_SUCCESS;
if (context->parent) { - Status = add_ext_holes(&context->lastinode.exts, context->lastinode.size); + Status = add_ext_holes(context->Vcb, &context->lastinode.exts, context->lastinode.size); if (!NT_SUCCESS(Status)) { ERR("add_ext_holes returned %08x\n", Status); return Status; }
- Status = add_ext_holes(&context->lastinode.oldexts, context->lastinode.size); + Status = add_ext_holes(context->Vcb, &context->lastinode.oldexts, context->lastinode.size); if (!NT_SUCCESS(Status)) { ERR("add_ext_holes returned %08x\n", Status); return Status; @@ -2187,7 +2187,7 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr* tp1, traverse
if (se->data.compression == BTRFS_COMPRESSION_NONE) send_add_tlv(context, BTRFS_SEND_TLV_DATA, se->data.data, (UINT16)se->data.decoded_size); - else if (se->data.compression == BTRFS_COMPRESSION_ZLIB || se->data.compression == BTRFS_COMPRESSION_LZO) { + else if (se->data.compression == BTRFS_COMPRESSION_ZLIB || se->data.compression == BTRFS_COMPRESSION_LZO || se->data.compression == BTRFS_COMPRESSION_ZSTD) { ULONG inlen = se->datalen - (ULONG)offsetof(EXTENT_DATA, data[0]);
send_add_tlv(context, BTRFS_SEND_TLV_DATA, NULL, (UINT16)se->data.decoded_size); @@ -2217,6 +2217,14 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr* tp1, traverse if (se2) ExFreePool(se2); return Status; } + } else if (se->data.compression == BTRFS_COMPRESSION_ZSTD) { + Status = zstd_decompress(se->data.data, inlen, &context->data[context->datalen - se->data.decoded_size], (UINT32)se->data.decoded_size); + if (!NT_SUCCESS(Status)) { + ERR("zlib_decompress returned %08x\n", Status); + ExFreePool(se); + if (se2) ExFreePool(se2); + return Status; + } } } else { ERR("unhandled compression type %x\n", se->data.compression); @@ -2367,7 +2375,7 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr* tp1, traverse offset = se->offset + off; send_add_tlv(context, BTRFS_SEND_TLV_OFFSET, &offset, sizeof(UINT64));
- length = min((UINT16)(context->lastinode.size - se->offset - off), length); + length = (UINT16)min(context->lastinode.size - se->offset - off, length); send_add_tlv(context, BTRFS_SEND_TLV_DATA, buf + skip_start, length);
send_command_finish(context, pos); @@ -2459,6 +2467,16 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr* tp1, traverse if (se2) ExFreePool(se2); return Status; } + } else if (se->data.compression == BTRFS_COMPRESSION_ZSTD) { + Status = zstd_decompress(compbuf, (UINT32)ed2->size, buf, (UINT32)se->data.decoded_size); + if (!NT_SUCCESS(Status)) { + ERR("zstd_decompress returned %08x\n", Status); + ExFreePool(compbuf); + ExFreePool(buf); + ExFreePool(se); + if (se2) ExFreePool(se2); + return Status; + } }
ExFreePool(compbuf); @@ -2494,7 +2512,7 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr* tp1, traverse offset = se->offset + off; send_add_tlv(context, BTRFS_SEND_TLV_OFFSET, &offset, sizeof(UINT64));
- length = min((UINT16)(context->lastinode.size - se->offset - off), length); + length = (UINT16)min(context->lastinode.size - se->offset - off, length); send_add_tlv(context, BTRFS_SEND_TLV_DATA, &buf[off], length);
send_command_finish(context, pos); @@ -2639,7 +2657,8 @@ static NTSTATUS send_extent_data(send_context* context, traverse_ptr* tp, traver return STATUS_INTERNAL_ERROR; }
- if (ed->compression != BTRFS_COMPRESSION_NONE && ed->compression != BTRFS_COMPRESSION_ZLIB && ed->compression != BTRFS_COMPRESSION_LZO) { + if (ed->compression != BTRFS_COMPRESSION_NONE && ed->compression != BTRFS_COMPRESSION_ZLIB && + ed->compression != BTRFS_COMPRESSION_LZO && ed->compression != BTRFS_COMPRESSION_ZSTD) { ERR("unknown compression type %u\n", ed->compression); return STATUS_INTERNAL_ERROR; } @@ -2697,7 +2716,8 @@ static NTSTATUS send_extent_data(send_context* context, traverse_ptr* tp, traver return STATUS_INTERNAL_ERROR; }
- if (ed->compression != BTRFS_COMPRESSION_NONE && ed->compression != BTRFS_COMPRESSION_ZLIB && ed->compression != BTRFS_COMPRESSION_LZO) { + if (ed->compression != BTRFS_COMPRESSION_NONE && ed->compression != BTRFS_COMPRESSION_ZLIB && + ed->compression != BTRFS_COMPRESSION_LZO && ed->compression != BTRFS_COMPRESSION_ZSTD) { ERR("unknown compression type %u\n", ed->compression); return STATUS_INTERNAL_ERROR; } @@ -3730,6 +3750,10 @@ NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG datalen, PFILE_OBJ context = ExAllocatePoolWithTag(NonPagedPool, sizeof(send_context), ALLOC_TAG); if (!context) { ERR("out of memory\n"); + + if (clones) + ExFreePool(clones); + ExReleaseResourceLite(&Vcb->send_load_lock); return STATUS_INSUFFICIENT_RESOURCES; } @@ -3769,6 +3793,10 @@ NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG datalen, PFILE_OBJ ERR("out of memory\n"); ExFreePool(context->data); ExFreePool(context); + + if (clones) + ExFreePool(clones); + ExReleaseResourceLite(&Vcb->send_load_lock); return STATUS_INSUFFICIENT_RESOURCES; } @@ -3794,6 +3822,10 @@ NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG datalen, PFILE_OBJ ExFreePool(send); ExFreePool(context->data); ExFreePool(context); + + if (clones) + ExFreePool(clones); + ExReleaseResourceLite(&Vcb->send_load_lock); return Status; } diff --git a/drivers/filesystems/btrfs/treefuncs.c b/drivers/filesystems/btrfs/treefuncs.c index e2f6001e65..9785e12713 100644 --- a/drivers/filesystems/btrfs/treefuncs.c +++ b/drivers/filesystems/btrfs/treefuncs.c @@ -72,6 +72,7 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT6
if ((t->header.num_items * sizeof(leaf_node)) + sizeof(tree_header) > Vcb->superblock.node_size) { ERR("tree at %llx has more items than expected (%x)\n", t->header.num_items); + ExFreePool(t); ExFreePool(buf); return STATUS_INSUFFICIENT_RESOURCES; } @@ -80,6 +81,7 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT6 td = ExAllocateFromPagedLookasideList(&Vcb->tree_data_lookaside); if (!td) { ERR("out of memory\n"); + ExFreePool(t); ExFreePool(buf); return STATUS_INSUFFICIENT_RESOURCES; } @@ -93,6 +95,8 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT6
if (ln[i].size + sizeof(tree_header) + sizeof(leaf_node) > Vcb->superblock.node_size) { ERR("overlarge item in tree %llx: %u > %u\n", addr, ln[i].size, Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node)); + ExFreeToPagedLookasideList(&t->Vcb->tree_data_lookaside, td); + ExFreePool(t); ExFreePool(buf); return STATUS_INTERNAL_ERROR; } @@ -114,6 +118,7 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT6
if ((t->header.num_items * sizeof(internal_node)) + sizeof(tree_header) > Vcb->superblock.node_size) { ERR("tree at %llx has more items than expected (%x)\n", t->header.num_items); + ExFreePool(t); ExFreePool(buf); return STATUS_INSUFFICIENT_RESOURCES; } @@ -122,6 +127,7 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT6 td = ExAllocateFromPagedLookasideList(&Vcb->tree_data_lookaside); if (!td) { ERR("out of memory\n"); + ExFreePool(t); ExFreePool(buf); return STATUS_INSUFFICIENT_RESOURCES; } @@ -1096,7 +1102,7 @@ void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) { rollback_space* rs = ri->ptr;
if (rs->chunk) - ExAcquireResourceExclusiveLite(&rs->chunk->lock, TRUE); + acquire_chunk_lock(rs->chunk, Vcb);
if (ri->type == ROLLBACK_ADD_SPACE) space_list_subtract2(rs->list, rs->list_size, rs->address, rs->length, NULL, NULL); @@ -1138,7 +1144,7 @@ void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) { le2 = le3; }
- ExReleaseResourceLite(&rs->chunk->lock); + release_chunk_lock(rs->chunk, Vcb); }
ExFreePool(rs); @@ -1509,6 +1515,7 @@ static NTSTATUS handle_batch_collision(device_extension* Vcb, batch_item* bi, tr td2 = ExAllocateFromPagedLookasideList(&Vcb->tree_data_lookaside); if (!td2) { ERR("out of memory\n"); + ExFreePool(newdi); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -1595,6 +1602,7 @@ static NTSTATUS handle_batch_collision(device_extension* Vcb, batch_item* bi, tr td2 = ExAllocateFromPagedLookasideList(&Vcb->tree_data_lookaside); if (!td2) { ERR("out of memory\n"); + ExFreePool(newir); return STATUS_INSUFFICIENT_RESOURCES; }
diff --git a/drivers/filesystems/btrfs/volume.c b/drivers/filesystems/btrfs/volume.c index 5f7516a5c2..fa33221b7c 100644 --- a/drivers/filesystems/btrfs/volume.c +++ b/drivers/filesystems/btrfs/volume.c @@ -53,6 +53,8 @@ NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
Irp->IoStatus.Information = 0;
+ ExAcquireResourceExclusiveLite(&pdo_list_lock, TRUE); + ExAcquireResourceSharedLite(&pdode->child_lock, TRUE);
if (InterlockedDecrement(&vde->open_count) == 0 && vde->removing) { @@ -83,16 +85,20 @@ NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
ExReleaseResourceLite(&pdode->child_lock); ExDeleteResourceLite(&pdode->child_lock); - IoDetachDevice(vde->pdo); + + if (vde->pdo->AttachedDevice) + IoDetachDevice(vde->pdo);
pdo = vde->pdo; IoDeleteDevice(vde->device);
- if (no_pnp) + if (!no_pnp) IoDeleteDevice(pdo); } else ExReleaseResourceLite(&pdode->child_lock);
+ ExReleaseResourceLite(&pdo_list_lock); + return STATUS_SUCCESS; }
@@ -971,7 +977,7 @@ static BOOL allow_degraded_mount(BTRFS_UUID* uuid) { }
adus.Buffer = L"AllowDegraded"; - adus.Length = adus.MaximumLength = (USHORT)(wcslen(adus.Buffer) * sizeof(WCHAR)); + adus.Length = adus.MaximumLength = sizeof(adus.Buffer) - sizeof(WCHAR);
if (NT_SUCCESS(ZwQueryValueKey(h, &adus, KeyValueFullInformation, kvfi, kvfilen, &retlen))) { if (kvfi->Type == REG_DWORD && kvfi->DataLength >= sizeof(UINT32)) { diff --git a/drivers/filesystems/btrfs/write.c b/drivers/filesystems/btrfs/write.c index 6292d7efb0..ed1df4c897 100644 --- a/drivers/filesystems/btrfs/write.c +++ b/drivers/filesystems/btrfs/write.c @@ -404,10 +404,6 @@ NTSTATUS alloc_chunk(device_extension* Vcb, UINT64 flags, chunk** pc, BOOL full_ return STATUS_INTERNAL_ERROR; }
- max_chunk_size = min(max_chunk_size, total_size / 10); // cap at 10% - - TRACE("would allocate a new chunk of %llx bytes and stripe %llx\n", max_chunk_size, max_stripe_size); - if (flags & BLOCK_FLAG_DUPLICATE) { min_stripes = 2; max_stripes = 2; @@ -452,6 +448,13 @@ NTSTATUS alloc_chunk(device_extension* Vcb, UINT64 flags, chunk** pc, BOOL full_ allowed_missing = 0; }
+ if (max_chunk_size > total_size / 10) { // cap at 10% + max_chunk_size = total_size / 10; + max_stripe_size = max_chunk_size / min_stripes; + } + + TRACE("would allocate a new chunk of %llx bytes and stripe %llx\n", max_chunk_size, max_stripe_size); + stripes = ExAllocatePoolWithTag(PagedPool, sizeof(stripe) * max_stripes, ALLOC_TAG); if (!stripes) { ERR("out of memory\n"); @@ -511,6 +514,8 @@ NTSTATUS alloc_chunk(device_extension* Vcb, UINT64 flags, chunk** pc, BOOL full_ goto end; }
+ c->devices = NULL; + cisize = sizeof(CHUNK_ITEM) + (num_stripes * sizeof(CHUNK_ITEM_STRIPE)); c->chunk_item = ExAllocatePoolWithTag(NonPagedPool, cisize, ALLOC_TAG); if (!c->chunk_item) { @@ -549,7 +554,8 @@ NTSTATUS alloc_chunk(device_extension* Vcb, UINT64 flags, chunk** pc, BOOL full_ stripe_size -= stripe_size % stripe_length;
if (stripe_size == 0) { - Status = STATUS_INTERNAL_ERROR; + ERR("not enough free space found (stripe_size == 0)\n"); + Status = STATUS_DISK_FULL; goto end; }
@@ -1287,7 +1293,8 @@ static NTSTATUS prepare_raid5_write(device_extension* Vcb, chunk* c, UINT64 addr stripes[i].mdl = IoAllocateMdl((UINT8*)MmGetMdlVirtualAddress(master_mdl) + irp_offset, (ULONG)(stripes[i].end - stripes[i].start), FALSE, FALSE, NULL); if (!stripes[i].mdl) { ERR("IoAllocateMdl failed\n"); - return STATUS_INSUFFICIENT_RESOURCES; + Status = STATUS_INSUFFICIENT_RESOURCES; + goto exit; } } } @@ -1702,7 +1709,8 @@ static NTSTATUS prepare_raid6_write(device_extension* Vcb, chunk* c, UINT64 addr stripes[i].mdl = IoAllocateMdl((UINT8*)MmGetMdlVirtualAddress(master_mdl) + irp_offset, (ULONG)(stripes[i].end - stripes[i].start), FALSE, FALSE, NULL); if (!stripes[i].mdl) { ERR("IoAllocateMdl failed\n"); - return STATUS_INSUFFICIENT_RESOURCES; + Status = STATUS_INSUFFICIENT_RESOURCES; + goto exit; } } } @@ -1880,7 +1888,6 @@ NTSTATUS write_data(_In_ device_extension* Vcb, _In_ UINT64 address, _In_reads_b NTSTATUS Status; UINT32 i; CHUNK_ITEM_STRIPE* cis; - write_data_stripe* stripe; write_stripe* stripes = NULL; UINT64 total_writing = 0; ULONG allowed_missing, missing; @@ -2001,6 +2008,7 @@ NTSTATUS write_data(_In_ device_extension* Vcb, _In_ UINT64 address, _In_reads_b }
for (i = 0; i < c->chunk_item->num_stripes; i++) { + write_data_stripe* stripe; PIO_STACK_LOCATION IrpSp;
stripe = ExAllocatePoolWithTag(NonPagedPool, sizeof(write_data_stripe), ALLOC_TAG); @@ -2028,6 +2036,7 @@ NTSTATUS write_data(_In_ device_extension* Vcb, _In_ UINT64 address, _In_reads_b
if (!stripe->Irp) { ERR("IoAllocateIrp failed\n"); + ExFreePool(stripe); Status = STATUS_INSUFFICIENT_RESOURCES; goto end; } @@ -2036,6 +2045,7 @@ NTSTATUS write_data(_In_ device_extension* Vcb, _In_ UINT64 address, _In_reads_b
if (!stripe->Irp) { ERR("IoMakeAssociatedIrp failed\n"); + ExFreePool(stripe); Status = STATUS_INSUFFICIENT_RESOURCES; goto end; } @@ -2333,10 +2343,9 @@ void free_write_data_stripes(write_data_context* wtc) {
last_mdl = stripe->mdl;
-#ifdef __REACTOS__ if (stripe->Irp) IoFreeIrp(stripe->Irp); -#endif + le = le->Flink; }
@@ -2888,7 +2897,7 @@ BOOL insert_extent_chunk(_In_ device_extension* Vcb, _In_ fcb* fcb, _In_ chunk*
ExReleaseResourceLite(&c->changed_extents_lock);
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb);
if (data) { Status = write_data_complete(Vcb, address, data, (UINT32)length, Irp, NULL, file_write, irp_offset, @@ -2949,10 +2958,10 @@ static BOOL try_extend_data(device_extension* Vcb, fcb* fcb, UINT64 start_data, if (c->reloc || c->readonly || c->chunk_item->type != Vcb->data_flags) return FALSE;
- ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
if (length > c->chunk_item->size - c->used) { - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); return FALSE; }
@@ -2961,7 +2970,7 @@ static BOOL try_extend_data(device_extension* Vcb, fcb* fcb, UINT64 start_data,
if (!NT_SUCCESS(Status)) { ERR("load_cache_chunk returned %08x\n", Status); - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); return FALSE; } } @@ -2978,7 +2987,7 @@ static BOOL try_extend_data(device_extension* Vcb, fcb* fcb, UINT64 start_data, if (success) *written += newlen; else - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb);
return success; } else if (s->address > ed2->address + ed2->size) @@ -2987,7 +2996,7 @@ static BOOL try_extend_data(device_extension* Vcb, fcb* fcb, UINT64 start_data, le = le->Flink; }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb);
return FALSE; } @@ -3017,7 +3026,7 @@ static NTSTATUS insert_chunk_fragmented(fcb* fcb, UINT64 start, UINT64 length, U c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly && !c->reloc) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == flags) { while (!IsListEmpty(&c->space_size) && length > 0) { @@ -3029,12 +3038,12 @@ static NTSTATUS insert_chunk_fragmented(fcb* fcb, UINT64 start, UINT64 length, U length -= extlen; if (data) data += extlen;
- ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, fcb->Vcb); } } }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, fcb->Vcb);
if (length == 0) break; @@ -3067,7 +3076,7 @@ static NTSTATUS insert_prealloc_extent(fcb* fcb, UINT64 start, UINT64 length, LI c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly && !c->reloc) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == flags && (c->chunk_item->size - c->used) >= extlen) { if (insert_extent_chunk(fcb->Vcb, fcb, c, start, extlen, !page_file, NULL, NULL, rollback, BTRFS_COMPRESSION_NONE, extlen, FALSE, 0)) { @@ -3076,7 +3085,7 @@ static NTSTATUS insert_prealloc_extent(fcb* fcb, UINT64 start, UINT64 length, LI } }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, fcb->Vcb); }
le = le->Flink; @@ -3095,14 +3104,14 @@ static NTSTATUS insert_prealloc_extent(fcb* fcb, UINT64 start, UINT64 length, LI goto end; }
- ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == flags && (c->chunk_item->size - c->used) >= extlen) { if (insert_extent_chunk(fcb->Vcb, fcb, c, start, extlen, !page_file, NULL, NULL, rollback, BTRFS_COMPRESSION_NONE, extlen, FALSE, 0)) goto cont; }
- ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, fcb->Vcb);
Status = insert_chunk_fragmented(fcb, start, length, NULL, TRUE, rollback); if (!NT_SUCCESS(Status)) @@ -3159,7 +3168,7 @@ static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, UINT64 start_data c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly && !c->reloc) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
if (c->chunk_item->type == flags && (c->chunk_item->size - c->used) >= newlen && insert_extent_chunk(Vcb, fcb, c, start_data, newlen, FALSE, data, Irp, rollback, BTRFS_COMPRESSION_NONE, newlen, file_write, irp_offset)) { @@ -3177,7 +3186,7 @@ static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, UINT64 start_data break; } } else - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); }
le = le->Flink; @@ -3201,7 +3210,7 @@ static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, UINT64 start_data }
if (c) { - ExAcquireResourceExclusiveLite(&c->lock, TRUE); + acquire_chunk_lock(c, Vcb);
if (c->chunk_item->type == flags && (c->chunk_item->size - c->used) >= newlen && insert_extent_chunk(Vcb, fcb, c, start_data, newlen, FALSE, data, Irp, rollback, BTRFS_COMPRESSION_NONE, newlen, file_write, irp_offset)) { @@ -3217,7 +3226,7 @@ static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, UINT64 start_data data = &((UINT8*)data)[newlen]; } } else - ExReleaseResourceLite(&c->lock); + release_chunk_lock(c, Vcb); }
if (!done) { @@ -3642,6 +3651,8 @@ static NTSTATUS do_write_file_prealloc(fcb* fcb, extent* ext, UINT64 start_data, Irp, NULL, file_write, irp_offset + ext->offset - start_data, priority); if (!NT_SUCCESS(Status)) { ERR("write_data_complete returned %08x\n", Status); + ExFreePool(newext1); + ExFreePool(newext2); return Status; }
@@ -3737,6 +3748,8 @@ static NTSTATUS do_write_file_prealloc(fcb* fcb, extent* ext, UINT64 start_data, Status = write_data_complete(fcb->Vcb, ed2->address + ned2->offset, data, (UINT32)ned2->num_bytes, Irp, NULL, file_write, irp_offset, priority); if (!NT_SUCCESS(Status)) { ERR("write_data_complete returned %08x\n", Status); + ExFreePool(newext1); + ExFreePool(newext2); return Status; }
diff --git a/drivers/filesystems/btrfs/zstd/bitstream.h b/drivers/filesystems/btrfs/zstd/bitstream.h new file mode 100644 index 0000000000..ef89b9878e --- /dev/null +++ b/drivers/filesystems/btrfs/zstd/bitstream.h @@ -0,0 +1,455 @@ +/* ****************************************************************** + bitstream + Part of FSE library + Copyright (C) 2013-present, Yann Collet. + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - Source repository : https://github.com/Cyan4973/FiniteStateEntropy +****************************************************************** */ +#ifndef BITSTREAM_H_MODULE +#define BITSTREAM_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif + +/* +* This API consists of small unitary functions, which must be inlined for best performance. +* Since link-time-optimization is not available for all compilers, +* these functions are defined into a .h to be included. +*/ + +/*-**************************************** +* Dependencies +******************************************/ +#include "mem.h" /* unaligned access routines */ +#include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */ +#include "error_private.h" /* error codes and messages */ + + +/*========================================= +* Target specific +=========================================*/ +#if defined(__BMI__) && defined(__GNUC__) +# include <immintrin.h> /* support for bextr (experimental) */ +#endif + +#define STREAM_ACCUMULATOR_MIN_32 25 +#define STREAM_ACCUMULATOR_MIN_64 57 +#define STREAM_ACCUMULATOR_MIN ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64)) + + +/*-****************************************** +* bitStream encoding API (write forward) +********************************************/ +/* bitStream can mix input from multiple sources. + * A critical property of these streams is that they encode and decode in **reverse** direction. + * So the first bit sequence you add will be the last to be read, like a LIFO stack. + */ +typedef struct { + size_t bitContainer; + unsigned bitPos; + char* startPtr; + char* ptr; + char* endPtr; +} BIT_CStream_t; + +MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity); +MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits); +MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC); +MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC); + +/* Start with initCStream, providing the size of buffer to write into. +* bitStream will never write outside of this buffer. +* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code. +* +* bits are first added to a local register. +* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems. +* Writing data into memory is an explicit operation, performed by the flushBits function. +* Hence keep track how many bits are potentially stored into local register to avoid register overflow. +* After a flushBits, a maximum of 7 bits might still be stored into local register. +* +* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers. +* +* Last operation is to close the bitStream. +* The function returns the final size of CStream in bytes. +* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable) +*/ + + +/*-******************************************** +* bitStream decoding API (read backward) +**********************************************/ +typedef struct { + size_t bitContainer; + unsigned bitsConsumed; + const char* ptr; + const char* start; + const char* limitPtr; +} BIT_DStream_t; + +typedef enum { BIT_DStream_unfinished = 0, + BIT_DStream_endOfBuffer = 1, + BIT_DStream_completed = 2, + BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */ + /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */ + +MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize); +MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits); +MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD); +MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD); + + +/* Start by invoking BIT_initDStream(). +* A chunk of the bitStream is then stored into a local register. +* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). +* You can then retrieve bitFields stored into the local register, **in reverse order**. +* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method. +* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished. +* Otherwise, it can be less than that, so proceed accordingly. +* Checking if DStream has reached its end can be performed with BIT_endOfDStream(). +*/ + + +/*-**************************************** +* unsafe API +******************************************/ +MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits); +/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */ + +MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC); +/* unsafe version; does not check buffer overflow */ + +MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); +/* faster, but works only if nbBits >= 1 */ + + + +/*-************************************************************** +* Internal functions +****************************************************************/ +MEM_STATIC unsigned BIT_highbit32 (U32 val) +{ + assert(val != 0); + { +# if defined(_MSC_VER) /* Visual */ + unsigned long r=0; + _BitScanReverse ( &r, val ); + return (unsigned) r; +# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ + return 31 - __builtin_clz (val); +# else /* Software version */ + static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, + 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, + 19, 27, 23, 6, 26, 5, 4, 31 }; + U32 v = val; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27]; +# endif + } +} + +/*===== Local Constants =====*/ +static const unsigned BIT_mask[] = { + 0, 1, 3, 7, 0xF, 0x1F, + 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, + 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, + 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, + 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF, + 0x3FFFFFFF, 0x7FFFFFFF}; /* up to 31 bits */ +#define BIT_MASK_SIZE (sizeof(BIT_mask) / sizeof(BIT_mask[0])) + +/*-************************************************************** +* bitStream encoding +****************************************************************/ +/*! BIT_initCStream() : + * `dstCapacity` must be > sizeof(size_t) + * @return : 0 if success, + * otherwise an error code (can be tested using ERR_isError()) */ +MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, + void* startPtr, size_t dstCapacity) +{ + bitC->bitContainer = 0; + bitC->bitPos = 0; + bitC->startPtr = (char*)startPtr; + bitC->ptr = bitC->startPtr; + bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer); + if (dstCapacity <= sizeof(bitC->bitContainer)) return ERROR(dstSize_tooSmall); + return 0; +} + +/*! BIT_addBits() : + * can add up to 31 bits into `bitC`. + * Note : does not check for register overflow ! */ +MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, + size_t value, unsigned nbBits) +{ + MEM_STATIC_ASSERT(BIT_MASK_SIZE == 32); + assert(nbBits < BIT_MASK_SIZE); + assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); + bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos; + bitC->bitPos += nbBits; +} + +/*! BIT_addBitsFast() : + * works only if `value` is _clean_, + * meaning all high bits above nbBits are 0 */ +MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, + size_t value, unsigned nbBits) +{ + assert((value>>nbBits) == 0); + assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); + bitC->bitContainer |= value << bitC->bitPos; + bitC->bitPos += nbBits; +} + +/*! BIT_flushBitsFast() : + * assumption : bitContainer has not overflowed + * unsafe version; does not check buffer overflow */ +MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC) +{ + size_t const nbBytes = bitC->bitPos >> 3; + assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8); + MEM_writeLEST(bitC->ptr, bitC->bitContainer); + bitC->ptr += nbBytes; + assert(bitC->ptr <= bitC->endPtr); + bitC->bitPos &= 7; + bitC->bitContainer >>= nbBytes*8; +} + +/*! BIT_flushBits() : + * assumption : bitContainer has not overflowed + * safe version; check for buffer overflow, and prevents it. + * note : does not signal buffer overflow. + * overflow will be revealed later on using BIT_closeCStream() */ +MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC) +{ + size_t const nbBytes = bitC->bitPos >> 3; + assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8); + MEM_writeLEST(bitC->ptr, bitC->bitContainer); + bitC->ptr += nbBytes; + if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr; + bitC->bitPos &= 7; + bitC->bitContainer >>= nbBytes*8; +} + +/*! BIT_closeCStream() : + * @return : size of CStream, in bytes, + * or 0 if it could not fit into dstBuffer */ +MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC) +{ + BIT_addBitsFast(bitC, 1, 1); /* endMark */ + BIT_flushBits(bitC); + if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */ + return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0); +} + + +/*-******************************************************** +* bitStream decoding +**********************************************************/ +/*! BIT_initDStream() : + * Initialize a BIT_DStream_t. + * `bitD` : a pointer to an already allocated BIT_DStream_t structure. + * `srcSize` must be the *exact* size of the bitStream, in bytes. + * @return : size of stream (== srcSize), or an errorCode if a problem is detected + */ +MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize) +{ + if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } + + bitD->start = (const char*)srcBuffer; + bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer); + + if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */ + bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer); + bitD->bitContainer = MEM_readLEST(bitD->ptr); + { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; + bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */ + if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ } + } else { + bitD->ptr = bitD->start; + bitD->bitContainer = *(const BYTE*)(bitD->start); + switch(srcSize) + { + case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16); + /* fall-through */ + + case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24); + /* fall-through */ + + case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32); + /* fall-through */ + + case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24; + /* fall-through */ + + case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16; + /* fall-through */ + + case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8; + /* fall-through */ + + default: break; + } + { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; + bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; + if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */ + } + bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8; + } + + return srcSize; +} + +MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start) +{ + return bitContainer >> start; +} + +MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits) +{ + U32 const regMask = sizeof(bitContainer)*8 - 1; + /* if start > regMask, bitstream is corrupted, and result is undefined */ + assert(nbBits < BIT_MASK_SIZE); + return (bitContainer >> (start & regMask)) & BIT_mask[nbBits]; +} + +MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) +{ + assert(nbBits < BIT_MASK_SIZE); + return bitContainer & BIT_mask[nbBits]; +} + +/*! BIT_lookBits() : + * Provides next n bits from local register. + * local register is not modified. + * On 32-bits, maxNbBits==24. + * On 64-bits, maxNbBits==56. + * @return : value extracted */ +MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits) +{ + /* arbitrate between double-shift and shift+mask */ +#if 1 + /* if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8, + * bitstream is likely corrupted, and result is undefined */ + return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) - bitD->bitsConsumed - nbBits, nbBits); +#else ... 20921 lines suppressed ...