[BTRFS][UBTRFS][SHELLBTRFS] Upgrade to 1.8.1 (#4729)

CORE-18322

v1.8.1 (2022-08-23):
- Fixed use-after-free when flushing
- Fixed crash when opening volume when AppLocker installed
- Compression now disabled for no-COW files, as on Linux
- Flushing now scales better on very fast drives
- Fixed small files getting padded to 4,096 bytes by lazy writer
- Added NoDataCOW registry option
This commit is contained in:
Johannes Obermayr 2022-09-28 18:08:10 +02:00 committed by GitHub
parent 22d8c0fd54
commit 29d1938258
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 319 additions and 115 deletions

View File

@ -597,6 +597,16 @@ void BtrfsPropSheet::change_inode_flag(HWND hDlg, uint64_t flag, UINT state) {
flags_set = ~flag; flags_set = ~flag;
} }
if (flags & BTRFS_INODE_NODATACOW && flags_set & BTRFS_INODE_NODATACOW) {
EnableWindow(GetDlgItem(hDlg, IDC_COMPRESS), false);
EnableWindow(GetDlgItem(hDlg, IDC_COMPRESS_TYPE), false);
} else {
EnableWindow(GetDlgItem(hDlg, IDC_COMPRESS), true);
EnableWindow(GetDlgItem(hDlg, IDC_COMPRESS_TYPE), flags & BTRFS_INODE_COMPRESS && flags_set & BTRFS_INODE_COMPRESS);
}
EnableWindow(GetDlgItem(hDlg, IDC_NODATACOW), !(flags & BTRFS_INODE_COMPRESS) || !(flags_set & BTRFS_INODE_COMPRESS));
flags_changed = true; flags_changed = true;
SendMessageW(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0); SendMessageW(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0);
@ -995,6 +1005,11 @@ void BtrfsPropSheet::init_propsheet(HWND hwndDlg) {
set_check_box(hwndDlg, IDC_NODATACOW, min_flags & BTRFS_INODE_NODATACOW, max_flags & BTRFS_INODE_NODATACOW); set_check_box(hwndDlg, IDC_NODATACOW, min_flags & BTRFS_INODE_NODATACOW, max_flags & BTRFS_INODE_NODATACOW);
set_check_box(hwndDlg, IDC_COMPRESS, min_flags & BTRFS_INODE_COMPRESS, max_flags & BTRFS_INODE_COMPRESS); set_check_box(hwndDlg, IDC_COMPRESS, min_flags & BTRFS_INODE_COMPRESS, max_flags & BTRFS_INODE_COMPRESS);
if (min_flags & BTRFS_INODE_NODATACOW || max_flags & BTRFS_INODE_NODATACOW)
EnableWindow(GetDlgItem(hwndDlg, IDC_COMPRESS), false);
else if (min_flags & BTRFS_INODE_COMPRESS || max_flags & BTRFS_INODE_COMPRESS)
EnableWindow(GetDlgItem(hwndDlg, IDC_NODATACOW), false);
comptype = GetDlgItem(hwndDlg, IDC_COMPRESS_TYPE); comptype = GetDlgItem(hwndDlg, IDC_COMPRESS_TYPE);
while (SendMessageW(comptype, CB_GETCOUNT, 0, 0) > 0) { while (SendMessageW(comptype, CB_GETCOUNT, 0, 0) > 0) {

View File

@ -61,8 +61,8 @@ IDI_ICON1 ICON "subvol.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,8,0,0 FILEVERSION 1,8,1,0
PRODUCTVERSION 1,8,0,0 PRODUCTVERSION 1,8,1,0
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -78,12 +78,12 @@ BEGIN
BLOCK "080904b0" BLOCK "080904b0"
BEGIN BEGIN
VALUE "FileDescription", "WinBtrfs shell extension" VALUE "FileDescription", "WinBtrfs shell extension"
VALUE "FileVersion", "1.8.0" VALUE "FileVersion", "1.8.1"
VALUE "InternalName", "btrfs" VALUE "InternalName", "btrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-22" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-22"
VALUE "OriginalFilename", "shellbtrfs.dll" VALUE "OriginalFilename", "shellbtrfs.dll"
VALUE "ProductName", "WinBtrfs" VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "1.8.0" VALUE "ProductVersion", "1.8.1"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -51,8 +51,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,8,0,0 FILEVERSION 1,8,1,0
PRODUCTVERSION 1,8,0,0 PRODUCTVERSION 1,8,1,0
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -68,12 +68,12 @@ BEGIN
BLOCK "080904b0" BLOCK "080904b0"
BEGIN BEGIN
VALUE "FileDescription", "Btrfs utility DLL" VALUE "FileDescription", "Btrfs utility DLL"
VALUE "FileVersion", "1.8.0" VALUE "FileVersion", "1.8.1"
VALUE "InternalName", "ubtrfs" VALUE "InternalName", "ubtrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-22" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-22"
VALUE "OriginalFilename", "ubtrfs.dll" VALUE "OriginalFilename", "ubtrfs.dll"
VALUE "ProductName", "WinBtrfs" VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "1.8.0" VALUE "ProductVersion", "1.8.1"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -83,6 +83,7 @@ uint32_t mount_clear_cache = 0;
uint32_t mount_allow_degraded = 0; uint32_t mount_allow_degraded = 0;
uint32_t mount_readonly = 0; uint32_t mount_readonly = 0;
uint32_t mount_no_root_dir = 0; uint32_t mount_no_root_dir = 0;
uint32_t mount_nodatacow = 0;
uint32_t no_pnp = 0; uint32_t no_pnp = 0;
bool log_started = false; bool log_started = false;
UNICODE_STRING log_device, log_file, registry_path; UNICODE_STRING log_device, log_file, registry_path;
@ -645,6 +646,36 @@ static void calculate_total_space(_In_ device_extension* Vcb, _Out_ uint64_t* to
} }
#ifndef __REACTOS__ #ifndef __REACTOS__
// simplified version of FsRtlAreNamesEqual, which can be a bottleneck!
static bool compare_strings(const UNICODE_STRING* us1, const UNICODE_STRING* us2) {
if (us1->Length != us2->Length)
return false;
WCHAR* s1 = us1->Buffer;
WCHAR* s2 = us2->Buffer;
for (unsigned int i = 0; i < us1->Length; i++) {
WCHAR c1 = *s1;
WCHAR c2 = *s2;
if (c1 != c2) {
if (c1 >= 'a' && c1 <= 'z')
c1 = c1 - 'a' + 'A';
if (c2 >= 'a' && c2 <= 'z')
c2 = c2 - 'a' + 'A';
if (c1 != c2)
return false;
}
s1++;
s2++;
}
return true;
}
#define INIT_UNICODE_STRING(var, val) UNICODE_STRING us##var; us##var.Buffer = (WCHAR*)val; us##var.Length = us##var.MaximumLength = sizeof(val) - sizeof(WCHAR); #define INIT_UNICODE_STRING(var, val) UNICODE_STRING us##var; us##var.Buffer = (WCHAR*)val; us##var.Length = us##var.MaximumLength = sizeof(val) - sizeof(WCHAR);
// This function exists because we have to lie about our FS type in certain situations. // This function exists because we have to lie about our FS type in certain situations.
@ -707,7 +738,7 @@ static bool lie_about_fs_type() {
name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usmpr.Length) / sizeof(WCHAR)]; name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usmpr.Length) / sizeof(WCHAR)];
name.Length = name.MaximumLength = usmpr.Length; name.Length = name.MaximumLength = usmpr.Length;
blacklist = FsRtlAreNamesEqual(&name, &usmpr, true, NULL); blacklist = compare_strings(&name, &usmpr);
} }
if (!blacklist && entry->FullDllName.Length >= uscmd.Length) { if (!blacklist && entry->FullDllName.Length >= uscmd.Length) {
@ -716,7 +747,7 @@ static bool lie_about_fs_type() {
name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - uscmd.Length) / sizeof(WCHAR)]; name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - uscmd.Length) / sizeof(WCHAR)];
name.Length = name.MaximumLength = uscmd.Length; name.Length = name.MaximumLength = uscmd.Length;
blacklist = FsRtlAreNamesEqual(&name, &uscmd, true, NULL); blacklist = compare_strings(&name, &uscmd);
} }
if (!blacklist && entry->FullDllName.Length >= usfsutil.Length) { if (!blacklist && entry->FullDllName.Length >= usfsutil.Length) {
@ -725,7 +756,7 @@ static bool lie_about_fs_type() {
name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usfsutil.Length) / sizeof(WCHAR)]; name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usfsutil.Length) / sizeof(WCHAR)];
name.Length = name.MaximumLength = usfsutil.Length; name.Length = name.MaximumLength = usfsutil.Length;
blacklist = FsRtlAreNamesEqual(&name, &usfsutil, true, NULL); blacklist = compare_strings(&name, &usfsutil);
} }
if (!blacklist && entry->FullDllName.Length >= usstorsvc.Length) { if (!blacklist && entry->FullDllName.Length >= usstorsvc.Length) {
@ -734,7 +765,7 @@ static bool lie_about_fs_type() {
name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usstorsvc.Length) / sizeof(WCHAR)]; name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usstorsvc.Length) / sizeof(WCHAR)];
name.Length = name.MaximumLength = usstorsvc.Length; name.Length = name.MaximumLength = usstorsvc.Length;
blacklist = FsRtlAreNamesEqual(&name, &usstorsvc, true, NULL); blacklist = compare_strings(&name, &usstorsvc);
} }
if (!blacklist && entry->FullDllName.Length >= usifstest.Length) { if (!blacklist && entry->FullDllName.Length >= usifstest.Length) {
@ -743,7 +774,7 @@ static bool lie_about_fs_type() {
name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usifstest.Length) / sizeof(WCHAR)]; name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usifstest.Length) / sizeof(WCHAR)];
name.Length = name.MaximumLength = usifstest.Length; name.Length = name.MaximumLength = usifstest.Length;
blacklist = FsRtlAreNamesEqual(&name, &usifstest, true, NULL); blacklist = compare_strings(&name, &usifstest);
} }
if (blacklist) { if (blacklist) {
@ -5943,60 +5974,33 @@ static void init_serial(bool first_time) {
#if !defined(__REACTOS__) && (defined(_X86_) || defined(_AMD64_)) #if !defined(__REACTOS__) && (defined(_X86_) || defined(_AMD64_))
static void check_cpu() { static void check_cpu() {
bool have_sse2 = false, have_sse42 = false, have_avx2 = false; bool have_sse2 = false, have_sse42 = false, have_avx2 = false;
int cpu_info[4];
#ifndef _MSC_VER __cpuid(cpu_info, 1);
{ have_sse42 = cpu_info[2] & (1 << 20);
uint32_t eax, ebx, ecx, edx; have_sse2 = cpu_info[3] & (1 << 26);
__cpuid(1, eax, ebx, ecx, edx); __cpuidex(cpu_info, 7, 0);
have_avx2 = cpu_info[1] & (1 << 5);
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) { if (have_avx2) {
have_sse42 = ecx & bit_SSE4_2; // check Windows has enabled AVX2 - Windows 10 doesn't immediately
have_sse2 = edx & bit_SSE2;
}
if (__get_cpuid_count(7, 0, &eax, &ebx, &ecx, &edx)) if (__readcr4() & (1 << 18)) {
have_avx2 = ebx & bit_AVX2; uint32_t xcr0;
if (have_avx2) { #ifdef _MSC_VER
// check Windows has enabled AVX2 - Windows 10 doesn't immediately xcr0 = (uint32_t)_xgetbv(0);
if (__readcr4() & (1 << 18)) {
uint32_t xcr0;
__asm__("xgetbv" : "=a" (xcr0) : "c" (0) : "edx" );
if ((xcr0 & 6) != 6)
have_avx2 = false;
} else
have_avx2 = false;
}
}
#else #else
{ __asm__("xgetbv" : "=a" (xcr0) : "c" (0) : "edx");
unsigned int cpu_info[4];
__cpuid(cpu_info, 1);
have_sse42 = cpu_info[2] & (1 << 20);
have_sse2 = cpu_info[3] & (1 << 26);
__cpuidex(cpu_info, 7, 0);
have_avx2 = cpu_info[1] & (1 << 5);
if (have_avx2) {
// check Windows has enabled AVX2 - Windows 10 doesn't immediately
if (__readcr4() & (1 << 18)) {
uint32_t xcr0 = (uint32_t)_xgetbv(0);
if ((xcr0 & 6) != 6)
have_avx2 = false;
} else
have_avx2 = false;
}
}
#endif #endif
if ((xcr0 & 6) != 6)
have_avx2 = false;
} else
have_avx2 = false;
}
if (have_sse42) { if (have_sse42) {
TRACE("SSE4.2 is supported\n"); TRACE("SSE4.2 is supported\n");
calc_crc32c = calc_crc32c_hw; calc_crc32c = calc_crc32c_hw;

View File

@ -10,7 +10,7 @@ Signature = "$Windows NT$"
Class = Volume Class = Volume
ClassGuid = {71a27cdd-812a-11d0-bec7-08002be2092f} ClassGuid = {71a27cdd-812a-11d0-bec7-08002be2092f}
Provider = %Me% Provider = %Me%
DriverVer = 03/12/2022,1.8.0 DriverVer = 08/23/2022,1.8.1
CatalogFile = btrfs.cat CatalogFile = btrfs.cat
[DestinationDirs] [DestinationDirs]

View File

@ -51,8 +51,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,8,0,0 FILEVERSION 1,8,1,0
PRODUCTVERSION 1,8,0,0 PRODUCTVERSION 1,8,1,0
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -68,12 +68,12 @@ BEGIN
BLOCK "080904b0" BLOCK "080904b0"
BEGIN BEGIN
VALUE "FileDescription", "WinBtrfs" VALUE "FileDescription", "WinBtrfs"
VALUE "FileVersion", "1.8.0" VALUE "FileVersion", "1.8.1"
VALUE "InternalName", "btrfs" VALUE "InternalName", "btrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-22" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-22"
VALUE "OriginalFilename", "btrfs.sys" VALUE "OriginalFilename", "btrfs.sys"
VALUE "ProductName", "WinBtrfs" VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "1.8.0" VALUE "ProductVersion", "1.8.1"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -492,8 +492,15 @@ typedef struct {
} batch_item; } batch_item;
typedef struct { typedef struct {
root* r; KEY key;
LIST_ENTRY items; LIST_ENTRY items;
unsigned int num_items;
LIST_ENTRY list_entry;
} batch_item_ind;
typedef struct {
root* r;
LIST_ENTRY items_ind;
LIST_ENTRY list_entry; LIST_ENTRY list_entry;
} batch_root; } batch_root;
@ -674,6 +681,7 @@ typedef struct {
bool clear_cache; bool clear_cache;
bool allow_degraded; bool allow_degraded;
bool no_root_dir; bool no_root_dir;
bool nodatacow;
} mount_options; } mount_options;
#define VCB_TYPE_FS 1 #define VCB_TYPE_FS 1
@ -1182,6 +1190,7 @@ extern uint32_t mount_clear_cache;
extern uint32_t mount_allow_degraded; extern uint32_t mount_allow_degraded;
extern uint32_t mount_readonly; extern uint32_t mount_readonly;
extern uint32_t mount_no_root_dir; extern uint32_t mount_no_root_dir;
extern uint32_t mount_nodatacow;
extern uint32_t no_pnp; extern uint32_t no_pnp;
#ifndef __GNUC__ #ifndef __GNUC__
@ -1468,8 +1477,6 @@ NTSTATUS do_tree_writes(device_extension* Vcb, LIST_ENTRY* tree_writes, bool no_
void add_checksum_entry(device_extension* Vcb, uint64_t address, ULONG length, void* csum, PIRP Irp); void add_checksum_entry(device_extension* Vcb, uint64_t address, ULONG length, void* csum, PIRP Irp);
bool find_metadata_address_in_chunk(device_extension* Vcb, chunk* c, uint64_t* address); bool find_metadata_address_in_chunk(device_extension* Vcb, chunk* c, uint64_t* address);
void add_trim_entry_avoid_sb(device_extension* Vcb, device* dev, uint64_t address, uint64_t size); void add_trim_entry_avoid_sb(device_extension* Vcb, device* dev, uint64_t address, uint64_t size);
NTSTATUS insert_tree_item_batch(LIST_ENTRY* batchlist, device_extension* Vcb, root* r, uint64_t objid, uint8_t objtype, uint64_t offset,
_In_opt_ _When_(return >= 0, __drv_aliasesMem) void* data, uint16_t datalen, enum batch_operation operation);
NTSTATUS flush_partial_stripe(device_extension* Vcb, chunk* c, partial_stripe* ps); NTSTATUS flush_partial_stripe(device_extension* Vcb, chunk* c, partial_stripe* ps);
NTSTATUS update_dev_item(device_extension* Vcb, device* device, PIRP Irp); NTSTATUS update_dev_item(device_extension* Vcb, device* device, PIRP Irp);
void calc_tree_checksum(device_extension* Vcb, tree_header* th); void calc_tree_checksum(device_extension* Vcb, tree_header* th);
@ -1697,6 +1704,9 @@ static __inline void print_open_trees(device_extension* Vcb) {
} }
static __inline bool write_fcb_compressed(fcb* fcb) { static __inline bool write_fcb_compressed(fcb* fcb) {
if (fcb->inode_item.flags & BTRFS_INODE_NODATACOW)
return false;
// make sure we don't accidentally write the cache inodes or pagefile compressed // make sure we don't accidentally write the cache inodes or pagefile compressed
if (fcb->subvol->id == BTRFS_ROOT_ROOT || fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE) if (fcb->subvol->id == BTRFS_ROOT_ROOT || fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE)
return false; return false;

View File

@ -2319,19 +2319,24 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr
fcb->inode_item.flags = BTRFS_INODE_NODATACOW | BTRFS_INODE_NODATASUM | BTRFS_INODE_NOCOMPRESS; fcb->inode_item.flags = BTRFS_INODE_NODATACOW | BTRFS_INODE_NODATASUM | BTRFS_INODE_NOCOMPRESS;
} else { } else {
// inherit nodatacow flag from parent directory // inherit nodatacow flag from parent directory
if (parfileref->fcb->inode_item.flags & BTRFS_INODE_NODATACOW) { if (parfileref->fcb->inode_item.flags & BTRFS_INODE_NODATACOW || Vcb->options.nodatacow) {
fcb->inode_item.flags |= BTRFS_INODE_NODATACOW; fcb->inode_item.flags |= BTRFS_INODE_NODATACOW;
if (type != BTRFS_TYPE_DIRECTORY) if (type != BTRFS_TYPE_DIRECTORY)
fcb->inode_item.flags |= BTRFS_INODE_NODATASUM; fcb->inode_item.flags |= BTRFS_INODE_NODATASUM;
} }
if (parfileref->fcb->inode_item.flags & BTRFS_INODE_COMPRESS) if (parfileref->fcb->inode_item.flags & BTRFS_INODE_COMPRESS &&
!(fcb->inode_item.flags & BTRFS_INODE_NODATACOW)) {
fcb->inode_item.flags |= BTRFS_INODE_COMPRESS; fcb->inode_item.flags |= BTRFS_INODE_COMPRESS;
}
} }
fcb->prop_compression = parfileref->fcb->prop_compression; if (!(fcb->inode_item.flags & BTRFS_INODE_NODATACOW)) {
fcb->prop_compression_changed = fcb->prop_compression != PropCompression_None; fcb->prop_compression = parfileref->fcb->prop_compression;
fcb->prop_compression_changed = fcb->prop_compression != PropCompression_None;
} else
fcb->prop_compression = PropCompression_None;
fcb->inode_item_changed = true; fcb->inode_item_changed = true;
@ -2838,7 +2843,7 @@ 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); fcb->adsmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - (sizeof(DIR_ITEM) - 1);
if (utf8len + sizeof(xapref) - 1 + overhead > fcb->adsmaxlen) { if (utf8len + sizeof(xapref) - 1 + overhead > fcb->adsmaxlen) {
WARN("not enough room for new DIR_ITEM (%Iu + %lu > %lu)", utf8len + sizeof(xapref) - 1, overhead, fcb->adsmaxlen); WARN("not enough room for new DIR_ITEM (%Iu + %lu > %lu)\n", utf8len + sizeof(xapref) - 1, overhead, fcb->adsmaxlen);
reap_fcb(fcb); reap_fcb(fcb);
free_fileref(parfileref); free_fileref(parfileref);
return STATUS_DISK_FULL; return STATUS_DISK_FULL;
@ -4551,7 +4556,7 @@ static NTSTATUS open_file(PDEVICE_OBJECT DeviceObject, _Requires_lock_held_(_Cur
uint64_t inode; uint64_t inode;
if (!related) { if (!related) {
WARN("cannot open by short file ID unless related fileref also provided"); WARN("cannot open by short file ID unless related fileref also provided"\n);
Status = STATUS_INVALID_PARAMETER; Status = STATUS_INVALID_PARAMETER;
goto exit; goto exit;
} }

View File

@ -3248,6 +3248,7 @@ static NTSTATUS set_end_of_file_information(device_extension* Vcb, PIRP Irp, PFI
LIST_ENTRY rollback; LIST_ENTRY rollback;
bool set_size = false; bool set_size = false;
ULONG filter; ULONG filter;
uint64_t new_end_of_file;
if (!fileref) { if (!fileref) {
ERR("fileref is NULL\n"); ERR("fileref is NULL\n");
@ -3306,35 +3307,43 @@ static NTSTATUS set_end_of_file_information(device_extension* Vcb, PIRP Irp, PFI
TRACE("FileObject: AllocationSize = %I64x, FileSize = %I64x, ValidDataLength = %I64x\n", TRACE("FileObject: AllocationSize = %I64x, FileSize = %I64x, ValidDataLength = %I64x\n",
fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart); fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
TRACE("setting new end to %I64x bytes (currently %I64x)\n", feofi->EndOfFile.QuadPart, fcb->inode_item.st_size); new_end_of_file = feofi->EndOfFile.QuadPart;
if ((uint64_t)feofi->EndOfFile.QuadPart < fcb->inode_item.st_size) { /* The lazy writer sometimes tries to round files to the next page size through CcSetValidData -
* ignore these. See fastfat!FatSetEndOfFileInfo, where Microsoft does the same as we're
* doing below. */
if (advance_only && new_end_of_file >= (uint64_t)fcb->Header.FileSize.QuadPart)
new_end_of_file = fcb->Header.FileSize.QuadPart;
TRACE("setting new end to %I64x bytes (currently %I64x)\n", new_end_of_file, fcb->inode_item.st_size);
if (new_end_of_file < fcb->inode_item.st_size) {
if (advance_only) { if (advance_only) {
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
goto end; goto end;
} }
TRACE("truncating file to %I64x bytes\n", feofi->EndOfFile.QuadPart); TRACE("truncating file to %I64x bytes\n", new_end_of_file);
if (!MmCanFileBeTruncated(&fcb->nonpaged->segment_object, &feofi->EndOfFile)) { if (!MmCanFileBeTruncated(&fcb->nonpaged->segment_object, &feofi->EndOfFile)) {
Status = STATUS_USER_MAPPED_FILE; Status = STATUS_USER_MAPPED_FILE;
goto end; goto end;
} }
Status = truncate_file(fcb, feofi->EndOfFile.QuadPart, Irp, &rollback); Status = truncate_file(fcb, new_end_of_file, Irp, &rollback);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("error - truncate_file failed\n"); ERR("error - truncate_file failed\n");
goto end; goto end;
} }
} else if ((uint64_t)feofi->EndOfFile.QuadPart > fcb->inode_item.st_size) { } else if (new_end_of_file > fcb->inode_item.st_size) {
TRACE("extending file to %I64x bytes\n", feofi->EndOfFile.QuadPart); TRACE("extending file to %I64x bytes\n", new_end_of_file);
Status = extend_file(fcb, fileref, feofi->EndOfFile.QuadPart, prealloc, NULL, &rollback); Status = extend_file(fcb, fileref, new_end_of_file, prealloc, NULL, &rollback);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("error - extend_file failed\n"); ERR("error - extend_file failed\n");
goto end; goto end;
} }
} else if ((uint64_t)feofi->EndOfFile.QuadPart == fcb->inode_item.st_size && advance_only) { } else if (new_end_of_file == fcb->inode_item.st_size && advance_only) {
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
goto end; goto end;
} }
@ -5502,6 +5511,11 @@ NTSTATUS __stdcall drv_query_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
goto end; goto end;
} }
if (fcb == fcb->Vcb->volume_fcb) {
Status = STATUS_INVALID_PARAMETER;
goto end;
}
ccb = FileObject->FsContext2; ccb = FileObject->FsContext2;
if (!ccb) { if (!ccb) {
@ -5753,6 +5767,11 @@ NTSTATUS __stdcall drv_set_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
goto end; goto end;
} }
if (fcb == fcb->Vcb->volume_fcb) {
Status = STATUS_INVALID_PARAMETER;
goto end;
}
ccb = FileObject->FsContext2; ccb = FileObject->FsContext2;
if (!ccb) { if (!ccb) {

View File

@ -29,6 +29,8 @@
// #define DEBUG_WRITE_LOOPS // #define DEBUG_WRITE_LOOPS
#define BATCH_ITEM_LIMIT 1000
typedef struct { typedef struct {
KEVENT Event; KEVENT Event;
IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK iosb;
@ -49,6 +51,10 @@ typedef struct {
static NTSTATUS create_chunk(device_extension* Vcb, chunk* c, PIRP Irp); static NTSTATUS create_chunk(device_extension* Vcb, chunk* c, PIRP Irp);
static NTSTATUS update_tree_extents(device_extension* Vcb, tree* t, PIRP Irp, LIST_ENTRY* rollback); static NTSTATUS update_tree_extents(device_extension* Vcb, tree* t, PIRP Irp, LIST_ENTRY* rollback);
static NTSTATUS insert_tree_item_batch(LIST_ENTRY* batchlist, device_extension* Vcb, root* r, uint64_t objid,
uint8_t objtype, uint64_t offset, _In_opt_ _When_(return >= 0, __drv_aliasesMem) void* data,
uint16_t datalen, enum batch_operation operation);
_Function_class_(IO_COMPLETION_ROUTINE) _Function_class_(IO_COMPLETION_ROUTINE)
static NTSTATUS __stdcall write_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) { static NTSTATUS __stdcall write_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
write_context* context = conptr; write_context* context = conptr;
@ -2923,7 +2929,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp, LIST_ENTRY*
#ifdef DEBUG_PARANOID #ifdef DEBUG_PARANOID
if (bgi->used & 0x8000000000000000) { if (bgi->used & 0x8000000000000000) {
ERR("refusing to write BLOCK_GROUP_ITEM with negative usage value (%I64x)", bgi->used); ERR("refusing to write BLOCK_GROUP_ITEM with negative usage value (%I64x)\n", bgi->used);
int3; int3;
} }
#endif #endif
@ -4429,12 +4435,88 @@ static NTSTATUS insert_sparse_extent(fcb* fcb, LIST_ENTRY* batchlist, uint64_t s
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS split_batch_item_list(batch_item_ind* bii) {
LIST_ENTRY* le;
unsigned int i = 0;
LIST_ENTRY* midpoint = NULL;
batch_item_ind* bii2;
batch_item* midpoint_item;
LIST_ENTRY* before_midpoint;
le = bii->items.Flink;
while (le != &bii->items) {
if (i >= bii->num_items / 2) {
midpoint = le;
break;
}
i++;
le = le->Flink;
}
if (!midpoint)
return STATUS_SUCCESS;
// make sure items on either side of split don't have same key
while (midpoint->Blink != &bii->items) {
batch_item* item = CONTAINING_RECORD(midpoint, batch_item, list_entry);
batch_item* prev = CONTAINING_RECORD(midpoint->Blink, batch_item, list_entry);
if (item->key.obj_id != prev->key.obj_id)
break;
if (item->key.obj_type != prev->key.obj_type)
break;
if (item->key.offset != prev->key.offset)
break;
midpoint = midpoint->Blink;
i--;
}
if (midpoint->Blink == &bii->items)
return STATUS_SUCCESS;
bii2 = ExAllocatePoolWithTag(PagedPool, sizeof(batch_item_ind), ALLOC_TAG);
if (!bii2) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
midpoint_item = CONTAINING_RECORD(midpoint, batch_item, list_entry);
bii2->key.obj_id = midpoint_item->key.obj_id;
bii2->key.obj_type = midpoint_item->key.obj_type;
bii2->key.offset = midpoint_item->key.offset;
bii2->num_items = bii->num_items - i;
bii->num_items = i;
before_midpoint = midpoint->Blink;
bii2->items.Flink = midpoint;
midpoint->Blink = &bii2->items;
bii2->items.Blink = bii->items.Blink;
bii->items.Blink->Flink = &bii2->items;
bii->items.Blink = before_midpoint;
before_midpoint->Flink = &bii->items;
InsertHeadList(&bii->list_entry, &bii2->list_entry);
return STATUS_SUCCESS;
}
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) #pragma warning(push)
#pragma warning(suppress: 28194) #pragma warning(suppress: 28194)
#endif #endif
NTSTATUS insert_tree_item_batch(LIST_ENTRY* batchlist, device_extension* Vcb, root* r, uint64_t objid, uint8_t objtype, uint64_t offset, static NTSTATUS insert_tree_item_batch(LIST_ENTRY* batchlist, device_extension* Vcb, root* r, uint64_t objid,
_In_opt_ _When_(return >= 0, __drv_aliasesMem) void* data, uint16_t datalen, enum batch_operation operation) { uint8_t objtype, uint64_t offset, _In_opt_ _When_(return >= 0, __drv_aliasesMem) void* data,
uint16_t datalen, enum batch_operation operation) {
LIST_ENTRY* le; LIST_ENTRY* le;
batch_root* br = NULL; batch_root* br = NULL;
batch_item* bi; batch_item* bi;
@ -4459,10 +4541,27 @@ NTSTATUS insert_tree_item_batch(LIST_ENTRY* batchlist, device_extension* Vcb, ro
} }
br->r = r; br->r = r;
InitializeListHead(&br->items); InitializeListHead(&br->items_ind);
InsertTailList(batchlist, &br->list_entry); InsertTailList(batchlist, &br->list_entry);
} }
if (IsListEmpty(&br->items_ind)) {
batch_item_ind* bii;
bii = ExAllocatePoolWithTag(PagedPool, sizeof(batch_item_ind), ALLOC_TAG);
if (!bii) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
bii->key.obj_id = 0;
bii->key.obj_type = 0;
bii->key.offset = 0;
InitializeListHead(&bii->items);
bii->num_items = 0;
InsertTailList(&br->items_ind, &bii->list_entry);
}
bi = ExAllocateFromPagedLookasideList(&Vcb->batch_item_lookaside); bi = ExAllocateFromPagedLookasideList(&Vcb->batch_item_lookaside);
if (!bi) { if (!bi) {
ERR("out of memory\n"); ERR("out of memory\n");
@ -4476,22 +4575,41 @@ NTSTATUS insert_tree_item_batch(LIST_ENTRY* batchlist, device_extension* Vcb, ro
bi->datalen = datalen; bi->datalen = datalen;
bi->operation = operation; bi->operation = operation;
le = br->items.Blink; le = br->items_ind.Blink;
while (le != &br->items) { while (le != &br->items_ind) {
batch_item* bi2 = CONTAINING_RECORD(le, batch_item, list_entry); LIST_ENTRY* le2;
int cmp = keycmp(bi2->key, bi->key); batch_item_ind* bii = CONTAINING_RECORD(le, batch_item_ind, list_entry);
if (cmp == -1 || (cmp == 0 && bi->operation >= bi2->operation)) { if (keycmp(bii->key, bi->key) == 1) {
InsertHeadList(&bi2->list_entry, &bi->list_entry); le = le->Blink;
return STATUS_SUCCESS; continue;
} }
le = le->Blink; le2 = bii->items.Blink;
while (le2 != &bii->items) {
batch_item* bi2 = CONTAINING_RECORD(le2, batch_item, list_entry);
int cmp = keycmp(bi2->key, bi->key);
if (cmp == -1 || (cmp == 0 && bi->operation >= bi2->operation)) {
InsertHeadList(&bi2->list_entry, &bi->list_entry);
bii->num_items++;
goto end;
}
le2 = le2->Blink;
}
InsertHeadList(&bii->items, &bi->list_entry);
bii->num_items++;
end:
if (bii->num_items > BATCH_ITEM_LIMIT)
return split_batch_item_list(bii);
return STATUS_SUCCESS;
} }
InsertHeadList(&br->items, &bi->list_entry); return STATUS_INTERNAL_ERROR;
return STATUS_SUCCESS;
} }
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)

View File

@ -1892,16 +1892,16 @@ static NTSTATUS update_chunk_cache_tree(device_extension* Vcb, chunk* c, PIRP Ir
fsi_count++; fsi_count++;
ExFreePool(s);
RemoveHeadList(&space_list); RemoveHeadList(&space_list);
ExFreePool(s);
continue; continue;
} else if (s->address == tp.item->key.obj_id && s->size == tp.item->key.offset) { } else if (s->address == tp.item->key.obj_id && s->size == tp.item->key.offset) {
// unchanged entry // unchanged entry
fsi_count++; fsi_count++;
ExFreePool(s);
RemoveHeadList(&space_list); RemoveHeadList(&space_list);
ExFreePool(s);
} else { } else {
// remove entry // remove entry

View File

@ -1363,6 +1363,10 @@ static NTSTATUS set_inode_info(PFILE_OBJECT FileObject, void* data, ULONG length
return STATUS_ACCESS_DENIED; return STATUS_ACCESS_DENIED;
} }
// nocow and compression are mutually exclusive
if (bsii->flags_changed && bsii->flags & BTRFS_INODE_NODATACOW && bsii->flags & BTRFS_INODE_COMPRESS)
return STATUS_INVALID_PARAMETER;
ExAcquireResourceExclusiveLite(fcb->Header.Resource, true); ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
if (bsii->flags_changed) { if (bsii->flags_changed) {

View File

@ -38,7 +38,7 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
mount_options* options = &Vcb->options; mount_options* options = &Vcb->options;
UNICODE_STRING path, ignoreus, compressus, compressforceus, compresstypeus, readonlyus, zliblevelus, flushintervalus, UNICODE_STRING path, ignoreus, compressus, compressforceus, compresstypeus, readonlyus, zliblevelus, flushintervalus,
maxinlineus, subvolidus, skipbalanceus, nobarrierus, notrimus, clearcacheus, allowdegradedus, zstdlevelus, maxinlineus, subvolidus, skipbalanceus, nobarrierus, notrimus, clearcacheus, allowdegradedus, zstdlevelus,
norootdirus; norootdirus, nodatacowus;
OBJECT_ATTRIBUTES oa; OBJECT_ATTRIBUTES oa;
NTSTATUS Status; NTSTATUS Status;
ULONG i, j, kvfilen, index, retlen; ULONG i, j, kvfilen, index, retlen;
@ -59,6 +59,8 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
options->clear_cache = mount_clear_cache; options->clear_cache = mount_clear_cache;
options->allow_degraded = mount_allow_degraded; options->allow_degraded = mount_allow_degraded;
options->subvol_id = 0; options->subvol_id = 0;
options->no_root_dir = mount_no_root_dir;
options->nodatacow = mount_nodatacow;
path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR)); path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG); path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
@ -123,6 +125,7 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
RtlInitUnicodeString(&allowdegradedus, L"AllowDegraded"); RtlInitUnicodeString(&allowdegradedus, L"AllowDegraded");
RtlInitUnicodeString(&zstdlevelus, L"ZstdLevel"); RtlInitUnicodeString(&zstdlevelus, L"ZstdLevel");
RtlInitUnicodeString(&norootdirus, L"NoRootDir"); RtlInitUnicodeString(&norootdirus, L"NoRootDir");
RtlInitUnicodeString(&nodatacowus, L"NoDataCOW");
do { do {
Status = ZwEnumerateValueKey(h, index, KeyValueFullInformation, kvfi, kvfilen, &retlen); Status = ZwEnumerateValueKey(h, index, KeyValueFullInformation, kvfi, kvfilen, &retlen);
@ -199,6 +202,10 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset); DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
options->no_root_dir = *val; options->no_root_dir = *val;
} else if (FsRtlAreNamesEqual(&nodatacowus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
options->nodatacow = *val;
} }
} else if (Status != STATUS_NO_MORE_ENTRIES) { } else if (Status != STATUS_NO_MORE_ENTRIES) {
ERR("ZwEnumerateValueKey returned %08lx\n", Status); ERR("ZwEnumerateValueKey returned %08lx\n", Status);
@ -813,6 +820,7 @@ void read_registry(PUNICODE_STRING regpath, bool refresh) {
get_registry_value(h, L"Readonly", REG_DWORD, &mount_readonly, sizeof(mount_readonly)); 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)); get_registry_value(h, L"ZstdLevel", REG_DWORD, &mount_zstd_level, sizeof(mount_zstd_level));
get_registry_value(h, L"NoRootDir", REG_DWORD, &mount_no_root_dir, sizeof(mount_no_root_dir)); get_registry_value(h, L"NoRootDir", REG_DWORD, &mount_no_root_dir, sizeof(mount_no_root_dir));
get_registry_value(h, L"NoDataCOW", REG_DWORD, &mount_nodatacow, sizeof(mount_nodatacow));
if (!refresh) if (!refresh)
get_registry_value(h, L"NoPNP", REG_DWORD, &no_pnp, sizeof(no_pnp)); get_registry_value(h, L"NoPNP", REG_DWORD, &no_pnp, sizeof(no_pnp));

View File

@ -1254,11 +1254,16 @@ void clear_batch_list(device_extension* Vcb, LIST_ENTRY* batchlist) {
LIST_ENTRY* le = RemoveHeadList(batchlist); LIST_ENTRY* le = RemoveHeadList(batchlist);
batch_root* br = CONTAINING_RECORD(le, batch_root, list_entry); batch_root* br = CONTAINING_RECORD(le, batch_root, list_entry);
while (!IsListEmpty(&br->items)) { while (!IsListEmpty(&br->items_ind)) {
LIST_ENTRY* le2 = RemoveHeadList(&br->items); batch_item_ind* bii = CONTAINING_RECORD(RemoveHeadList(&br->items_ind), batch_item_ind, list_entry);
batch_item* bi = CONTAINING_RECORD(le2, batch_item, list_entry);
ExFreeToPagedLookasideList(&Vcb->batch_item_lookaside, bi); while (!IsListEmpty(&bii->items)) {
batch_item* bi = CONTAINING_RECORD(RemoveHeadList(&bii->items), batch_item, list_entry);
ExFreeToPagedLookasideList(&Vcb->batch_item_lookaside, bi);
}
ExFreePool(bii);
} }
ExFreePool(br); ExFreePool(br);
@ -1901,15 +1906,31 @@ static NTSTATUS handle_batch_collision(device_extension* Vcb, batch_item* bi, tr
__attribute__((nonnull(1,2))) __attribute__((nonnull(1,2)))
static NTSTATUS commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, batch_root* br, PIRP Irp) { static NTSTATUS commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, batch_root* br, PIRP Irp) {
LIST_ENTRY items;
LIST_ENTRY* le; LIST_ENTRY* le;
NTSTATUS Status; NTSTATUS Status;
TRACE("root: %I64x\n", br->r->id); TRACE("root: %I64x\n", br->r->id);
le = br->items.Flink; InitializeListHead(&items);
while (le != &br->items) {
// move sub-lists into one big list
while (!IsListEmpty(&br->items_ind)) {
batch_item_ind* bii = CONTAINING_RECORD(RemoveHeadList(&br->items_ind), batch_item_ind, list_entry);
items.Blink->Flink = bii->items.Flink;
bii->items.Flink->Blink = items.Blink;
items.Blink = bii->items.Blink;
bii->items.Blink->Flink = &items;
ExFreePool(bii);
}
le = items.Flink;
while (le != &items) {
batch_item* bi = CONTAINING_RECORD(le, batch_item, list_entry); batch_item* bi = CONTAINING_RECORD(le, batch_item, list_entry);
LIST_ENTRY *le2; LIST_ENTRY* le2;
traverse_ptr tp; traverse_ptr tp;
KEY tree_end; KEY tree_end;
bool no_end; bool no_end;
@ -2174,7 +2195,7 @@ static NTSTATUS commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tr
if (td) if (td)
InsertHeadList(tp.item->list_entry.Blink, &td->list_entry); InsertHeadList(tp.item->list_entry.Blink, &td->list_entry);
} else { } else {
Status = handle_batch_collision(Vcb, bi, tp.tree, tp.item, td, &br->items, &ignore); Status = handle_batch_collision(Vcb, bi, tp.tree, tp.item, td, &items, &ignore);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("handle_batch_collision returned %08lx\n", Status); ERR("handle_batch_collision returned %08lx\n", Status);
#ifdef _DEBUG #ifdef _DEBUG
@ -2192,7 +2213,7 @@ static NTSTATUS commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tr
} }
if (bi->operation == Batch_DeleteInodeRef && cmp != 0 && Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF) { if (bi->operation == Batch_DeleteInodeRef && cmp != 0 && Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF) {
add_delete_inode_extref(Vcb, bi, &br->items); add_delete_inode_extref(Vcb, bi, &items);
} }
if (!ignore && td) { if (!ignore && td) {
@ -2214,7 +2235,7 @@ static NTSTATUS commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tr
} }
le2 = le->Flink; le2 = le->Flink;
while (le2 != &br->items) { while (le2 != &items) {
batch_item* bi2 = CONTAINING_RECORD(le2, batch_item, list_entry); batch_item* bi2 = CONTAINING_RECORD(le2, batch_item, list_entry);
if (bi2->operation == Batch_DeleteInode || bi2->operation == Batch_DeleteExtentData || bi2->operation == Batch_DeleteFreeSpace) if (bi2->operation == Batch_DeleteInode || bi2->operation == Batch_DeleteExtentData || bi2->operation == Batch_DeleteFreeSpace)
@ -2255,10 +2276,10 @@ static NTSTATUS commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tr
InsertHeadList(le3->Blink, &td->list_entry); InsertHeadList(le3->Blink, &td->list_entry);
inserted = true; inserted = true;
} else if (bi2->operation == Batch_DeleteInodeRef && Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF) { } else if (bi2->operation == Batch_DeleteInodeRef && Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF) {
add_delete_inode_extref(Vcb, bi2, &br->items); add_delete_inode_extref(Vcb, bi2, &items);
} }
} else { } else {
Status = handle_batch_collision(Vcb, bi2, tp.tree, td2, td, &br->items, &ignore); Status = handle_batch_collision(Vcb, bi2, tp.tree, td2, td, &items, &ignore);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("handle_batch_collision returned %08lx\n", Status); ERR("handle_batch_collision returned %08lx\n", Status);
#ifdef _DEBUG #ifdef _DEBUG
@ -2275,7 +2296,7 @@ static NTSTATUS commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tr
InsertHeadList(le3->Blink, &td->list_entry); InsertHeadList(le3->Blink, &td->list_entry);
inserted = true; inserted = true;
} else if (bi2->operation == Batch_DeleteInodeRef && Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF) { } else if (bi2->operation == Batch_DeleteInodeRef && Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF) {
add_delete_inode_extref(Vcb, bi2, &br->items); add_delete_inode_extref(Vcb, bi2, &items);
} }
break; break;
} }
@ -2294,7 +2315,7 @@ static NTSTATUS commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tr
listhead = td; listhead = td;
} }
} else if (!inserted && bi2->operation == Batch_DeleteInodeRef && Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF) { } else if (!inserted && bi2->operation == Batch_DeleteInodeRef && Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF) {
add_delete_inode_extref(Vcb, bi2, &br->items); add_delete_inode_extref(Vcb, bi2, &items);
} }
while (listhead->list_entry.Blink != &tp.tree->itemlist) { while (listhead->list_entry.Blink != &tp.tree->itemlist) {
@ -2330,8 +2351,8 @@ static NTSTATUS commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tr
} }
// FIXME - remove as we are going along // FIXME - remove as we are going along
while (!IsListEmpty(&br->items)) { while (!IsListEmpty(&items)) {
batch_item* bi = CONTAINING_RECORD(RemoveHeadList(&br->items), batch_item, list_entry); batch_item* bi = CONTAINING_RECORD(RemoveHeadList(&items), batch_item, list_entry);
if ((bi->operation == Batch_DeleteDirItem || bi->operation == Batch_DeleteInodeRef || if ((bi->operation == Batch_DeleteDirItem || bi->operation == Batch_DeleteInodeRef ||
bi->operation == Batch_DeleteInodeExtRef || bi->operation == Batch_DeleteXattr) && bi->data) bi->operation == Batch_DeleteInodeExtRef || bi->operation == Batch_DeleteXattr) && bi->data)