[BTRFS][UBTRFS][SHELLBTRFS] Upgrade to 1.7.3 (#4417)

v1.7.3 (2020-05-24):

- Fixed crash when sending file change notifications
- Improved symlink handling with LXSS
- Added support for undocumented flag SL_IGNORE_READONLY_ATTRIBUTE
- Fixed corruption caused by edge case, where address allocated and freed in same flush
- Improved handling of free space tree
- Improved handling of very full volumes
- Fixed spurious warnings raised by GCC 10 static analyser
- Replaced multiplications and divisions with bit shift operations where appropriate
- Fixed combobox stylings in shell extension
This commit is contained in:
Vincent Franchomme 2022-04-28 21:31:44 +02:00 committed by Hermès BÉLUSCA - MAÏTO
parent 7ba5f703d2
commit 174dfab667
23 changed files with 1296 additions and 1043 deletions

View file

@ -61,8 +61,8 @@ IDI_ICON1 ICON "subvol.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,7,2,0 FILEVERSION 1,7,3,0
PRODUCTVERSION 1,7,2,0 PRODUCTVERSION 1,7,3,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.7.2" VALUE "FileVersion", "1.7.3"
VALUE "InternalName", "btrfs" VALUE "InternalName", "btrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-20" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-20"
VALUE "OriginalFilename", "shellbtrfs.dll" VALUE "OriginalFilename", "shellbtrfs.dll"
VALUE "ProductName", "WinBtrfs" VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "1.7.2" VALUE "ProductVersion", "1.7.3"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
@ -221,7 +221,7 @@ BEGIN
CONTROL "",IDC_USAGE_END_SPINNER,"msctls_updown32",UDS_SETBUDDYINT | UDS_AUTOBUDDY | UDS_ARROWKEYS,77,94,11,14 CONTROL "",IDC_USAGE_END_SPINNER,"msctls_updown32",UDS_SETBUDDYINT | UDS_AUTOBUDDY | UDS_ARROWKEYS,77,94,11,14
LTEXT "% to",IDC_STATIC,39,97,16,8 LTEXT "% to",IDC_STATIC,39,97,16,8
CONTROL "&Device:",IDC_DEVID,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,104,6,34,10 CONTROL "&Device:",IDC_DEVID,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,104,6,34,10
COMBOBOX IDC_DEVID_COMBO,141,6,155,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_DEVID_COMBO,141,6,155,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "%",IDC_STATIC,91,97,8,8 LTEXT "%",IDC_STATIC,91,97,8,8
CONTROL "Device &range:",IDC_DRANGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,104,19,59,10 CONTROL "Device &range:",IDC_DRANGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,104,19,59,10
EDITTEXT IDC_DRANGE_END,159,32,40,14,ES_AUTOHSCROLL | ES_NUMBER EDITTEXT IDC_DRANGE_END,159,32,40,14,ES_AUTOHSCROLL | ES_NUMBER
@ -244,7 +244,7 @@ BEGIN
CONTROL "",IDC_STRIPES_END_SPINNER,"msctls_updown32",UDS_SETBUDDYINT | UDS_AUTOBUDDY | UDS_ARROWKEYS,272,32,11,14 CONTROL "",IDC_STRIPES_END_SPINNER,"msctls_updown32",UDS_SETBUDDYINT | UDS_AUTOBUDDY | UDS_ARROWKEYS,272,32,11,14
LTEXT "to",IDC_STATIC,242,35,8,8 LTEXT "to",IDC_STATIC,242,35,8,8
CONTROL "&Convert:",IDC_CONVERT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,210,49,36,10 CONTROL "&Convert:",IDC_CONVERT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,210,49,36,10
COMBOBOX IDC_CONVERT_COMBO,248,49,48,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_CONVERT_COMBO,248,49,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CONTROL "So&ft",IDC_SOFT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,210,64,28,10 CONTROL "So&ft",IDC_SOFT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,210,64,28,10
END END
@ -376,7 +376,7 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN BEGIN
DEFPUSHBUTTON "OK",IDOK,7,40,50,14 DEFPUSHBUTTON "OK",IDOK,7,40,50,14
PUSHBUTTON "Cancel",IDCANCEL,74,40,50,14 PUSHBUTTON "Cancel",IDCANCEL,74,40,50,14
COMBOBOX IDC_DRIVE_LETTER_COMBO,64,17,60,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_DRIVE_LETTER_COMBO,64,17,60,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
LTEXT "Drive letter:",IDC_STATIC,15,19,45,8 LTEXT "Drive letter:",IDC_STATIC,15,19,45,8
END END

View file

@ -25,18 +25,18 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
// TEXTINCLUDE // TEXTINCLUDE
// //
1 TEXTINCLUDE 1 TEXTINCLUDE
BEGIN BEGIN
"resource.h\0" "resource.h\0"
END END
2 TEXTINCLUDE 2 TEXTINCLUDE
BEGIN BEGIN
"#include ""winres.h""\r\n" "#include ""winres.h""\r\n"
"\0" "\0"
END END
3 TEXTINCLUDE 3 TEXTINCLUDE
BEGIN BEGIN
"\r\n" "\r\n"
"\0" "\0"
@ -51,8 +51,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,7,2,0 FILEVERSION 1,7,3,0
PRODUCTVERSION 1,7,2,0 PRODUCTVERSION 1,7,3,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.7.2" VALUE "FileVersion", "1.7.3"
VALUE "InternalName", "ubtrfs" VALUE "InternalName", "ubtrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-20" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-20"
VALUE "OriginalFilename", "ubtrfs.dll" VALUE "OriginalFilename", "ubtrfs.dll"
VALUE "ProductName", "WinBtrfs" VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "1.7.2" VALUE "ProductVersion", "1.7.3"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -750,7 +750,7 @@ static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree
if (newchunk->chunk_item->type == flags && find_metadata_address_in_chunk(Vcb, newchunk, &mr->new_address)) { if (newchunk->chunk_item->type == flags && find_metadata_address_in_chunk(Vcb, newchunk, &mr->new_address)) {
newchunk->used += Vcb->superblock.node_size; newchunk->used += Vcb->superblock.node_size;
space_list_subtract(newchunk, false, mr->new_address, Vcb->superblock.node_size, rollback); space_list_subtract(newchunk, mr->new_address, Vcb->superblock.node_size, rollback);
done = true; done = true;
} }
@ -770,7 +770,7 @@ static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree
if ((c2->chunk_item->size - c2->used) >= Vcb->superblock.node_size) { if ((c2->chunk_item->size - c2->used) >= Vcb->superblock.node_size) {
if (find_metadata_address_in_chunk(Vcb, c2, &mr->new_address)) { if (find_metadata_address_in_chunk(Vcb, c2, &mr->new_address)) {
c2->used += Vcb->superblock.node_size; c2->used += Vcb->superblock.node_size;
space_list_subtract(c2, false, mr->new_address, Vcb->superblock.node_size, rollback); space_list_subtract(c2, mr->new_address, Vcb->superblock.node_size, rollback);
release_chunk_lock(c2, Vcb); release_chunk_lock(c2, Vcb);
newchunk = c2; newchunk = c2;
done = true; done = true;
@ -806,7 +806,7 @@ static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree
goto end; goto end;
} else { } else {
newchunk->used += Vcb->superblock.node_size; newchunk->used += Vcb->superblock.node_size;
space_list_subtract(newchunk, false, mr->new_address, Vcb->superblock.node_size, rollback); space_list_subtract(newchunk, mr->new_address, Vcb->superblock.node_size, rollback);
} }
release_chunk_lock(newchunk, Vcb); release_chunk_lock(newchunk, Vcb);
@ -1767,7 +1767,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* change
if (find_data_address_in_chunk(Vcb, newchunk, dr->size, &dr->new_address)) { if (find_data_address_in_chunk(Vcb, newchunk, dr->size, &dr->new_address)) {
newchunk->used += dr->size; newchunk->used += dr->size;
space_list_subtract(newchunk, false, dr->new_address, dr->size, &rollback); space_list_subtract(newchunk, dr->new_address, dr->size, &rollback);
done = true; done = true;
} }
@ -1787,7 +1787,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* change
if ((c2->chunk_item->size - c2->used) >= dr->size) { if ((c2->chunk_item->size - c2->used) >= dr->size) {
if (find_data_address_in_chunk(Vcb, c2, dr->size, &dr->new_address)) { if (find_data_address_in_chunk(Vcb, c2, dr->size, &dr->new_address)) {
c2->used += dr->size; c2->used += dr->size;
space_list_subtract(c2, false, dr->new_address, dr->size, &rollback); space_list_subtract(c2, dr->new_address, dr->size, &rollback);
release_chunk_lock(c2, Vcb); release_chunk_lock(c2, Vcb);
newchunk = c2; newchunk = c2;
done = true; done = true;
@ -1823,7 +1823,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* change
goto end; goto end;
} else { } else {
newchunk->used += dr->size; newchunk->used += dr->size;
space_list_subtract(newchunk, false, dr->new_address, dr->size, &rollback); space_list_subtract(newchunk, dr->new_address, dr->size, &rollback);
} }
release_chunk_lock(newchunk, Vcb); release_chunk_lock(newchunk, Vcb);
@ -1834,7 +1834,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* change
dr->newchunk = newchunk; dr->newchunk = newchunk;
bmplen = (ULONG)(dr->size / Vcb->superblock.sector_size); bmplen = (ULONG)(dr->size >> Vcb->sector_shift);
bmparr = ExAllocatePoolWithTag(PagedPool, (ULONG)sector_align(bmplen + 1, sizeof(ULONG)), ALLOC_TAG); bmparr = ExAllocatePoolWithTag(PagedPool, (ULONG)sector_align(bmplen + 1, sizeof(ULONG)), ALLOC_TAG);
if (!bmparr) { if (!bmparr) {
@ -1843,7 +1843,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* change
goto end; goto end;
} }
csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(dr->size * Vcb->csum_size / Vcb->superblock.sector_size), ALLOC_TAG); csum = ExAllocatePoolWithTag(PagedPool, (ULONG)((dr->size * Vcb->csum_size) >> Vcb->sector_shift), ALLOC_TAG);
if (!csum) { if (!csum) {
ERR("out of memory\n"); ERR("out of memory\n");
ExFreePool(bmparr); ExFreePool(bmparr);
@ -1873,15 +1873,15 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* change
if (tp.item->key.obj_type == TYPE_EXTENT_CSUM) { if (tp.item->key.obj_type == TYPE_EXTENT_CSUM) {
if (tp.item->key.offset >= dr->address + dr->size) if (tp.item->key.offset >= dr->address + dr->size)
break; break;
else if (tp.item->size >= Vcb->csum_size && tp.item->key.offset + (tp.item->size * Vcb->superblock.sector_size / Vcb->csum_size) >= dr->address) { else if (tp.item->size >= Vcb->csum_size && tp.item->key.offset + (((unsigned int)tp.item->size << Vcb->sector_shift) / Vcb->csum_size) >= dr->address) {
uint64_t cs = max(dr->address, tp.item->key.offset); uint64_t cs = max(dr->address, tp.item->key.offset);
uint64_t ce = min(dr->address + dr->size, tp.item->key.offset + (tp.item->size * Vcb->superblock.sector_size / Vcb->csum_size)); uint64_t ce = min(dr->address + dr->size, tp.item->key.offset + (((unsigned int)tp.item->size << Vcb->sector_shift) / Vcb->csum_size));
RtlCopyMemory((uint8_t*)csum + ((cs - dr->address) * Vcb->csum_size / Vcb->superblock.sector_size), RtlCopyMemory((uint8_t*)csum + (((cs - dr->address) * Vcb->csum_size) >> Vcb->sector_shift),
tp.item->data + ((cs - tp.item->key.offset) * Vcb->csum_size / Vcb->superblock.sector_size), tp.item->data + (((cs - tp.item->key.offset) * Vcb->csum_size) >> Vcb->sector_shift),
(ULONG)((ce - cs) * Vcb->csum_size / Vcb->superblock.sector_size)); (ULONG)(((ce - cs) * Vcb->csum_size) >> Vcb->sector_shift));
RtlClearBits(&bmp, (ULONG)((cs - dr->address) / Vcb->superblock.sector_size), (ULONG)((ce - cs) / Vcb->superblock.sector_size)); RtlClearBits(&bmp, (ULONG)((cs - dr->address) >> Vcb->sector_shift), (ULONG)((ce - cs) >> Vcb->sector_shift));
if (ce == dr->address + dr->size) if (ce == dr->address + dr->size)
break; break;
@ -1917,12 +1917,12 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* change
do { do {
ULONG rl; ULONG rl;
if (size * Vcb->superblock.sector_size > BALANCE_UNIT) if (size << Vcb->sector_shift > BALANCE_UNIT)
rl = BALANCE_UNIT / Vcb->superblock.sector_size; rl = BALANCE_UNIT >> Vcb->sector_shift;
else else
rl = size; rl = size;
Status = read_data(Vcb, dr->address + (off * Vcb->superblock.sector_size), rl * Vcb->superblock.sector_size, NULL, false, data, Status = read_data(Vcb, dr->address + (off << Vcb->sector_shift), rl << Vcb->sector_shift, NULL, false, data,
c, NULL, NULL, 0, false, NormalPagePriority); c, NULL, NULL, 0, false, NormalPagePriority);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("read_data returned %08lx\n", Status); ERR("read_data returned %08lx\n", Status);
@ -1931,7 +1931,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* change
goto end; goto end;
} }
Status = write_data_complete(Vcb, dr->new_address + (off * Vcb->superblock.sector_size), data, rl * Vcb->superblock.sector_size, Status = write_data_complete(Vcb, dr->new_address + (off << Vcb->sector_shift), data, rl << Vcb->sector_shift,
NULL, newchunk, false, 0, NormalPagePriority); NULL, newchunk, false, 0, NormalPagePriority);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("write_data_complete returned %08lx\n", Status); ERR("write_data_complete returned %08lx\n", Status);
@ -1945,19 +1945,19 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* change
} while (size > 0); } while (size > 0);
} }
add_checksum_entry(Vcb, dr->new_address + (index * Vcb->superblock.sector_size), runlength, (uint8_t*)csum + (index * Vcb->csum_size), NULL); add_checksum_entry(Vcb, dr->new_address + (index << Vcb->sector_shift), runlength, (uint8_t*)csum + (index * Vcb->csum_size), NULL);
add_checksum_entry(Vcb, dr->address + (index * Vcb->superblock.sector_size), runlength, NULL, NULL); add_checksum_entry(Vcb, dr->address + (index << Vcb->sector_shift), runlength, NULL, NULL);
// handle csum run // handle csum run
do { do {
ULONG rl; ULONG rl;
if (runlength * Vcb->superblock.sector_size > BALANCE_UNIT) if (runlength << Vcb->sector_shift > BALANCE_UNIT)
rl = BALANCE_UNIT / Vcb->superblock.sector_size; rl = BALANCE_UNIT >> Vcb->sector_shift;
else else
rl = runlength; rl = runlength;
Status = read_data(Vcb, dr->address + (index * Vcb->superblock.sector_size), rl * Vcb->superblock.sector_size, Status = read_data(Vcb, dr->address + (index << Vcb->sector_shift), rl << Vcb->sector_shift,
(uint8_t*)csum + (index * Vcb->csum_size), false, data, c, NULL, NULL, 0, false, NormalPagePriority); (uint8_t*)csum + (index * Vcb->csum_size), false, data, c, NULL, NULL, 0, false, NormalPagePriority);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("read_data returned %08lx\n", Status); ERR("read_data returned %08lx\n", Status);
@ -1966,7 +1966,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* change
goto end; goto end;
} }
Status = write_data_complete(Vcb, dr->new_address + (index * Vcb->superblock.sector_size), data, rl * Vcb->superblock.sector_size, Status = write_data_complete(Vcb, dr->new_address + (index << Vcb->sector_shift), data, rl << Vcb->sector_shift,
NULL, newchunk, false, 0, NormalPagePriority); NULL, newchunk, false, 0, NormalPagePriority);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("write_data_complete returned %08lx\n", Status); ERR("write_data_complete returned %08lx\n", Status);
@ -1987,26 +1987,26 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* change
ExFreePool(bmparr); ExFreePool(bmparr);
// handle final nocsum run // handle final nocsum run
if (lastoff < dr->size / Vcb->superblock.sector_size) { if (lastoff < dr->size >> Vcb->sector_shift) {
ULONG off = lastoff; ULONG off = lastoff;
ULONG size = (ULONG)((dr->size / Vcb->superblock.sector_size) - lastoff); ULONG size = (ULONG)((dr->size >> Vcb->sector_shift) - lastoff);
do { do {
ULONG rl; ULONG rl;
if (size * Vcb->superblock.sector_size > BALANCE_UNIT) if (size << Vcb->sector_shift > BALANCE_UNIT)
rl = BALANCE_UNIT / Vcb->superblock.sector_size; rl = BALANCE_UNIT >> Vcb->sector_shift;
else else
rl = size; rl = size;
Status = read_data(Vcb, dr->address + (off * Vcb->superblock.sector_size), rl * Vcb->superblock.sector_size, NULL, false, data, Status = read_data(Vcb, dr->address + (off << Vcb->sector_shift), rl << Vcb->sector_shift, NULL, false, data,
c, NULL, NULL, 0, false, NormalPagePriority); c, NULL, NULL, 0, false, NormalPagePriority);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("read_data returned %08lx\n", Status); ERR("read_data returned %08lx\n", Status);
goto end; goto end;
} }
Status = write_data_complete(Vcb, dr->new_address + (off * Vcb->superblock.sector_size), data, rl * Vcb->superblock.sector_size, Status = write_data_complete(Vcb, dr->new_address + (off << Vcb->sector_shift), data, rl << Vcb->sector_shift,
NULL, newchunk, false, 0, NormalPagePriority); NULL, newchunk, false, 0, NormalPagePriority);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("write_data_complete returned %08lx\n", Status); ERR("write_data_complete returned %08lx\n", Status);

View file

@ -33,10 +33,6 @@ extern PDRIVER_OBJECT drvobj;
BTRFS_UUID boot_uuid; // initialized to 0 BTRFS_UUID boot_uuid; // initialized to 0
uint64_t boot_subvol = 0; uint64_t boot_subvol = 0;
#ifndef _MSC_VER
NTSTATUS RtlUnicodeStringPrintf(PUNICODE_STRING DestinationString, const WCHAR* pszFormat, ...); // not in mingw
#endif
// Not in any headers? Windbg knows about it though. // Not in any headers? Windbg knows about it though.
#define DOE_START_PENDING 0x10 #define DOE_START_PENDING 0x10
@ -244,6 +240,34 @@ static void get_system_root(system_root* sr) {
ExFreePool(target.Buffer); ExFreePool(target.Buffer);
} }
static void append_int_to_us(UNICODE_STRING* us, unsigned int n) {
unsigned int num, digits = 0;
WCHAR* ptr;
if (n == 0) {
us->Buffer[us->Length / sizeof(WCHAR)] = '0';
us->Length += sizeof(WCHAR);
return;
}
num = n;
while (num > 0) {
digits++;
num /= 10;
}
ptr = &us->Buffer[(us->Length / sizeof(WCHAR)) + digits - 1];
while (n > 0) {
*ptr = L'0' + (n % 10);
ptr--;
n /= 10;
}
us->Length += digits * sizeof(WCHAR);
}
static void change_symlink(uint32_t disk_num, uint32_t partition_num, BTRFS_UUID* uuid) { static void change_symlink(uint32_t disk_num, uint32_t partition_num, BTRFS_UUID* uuid) {
NTSTATUS Status; NTSTATUS Status;
UNICODE_STRING us, us2; UNICODE_STRING us, us2;
@ -252,15 +276,21 @@ static void change_symlink(uint32_t disk_num, uint32_t partition_num, BTRFS_UUID
unsigned int i; unsigned int i;
#endif #endif
static const WCHAR dev_path1[] = L"\\Device\\Harddisk";
static const WCHAR dev_path2[] = L"\\Partition";
us.Buffer = symlink; us.Buffer = symlink;
us.Length = 0; us.Length = sizeof(dev_path1) - sizeof(WCHAR);
us.MaximumLength = sizeof(symlink); us.MaximumLength = sizeof(symlink);
Status = RtlUnicodeStringPrintf(&us, L"\\Device\\Harddisk%u\\Partition%u", disk_num, partition_num); RtlCopyMemory(symlink, dev_path1, sizeof(dev_path1) - sizeof(WCHAR));
if (!NT_SUCCESS(Status)) {
ERR("RtlUnicodeStringPrintf returned %08lx\n", Status); append_int_to_us(&us, disk_num);
return;
} RtlCopyMemory(&us.Buffer[us.Length / sizeof(WCHAR)], dev_path2, sizeof(dev_path2) - sizeof(WCHAR));
us.Length += sizeof(dev_path2) - sizeof(WCHAR);
append_int_to_us(&us, partition_num);
Status = IoDeleteSymbolicLink(&us); Status = IoDeleteSymbolicLink(&us);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))

View file

@ -48,11 +48,7 @@
#undef INITGUID #undef INITGUID
#endif #endif
#ifdef _MSC_VER
#include <ntstrsafe.h> #include <ntstrsafe.h>
#else
NTSTATUS RtlStringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList); // not in mingw
#endif
#define INCOMPAT_SUPPORTED (BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF | BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL | BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS | \ #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_COMPRESS_LZO | BTRFS_INCOMPAT_FLAGS_BIG_METADATA | BTRFS_INCOMPAT_FLAGS_RAID56 | \
@ -113,6 +109,7 @@ bool degraded_wait = true;
KEVENT mountmgr_thread_event; KEVENT mountmgr_thread_event;
bool shutting_down = false; bool shutting_down = false;
ERESOURCE boot_lock; ERESOURCE boot_lock;
bool is_windows_8;
extern uint64_t boot_subvol; extern uint64_t boot_subvol;
#ifdef _DEBUG #ifdef _DEBUG
@ -597,9 +594,9 @@ static void calculate_total_space(_In_ device_extension* Vcb, _Out_ uint64_t* to
dfactor = 1; dfactor = 1;
} }
sectors_used = (Vcb->superblock.bytes_used / Vcb->superblock.sector_size) * nfactor / dfactor; sectors_used = (Vcb->superblock.bytes_used >> Vcb->sector_shift) * nfactor / dfactor;
*totalsize = (Vcb->superblock.total_bytes / Vcb->superblock.sector_size) * nfactor / dfactor; *totalsize = (Vcb->superblock.total_bytes >> Vcb->sector_shift) * nfactor / dfactor;
*freespace = sectors_used > *totalsize ? 0 : (*totalsize - sectors_used); *freespace = sectors_used > *totalsize ? 0 : (*totalsize - sectors_used);
} }
@ -1200,7 +1197,6 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi
_Out_ root** rootptr, _In_ bool no_tree, _In_ uint64_t offset, _In_opt_ PIRP Irp) { _Out_ root** rootptr, _In_ bool no_tree, _In_ uint64_t offset, _In_opt_ PIRP Irp) {
NTSTATUS Status; NTSTATUS Status;
root* r; root* r;
tree* t = NULL;
ROOT_ITEM* ri; ROOT_ITEM* ri;
traverse_ptr tp; traverse_ptr tp;
@ -1217,29 +1213,10 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
if (!no_tree) {
t = ExAllocatePoolWithTag(PagedPool, sizeof(tree), ALLOC_TAG);
if (!t) {
ERR("out of memory\n");
ExFreePool(r->nonpaged);
ExFreePool(r);
return STATUS_INSUFFICIENT_RESOURCES;
}
t->nonpaged = NULL;
t->is_unique = true;
t->uniqueness_determined = true;
t->buf = NULL;
}
ri = ExAllocatePoolWithTag(PagedPool, sizeof(ROOT_ITEM), ALLOC_TAG); ri = ExAllocatePoolWithTag(PagedPool, sizeof(ROOT_ITEM), ALLOC_TAG);
if (!ri) { if (!ri) {
ERR("out of memory\n"); ERR("out of memory\n");
if (t)
ExFreePool(t);
ExFreePool(r->nonpaged); ExFreePool(r->nonpaged);
ExFreePool(r); ExFreePool(r);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
@ -1248,7 +1225,7 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi
r->id = id; r->id = id;
r->treeholder.address = 0; r->treeholder.address = 0;
r->treeholder.generation = Vcb->superblock.generation; r->treeholder.generation = Vcb->superblock.generation;
r->treeholder.tree = t; r->treeholder.tree = NULL;
r->lastinode = 0; r->lastinode = 0;
r->dirty = false; r->dirty = false;
r->received = false; r->received = false;
@ -1272,10 +1249,6 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("insert_tree_item returned %08lx\n", Status); ERR("insert_tree_item returned %08lx\n", Status);
ExFreePool(ri); ExFreePool(ri);
if (t)
ExFreePool(t);
ExFreePool(r->nonpaged); ExFreePool(r->nonpaged);
ExFreePool(r); ExFreePool(r);
return Status; return Status;
@ -1286,6 +1259,26 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi
InsertTailList(&Vcb->roots, &r->list_entry); InsertTailList(&Vcb->roots, &r->list_entry);
if (!no_tree) { if (!no_tree) {
tree* t = ExAllocatePoolWithTag(PagedPool, sizeof(tree), ALLOC_TAG);
if (!t) {
ERR("out of memory\n");
delete_tree_item(Vcb, &tp);
ExFreePool(r->nonpaged);
ExFreePool(r);
ExFreePool(ri);
return STATUS_INSUFFICIENT_RESOURCES;
}
t->nonpaged = NULL;
t->is_unique = true;
t->uniqueness_determined = true;
t->buf = NULL;
r->treeholder.tree = t;
RtlZeroMemory(&t->header, sizeof(tree_header)); RtlZeroMemory(&t->header, sizeof(tree_header));
t->header.fs_uuid = tp.tree->header.fs_uuid; t->header.fs_uuid = tp.tree->header.fs_uuid;
t->header.address = 0; t->header.address = 0;
@ -1493,7 +1486,9 @@ static void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_matc
// no point looking for hardlinks if st_nlink == 1 // no point looking for hardlinks if st_nlink == 1
if (fileref->fcb->inode_item.st_nlink == 1) { if (fileref->fcb->inode_item.st_nlink == 1) {
ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, true);
send_notification_fileref(fileref, filter_match, action, stream); send_notification_fileref(fileref, filter_match, action, stream);
ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
return; return;
} }
@ -2417,7 +2412,6 @@ static NTSTATUS __stdcall drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIR
// messages belonging to other devices. // messages belonging to other devices.
if (FileObject && FileObject->FsContext) { if (FileObject && FileObject->FsContext) {
LONG oc;
ccb* ccb; ccb* ccb;
file_ref* fileref; file_ref* fileref;
bool locked = true; bool locked = true;
@ -2439,13 +2433,6 @@ static NTSTATUS __stdcall drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIR
if (ccb) if (ccb)
FsRtlNotifyCleanup(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, ccb); FsRtlNotifyCleanup(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, ccb);
if (fileref) {
oc = InterlockedDecrement(&fileref->open_count);
#ifdef DEBUG_FCB_REFCOUNTS
ERR("fileref %p: open_count now %i\n", fileref, oc);
#endif
}
if (ccb && ccb->options & FILE_DELETE_ON_CLOSE && fileref) if (ccb && ccb->options & FILE_DELETE_ON_CLOSE && fileref)
fileref->delete_on_close = true; fileref->delete_on_close = true;
@ -2464,84 +2451,91 @@ static NTSTATUS __stdcall drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIR
// FIXME - flush all of subvol's fcbs // FIXME - flush all of subvol's fcbs
} }
if (fileref && (oc == 0 || (fileref->delete_on_close && fileref->posix_delete))) { if (fileref) {
if (!fcb->Vcb->removing) { LONG oc = InterlockedDecrement(&fileref->open_count);
if (oc == 0 && fileref->fcb->inode_item.st_nlink == 0 && fileref != fcb->Vcb->root_fileref && #ifdef DEBUG_FCB_REFCOUNTS
fcb != fcb->Vcb->volume_fcb && !fcb->ads) { // last handle closed on POSIX-deleted file ERR("fileref %p: open_count now %i\n", fileref, oc);
LIST_ENTRY rollback; #endif
InitializeListHead(&rollback); if (oc == 0 || (fileref->delete_on_close && fileref->posix_delete)) {
if (!fcb->Vcb->removing) {
if (oc == 0 && fileref->fcb->inode_item.st_nlink == 0 && fileref != fcb->Vcb->root_fileref &&
fcb != fcb->Vcb->volume_fcb && !fcb->ads) { // last handle closed on POSIX-deleted file
LIST_ENTRY rollback;
Status = delete_fileref_fcb(fileref, FileObject, Irp, &rollback); InitializeListHead(&rollback);
if (!NT_SUCCESS(Status)) {
ERR("delete_fileref_fcb returned %08lx\n", Status);
do_rollback(fcb->Vcb, &rollback);
ExReleaseResourceLite(fileref->fcb->Header.Resource);
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
goto exit;
}
clear_rollback(&rollback); Status = delete_fileref_fcb(fileref, FileObject, Irp, &rollback);
if (!NT_SUCCESS(Status)) {
ERR("delete_fileref_fcb returned %08lx\n", Status);
do_rollback(fcb->Vcb, &rollback);
ExReleaseResourceLite(fileref->fcb->Header.Resource);
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
goto exit;
}
mark_fcb_dirty(fileref->fcb); clear_rollback(&rollback);
} else if (fileref->delete_on_close && fileref != fcb->Vcb->root_fileref && fcb != fcb->Vcb->volume_fcb) {
LIST_ENTRY rollback;
InitializeListHead(&rollback); mark_fcb_dirty(fileref->fcb);
} else if (fileref->delete_on_close && fileref != fcb->Vcb->root_fileref && fcb != fcb->Vcb->volume_fcb) {
LIST_ENTRY rollback;
if (!fileref->fcb->ads || fileref->dc) { InitializeListHead(&rollback);
if (fileref->fcb->ads) {
send_notification_fileref(fileref->parent, fcb->type == BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_REMOVED, &fileref->dc->name);
} else
send_notification_fileref(fileref, fcb->type == BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED, NULL);
}
ExReleaseResourceLite(fcb->Header.Resource); if (!fileref->fcb->ads || fileref->dc) {
locked = false; if (fileref->fcb->ads) {
send_notification_fileref(fileref->parent, fcb->type == BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_REMOVED, &fileref->dc->name);
} else
send_notification_fileref(fileref, fcb->type == BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED, NULL);
}
// fileref_lock needs to be acquired before fcb->Header.Resource
ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, true);
Status = delete_fileref(fileref, FileObject, oc > 0 && fileref->posix_delete, Irp, &rollback);
if (!NT_SUCCESS(Status)) {
ERR("delete_fileref returned %08lx\n", Status);
do_rollback(fcb->Vcb, &rollback);
ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
goto exit;
}
ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
clear_rollback(&rollback);
} else if (FileObject->Flags & FO_CACHE_SUPPORTED && FileObject->SectionObjectPointer->DataSectionObject) {
IO_STATUS_BLOCK iosb;
if (locked) {
ExReleaseResourceLite(fcb->Header.Resource); ExReleaseResourceLite(fcb->Header.Resource);
locked = false; locked = false;
// fileref_lock needs to be acquired before fcb->Header.Resource
ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, true);
Status = delete_fileref(fileref, FileObject, oc > 0 && fileref->posix_delete, Irp, &rollback);
if (!NT_SUCCESS(Status)) {
ERR("delete_fileref returned %08lx\n", Status);
do_rollback(fcb->Vcb, &rollback);
ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
goto exit;
}
ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
clear_rollback(&rollback);
} else if (FileObject->Flags & FO_CACHE_SUPPORTED && FileObject->SectionObjectPointer->DataSectionObject) {
IO_STATUS_BLOCK iosb;
if (locked) {
ExReleaseResourceLite(fcb->Header.Resource);
locked = false;
}
CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb);
if (!NT_SUCCESS(iosb.Status))
ERR("CcFlushCache returned %08lx\n", iosb.Status);
if (!ExIsResourceAcquiredSharedLite(fcb->Header.PagingIoResource)) {
ExAcquireResourceExclusiveLite(fcb->Header.PagingIoResource, true);
ExReleaseResourceLite(fcb->Header.PagingIoResource);
}
CcPurgeCacheSection(FileObject->SectionObjectPointer, NULL, 0, false);
TRACE("flushed cache on close (FileObject = %p, fcb = %p, AllocationSize = %I64x, FileSize = %I64x, ValidDataLength = %I64x)\n",
FileObject, fcb, fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
} }
CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb);
if (!NT_SUCCESS(iosb.Status))
ERR("CcFlushCache returned %08lx\n", iosb.Status);
if (!ExIsResourceAcquiredSharedLite(fcb->Header.PagingIoResource)) {
ExAcquireResourceExclusiveLite(fcb->Header.PagingIoResource, true);
ExReleaseResourceLite(fcb->Header.PagingIoResource);
}
CcPurgeCacheSection(FileObject->SectionObjectPointer, NULL, 0, false);
TRACE("flushed cache on close (FileObject = %p, fcb = %p, AllocationSize = %I64x, FileSize = %I64x, ValidDataLength = %I64x)\n",
FileObject, fcb, fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
} }
}
if (fcb->Vcb && fcb != fcb->Vcb->volume_fcb) if (fcb->Vcb && fcb != fcb->Vcb->volume_fcb)
CcUninitializeCacheMap(FileObject, NULL, NULL); CcUninitializeCacheMap(FileObject, NULL, NULL);
}
} }
if (locked) if (locked)
@ -2860,6 +2854,8 @@ static NTSTATUS read_superblock(_In_ device_extension* Vcb, _In_ PDEVICE_OBJECT
if (sb->sector_size == 0) if (sb->sector_size == 0)
WARN("superblock sector size was 0\n"); WARN("superblock sector size was 0\n");
else if (sb->sector_size & (sb->sector_size - 1))
WARN("superblock sector size was not power of 2\n");
else if (sb->node_size < sizeof(tree_header) + sizeof(internal_node) || sb->node_size > 0x10000) else if (sb->node_size < sizeof(tree_header) + sizeof(internal_node) || sb->node_size > 0x10000)
WARN("invalid node size %x\n", sb->node_size); WARN("invalid node size %x\n", sb->node_size);
else if ((sb->node_size % sb->sector_size) != 0) else if ((sb->node_size % sb->sector_size) != 0)
@ -3715,7 +3711,7 @@ void protect_superblocks(_Inout_ chunk* c) {
// I realize this confuses physical and logical addresses, but this is what btrfs-progs does - // I realize this confuses physical and logical addresses, but this is what btrfs-progs does -
// evidently Linux assumes the chunk at 0 is always SINGLE. // evidently Linux assumes the chunk at 0 is always SINGLE.
if (c->offset < superblock_addrs[0]) if (c->offset < superblock_addrs[0])
space_list_subtract(c, false, c->offset, superblock_addrs[0] - c->offset, NULL); space_list_subtract(c, c->offset, superblock_addrs[0] - c->offset, NULL);
while (superblock_addrs[i] != 0) { while (superblock_addrs[i] != 0) {
CHUNK_ITEM* ci = c->chunk_item; CHUNK_ITEM* ci = c->chunk_item;
@ -3746,7 +3742,7 @@ void protect_superblocks(_Inout_ chunk* c) {
TRACE("startoff = %I64x, superblock = %I64x\n", startoff + cis[j].offset, superblock_addrs[i]); TRACE("startoff = %I64x, superblock = %I64x\n", startoff + cis[j].offset, superblock_addrs[i]);
#endif #endif
space_list_subtract(c, false, c->offset + off_start, off_end - off_start, NULL); space_list_subtract(c, c->offset + off_start, off_end - off_start, NULL);
} }
} }
} else if (ci->type & BLOCK_FLAG_RAID5) { } else if (ci->type & BLOCK_FLAG_RAID5) {
@ -3765,7 +3761,7 @@ void protect_superblocks(_Inout_ chunk* c) {
TRACE("cutting out %I64x, size %I64x\n", c->offset + off_start, off_end - off_start); TRACE("cutting out %I64x, size %I64x\n", c->offset + off_start, off_end - off_start);
space_list_subtract(c, false, c->offset + off_start, off_end - off_start, NULL); space_list_subtract(c, c->offset + off_start, off_end - off_start, NULL);
} }
} }
} else if (ci->type & BLOCK_FLAG_RAID6) { } else if (ci->type & BLOCK_FLAG_RAID6) {
@ -3784,7 +3780,7 @@ void protect_superblocks(_Inout_ chunk* c) {
TRACE("cutting out %I64x, size %I64x\n", c->offset + off_start, off_end - off_start); TRACE("cutting out %I64x, size %I64x\n", c->offset + off_start, off_end - off_start);
space_list_subtract(c, false, c->offset + off_start, off_end - off_start, NULL); space_list_subtract(c, c->offset + off_start, off_end - off_start, NULL);
} }
} }
} else { // SINGLE, DUPLICATE, RAID1, RAID1C3, RAID1C4 } else { // SINGLE, DUPLICATE, RAID1, RAID1C3, RAID1C4
@ -3797,7 +3793,7 @@ void protect_superblocks(_Inout_ chunk* c) {
off_start = ((superblock_addrs[i] - cis[j].offset) / c->chunk_item->stripe_length) * c->chunk_item->stripe_length; off_start = ((superblock_addrs[i] - cis[j].offset) / c->chunk_item->stripe_length) * c->chunk_item->stripe_length;
off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), c->chunk_item->stripe_length); off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), c->chunk_item->stripe_length);
space_list_subtract(c, false, c->offset + off_start, off_end - off_start, NULL); space_list_subtract(c, c->offset + off_start, off_end - off_start, NULL);
} }
} }
} }
@ -4320,6 +4316,17 @@ static bool still_has_superblock(_In_ PDEVICE_OBJECT device, _In_ PFILE_OBJECT f
return true; return true;
} }
static void calculate_sector_shift(device_extension* Vcb) {
uint32_t ss = Vcb->superblock.sector_size;
Vcb->sector_shift = 0;
while (!(ss & 1)) {
Vcb->sector_shift++;
ss >>= 1;
}
}
static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
PIO_STACK_LOCATION IrpSp; PIO_STACK_LOCATION IrpSp;
PDEVICE_OBJECT NewDeviceObject = NULL; PDEVICE_OBJECT NewDeviceObject = NULL;
@ -4561,6 +4568,8 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
if (Vcb->options.readonly) if (Vcb->options.readonly)
Vcb->readonly = true; Vcb->readonly = true;
calculate_sector_shift(Vcb);
Vcb->superblock.generation++; Vcb->superblock.generation++;
Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF; Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF;
@ -5150,6 +5159,8 @@ static NTSTATUS verify_volume(_In_ PDEVICE_OBJECT devobj) {
return STATUS_WRONG_VOLUME; return STATUS_WRONG_VOLUME;
} }
Status = STATUS_SUCCESS;
InterlockedIncrement(&Vcb->open_files); // so pnp_surprise_removal doesn't uninit the device while we're still using it InterlockedIncrement(&Vcb->open_files); // so pnp_surprise_removal doesn't uninit the device while we're still using it
le = Vcb->devices.Flink; le = Vcb->devices.Flink;
@ -5877,17 +5888,24 @@ 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() {
unsigned int cpuInfo[4];
bool have_sse42; bool have_sse42;
#ifndef _MSC_VER #ifndef _MSC_VER
__get_cpuid(1, &cpuInfo[0], &cpuInfo[1], &cpuInfo[2], &cpuInfo[3]); {
have_sse42 = cpuInfo[2] & bit_SSE4_2; uint32_t eax, ebx, ecx, edx;
have_sse2 = cpuInfo[3] & bit_SSE2;
__cpuid(1, eax, ebx, ecx, edx);
have_sse42 = ecx & bit_SSE4_2;
have_sse2 = edx & bit_SSE2;
}
#else #else
__cpuid(cpuInfo, 1); {
have_sse42 = cpuInfo[2] & (1 << 20); unsigned int cpu_info[4];
have_sse2 = cpuInfo[3] & (1 << 26);
__cpuid(cpu_info, 1);
have_sse42 = cpu_info[2] & (1 << 20);
have_sse2 = cpu_info[3] & (1 << 26);
}
#endif #endif
if (have_sse42) { if (have_sse42) {
@ -6091,7 +6109,7 @@ NTSTATUS __stdcall AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT Physica
*anp = ')'; *anp = ')';
Status = IoCreateDevice(drvobj, sizeof(volume_device_extension), &volname, FILE_DEVICE_DISK, Status = IoCreateDevice(drvobj, sizeof(volume_device_extension), &volname, FILE_DEVICE_DISK,
WdmlibRtlIsNtDdiVersionAvailable(NTDDI_WIN8) ? FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL : 0, false, &voldev); is_windows_8 ? FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL : 0, false, &voldev);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("IoCreateDevice returned %08lx\n", Status); ERR("IoCreateDevice returned %08lx\n", Status);
goto end2; goto end2;
@ -6162,6 +6180,17 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S
HANDLE regh; HANDLE regh;
OBJECT_ATTRIBUTES oa, system_thread_attributes; OBJECT_ATTRIBUTES oa, system_thread_attributes;
ULONG dispos; ULONG dispos;
RTL_OSVERSIONINFOW ver;
ver.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);
Status = RtlGetVersion(&ver);
if (!NT_SUCCESS(Status)) {
ERR("RtlGetVersion returned %08lx\n", Status);
return Status;
}
is_windows_8 = ver.dwMajorVersion > 6 || (ver.dwMajorVersion == 6 && ver.dwMinorVersion >= 2);
InitializeListHead(&uid_map_list); InitializeListHead(&uid_map_list);
InitializeListHead(&gid_map_list); InitializeListHead(&gid_map_list);
@ -6201,7 +6230,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S
check_cpu(); check_cpu();
#endif #endif
if (WdmlibRtlIsNtDdiVersionAvailable(NTDDI_WIN8)) { if (ver.dwMajorVersion > 6 || (ver.dwMajorVersion == 6 && ver.dwMinorVersion >= 2)) { // Windows 8 or above
UNICODE_STRING name; UNICODE_STRING name;
tPsIsDiskCountersEnabled fPsIsDiskCountersEnabled; tPsIsDiskCountersEnabled fPsIsDiskCountersEnabled;
@ -6241,7 +6270,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S
fFsRtlCheckLockForOplockRequest = NULL; fFsRtlCheckLockForOplockRequest = NULL;
} }
if (WdmlibRtlIsNtDdiVersionAvailable(NTDDI_WIN7)) { if (ver.dwMajorVersion > 6 || (ver.dwMajorVersion == 6 && ver.dwMinorVersion >= 1)) { // Windows 7 or above
UNICODE_STRING name; UNICODE_STRING name;
RtlInitUnicodeString(&name, L"IoUnregisterPlugPlayNotificationEx"); RtlInitUnicodeString(&name, L"IoUnregisterPlugPlayNotificationEx");
@ -6254,7 +6283,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S
fFsRtlAreThereCurrentOrInProgressFileLocks = NULL; fFsRtlAreThereCurrentOrInProgressFileLocks = NULL;
} }
if (WdmlibRtlIsNtDdiVersionAvailable(NTDDI_VISTA)) { if (ver.dwMajorVersion >= 6) { // Windows Vista or above
UNICODE_STRING name; UNICODE_STRING name;
RtlInitUnicodeString(&name, L"FsRtlGetEcpListFromIrp"); RtlInitUnicodeString(&name, L"FsRtlGetEcpListFromIrp");

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 = 04/10/2020,1.7.2.0 DriverVer = 05/24/2020,1.7.3.0
CatalogFile = btrfs.cat CatalogFile = btrfs.cat
[DestinationDirs] [DestinationDirs]

View file

@ -25,18 +25,18 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
// TEXTINCLUDE // TEXTINCLUDE
// //
1 TEXTINCLUDE 1 TEXTINCLUDE
BEGIN BEGIN
"resource.h\0" "resource.h\0"
END END
2 TEXTINCLUDE 2 TEXTINCLUDE
BEGIN BEGIN
"#include ""winres.h""\r\n" "#include ""winres.h""\r\n"
"\0" "\0"
END END
3 TEXTINCLUDE 3 TEXTINCLUDE
BEGIN BEGIN
"\r\n" "\r\n"
"\0" "\0"
@ -51,8 +51,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,7,2,0 FILEVERSION 1,7,3,0
PRODUCTVERSION 1,7,2,0 PRODUCTVERSION 1,7,3,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.7.2" VALUE "FileVersion", "1.7.3"
VALUE "InternalName", "btrfs" VALUE "InternalName", "btrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-20" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-20"
VALUE "OriginalFilename", "btrfs.sys" VALUE "OriginalFilename", "btrfs.sys"
VALUE "ProductName", "WinBtrfs" VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "1.7.2" VALUE "ProductVersion", "1.7.3"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -775,6 +775,7 @@ typedef struct _device_extension {
#endif #endif
uint64_t devices_loaded; uint64_t devices_loaded;
superblock superblock; superblock superblock;
unsigned int sector_shift;
unsigned int csum_size; unsigned int csum_size;
bool readonly; bool readonly;
bool removing; bool removing;
@ -1291,25 +1292,30 @@ static const char lxdev[] = "$LXDEV";
// in treefuncs.c // in treefuncs.c
NTSTATUS find_item(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _Out_ traverse_ptr* tp, 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); _In_ const KEY* searchkey, _In_ bool ignore, _In_opt_ PIRP Irp) __attribute__((nonnull(1,2,3,4)));
NTSTATUS find_item_to_level(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, bool ignore, uint8_t level, PIRP Irp); NTSTATUS find_item_to_level(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, bool ignore,
bool find_next_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* next_tp, bool ignore, PIRP Irp); uint8_t level, PIRP Irp) __attribute__((nonnull(1,2,3,4)));
bool find_prev_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* prev_tp, PIRP Irp); bool find_next_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, const traverse_ptr* tp,
void free_trees(device_extension* Vcb); traverse_ptr* next_tp, bool ignore, PIRP Irp) __attribute__((nonnull(1,2,3)));
bool find_prev_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, const traverse_ptr* tp,
traverse_ptr* prev_tp, PIRP Irp) __attribute__((nonnull(1,2,3)));
void free_trees(device_extension* Vcb) __attribute__((nonnull(1)));
NTSTATUS insert_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _In_ uint64_t obj_id, NTSTATUS insert_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _In_ uint64_t obj_id,
_In_ uint8_t obj_type, _In_ uint64_t offset, _In_reads_bytes_opt_(size) _When_(return >= 0, __drv_aliasesMem) void* data, _In_ uint8_t obj_type, _In_ uint64_t offset, _In_reads_bytes_opt_(size) _When_(return >= 0, __drv_aliasesMem) void* data,
_In_ uint16_t size, _Out_opt_ traverse_ptr* ptp, _In_opt_ PIRP Irp); _In_ uint16_t size, _Out_opt_ traverse_ptr* ptp, _In_opt_ PIRP Irp) __attribute__((nonnull(1,2)));
NTSTATUS delete_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _Inout_ traverse_ptr* tp); NTSTATUS delete_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb,
void free_tree(tree* t); _Inout_ traverse_ptr* tp) __attribute__((nonnull(1,2)));
NTSTATUS load_tree(device_extension* Vcb, uint64_t addr, uint8_t* buf, root* r, tree** pt); void free_tree(tree* t) __attribute__((nonnull(1)));
NTSTATUS do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, PIRP Irp); NTSTATUS load_tree(device_extension* Vcb, uint64_t addr, uint8_t* buf, root* r, tree** pt) __attribute__((nonnull(1,3,4,5)));
void clear_rollback(LIST_ENTRY* rollback); NTSTATUS do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, PIRP Irp) __attribute__((nonnull(1,2,3)));
void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback); void clear_rollback(LIST_ENTRY* rollback) __attribute__((nonnull(1)));
void free_trees_root(device_extension* Vcb, root* r); void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) __attribute__((nonnull(1,2)));
void add_rollback(_In_ LIST_ENTRY* rollback, _In_ enum rollback_type type, _In_ __drv_aliasesMem void* ptr); void free_trees_root(device_extension* Vcb, root* r) __attribute__((nonnull(1,2)));
NTSTATUS commit_batch_list(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, LIST_ENTRY* batchlist, PIRP Irp); void add_rollback(_In_ LIST_ENTRY* rollback, _In_ enum rollback_type type, _In_ __drv_aliasesMem void* ptr) __attribute__((nonnull(1,3)));
void clear_batch_list(device_extension* Vcb, LIST_ENTRY* batchlist); NTSTATUS commit_batch_list(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb,
NTSTATUS skip_to_difference(device_extension* Vcb, traverse_ptr* tp, traverse_ptr* tp2, bool* ended1, bool* ended2); LIST_ENTRY* batchlist, PIRP Irp) __attribute__((nonnull(1,2)));
void clear_batch_list(device_extension* Vcb, LIST_ENTRY* batchlist) __attribute__((nonnull(1,2)));
NTSTATUS skip_to_difference(device_extension* Vcb, traverse_ptr* tp, traverse_ptr* tp2, bool* ended1, bool* ended2) __attribute__((nonnull(1,2,3,4,5)));
// in search.c // in search.c
NTSTATUS remove_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath); NTSTATUS remove_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath);
@ -1335,35 +1341,36 @@ void init_cache();
extern CACHE_MANAGER_CALLBACKS cache_callbacks; extern CACHE_MANAGER_CALLBACKS cache_callbacks;
// in write.c // in write.c
NTSTATUS write_file(device_extension* Vcb, PIRP Irp, bool wait, bool deferred_write); NTSTATUS write_file(device_extension* Vcb, PIRP Irp, bool wait, bool deferred_write) __attribute__((nonnull(1,2)));
NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void* buf, ULONG* length, bool paging_io, bool no_cache, NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void* buf, ULONG* length, bool paging_io, bool no_cache,
bool wait, bool deferred_write, bool write_irp, LIST_ENTRY* rollback); bool wait, bool deferred_write, bool write_irp, LIST_ENTRY* rollback) __attribute__((nonnull(1,2,4,5,11)));
NTSTATUS truncate_file(fcb* fcb, uint64_t end, PIRP Irp, LIST_ENTRY* rollback); NTSTATUS truncate_file(fcb* fcb, uint64_t end, PIRP Irp, LIST_ENTRY* rollback) __attribute__((nonnull(1,4)));
NTSTATUS extend_file(fcb* fcb, file_ref* fileref, uint64_t end, bool prealloc, PIRP Irp, LIST_ENTRY* rollback); NTSTATUS extend_file(fcb* fcb, file_ref* fileref, uint64_t end, bool prealloc, PIRP Irp, LIST_ENTRY* rollback) __attribute__((nonnull(1,6)));
NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, uint64_t end_data, PIRP Irp, LIST_ENTRY* rollback); NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, uint64_t end_data, PIRP Irp, LIST_ENTRY* rollback) __attribute__((nonnull(1,2,6)));
chunk* get_chunk_from_address(device_extension* Vcb, uint64_t address); chunk* get_chunk_from_address(device_extension* Vcb, uint64_t address) __attribute__((nonnull(1)));
NTSTATUS alloc_chunk(device_extension* Vcb, uint64_t flags, chunk** pc, bool full_size); NTSTATUS alloc_chunk(device_extension* Vcb, uint64_t flags, chunk** pc, bool full_size) __attribute__((nonnull(1,3)));
NTSTATUS write_data(_In_ device_extension* Vcb, _In_ uint64_t address, _In_reads_bytes_(length) void* data, _In_ uint32_t length, _In_ write_data_context* wtc, NTSTATUS write_data(_In_ device_extension* Vcb, _In_ uint64_t address, _In_reads_bytes_(length) void* data, _In_ uint32_t length, _In_ write_data_context* wtc,
_In_opt_ PIRP Irp, _In_opt_ chunk* c, _In_ bool file_write, _In_ uint64_t irp_offset, _In_ ULONG priority); _In_opt_ PIRP Irp, _In_opt_ chunk* c, _In_ bool file_write, _In_ uint64_t irp_offset, _In_ ULONG priority) __attribute__((nonnull(1,3,5)));
NTSTATUS write_data_complete(device_extension* Vcb, uint64_t address, void* data, uint32_t length, PIRP Irp, chunk* c, bool file_write, uint64_t irp_offset, ULONG priority); NTSTATUS write_data_complete(device_extension* Vcb, uint64_t address, void* data, uint32_t length, PIRP Irp, chunk* c, bool file_write,
void free_write_data_stripes(write_data_context* wtc); uint64_t irp_offset, ULONG priority) __attribute__((nonnull(1,3)));
void free_write_data_stripes(write_data_context* wtc) __attribute__((nonnull(1)));
_Dispatch_type_(IRP_MJ_WRITE) _Dispatch_type_(IRP_MJ_WRITE)
_Function_class_(DRIVER_DISPATCH) _Function_class_(DRIVER_DISPATCH)
NTSTATUS __stdcall drv_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS __stdcall drv_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) __attribute__((nonnull(1,2)));
_Requires_lock_held_(c->lock) _Requires_lock_held_(c->lock)
_When_(return != 0, _Releases_lock_(c->lock)) _When_(return != 0, _Releases_lock_(c->lock))
bool insert_extent_chunk(_In_ device_extension* Vcb, _In_ fcb* fcb, _In_ chunk* c, _In_ uint64_t start_data, _In_ uint64_t length, _In_ bool prealloc, _In_opt_ void* data, bool insert_extent_chunk(_In_ device_extension* Vcb, _In_ fcb* fcb, _In_ chunk* c, _In_ uint64_t start_data, _In_ uint64_t length, _In_ bool prealloc,
_In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback, _In_ uint8_t compression, _In_ uint64_t decoded_size, _In_ bool file_write, _In_ uint64_t irp_offset); _In_opt_ void* data, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback, _In_ uint8_t compression, _In_ uint64_t decoded_size,
_In_ bool file_write, _In_ uint64_t irp_offset) __attribute__((nonnull(1,2,3,9)));
NTSTATUS do_write_file(fcb* fcb, uint64_t start_data, uint64_t end_data, void* data, PIRP Irp, bool file_write, uint32_t irp_offset, LIST_ENTRY* rollback); NTSTATUS do_write_file(fcb* fcb, uint64_t start_data, uint64_t end_data, void* data, PIRP Irp, bool file_write, uint32_t irp_offset, LIST_ENTRY* rollback) __attribute__((nonnull(1, 4)));
bool find_data_address_in_chunk(device_extension* Vcb, chunk* c, uint64_t length, uint64_t* address); bool find_data_address_in_chunk(device_extension* Vcb, chunk* c, uint64_t length, uint64_t* address) __attribute__((nonnull(1, 2, 4)));
void get_raid56_lock_range(chunk* c, uint64_t address, uint64_t length, uint64_t* lockaddr, uint64_t* locklen); void get_raid56_lock_range(chunk* c, uint64_t address, uint64_t length, uint64_t* lockaddr, uint64_t* locklen) __attribute__((nonnull(1,4,5)));
void add_insert_extent_rollback(LIST_ENTRY* rollback, fcb* fcb, extent* ext);
NTSTATUS add_extent_to_fcb(_In_ fcb* fcb, _In_ uint64_t offset, _In_reads_bytes_(edsize) EXTENT_DATA* ed, _In_ uint16_t edsize, NTSTATUS add_extent_to_fcb(_In_ fcb* fcb, _In_ uint64_t offset, _In_reads_bytes_(edsize) EXTENT_DATA* ed, _In_ uint16_t edsize,
_In_ bool unique, _In_opt_ _When_(return >= 0, __drv_aliasesMem) void* csum, _In_ LIST_ENTRY* rollback); _In_ bool unique, _In_opt_ _When_(return >= 0, __drv_aliasesMem) void* csum, _In_ LIST_ENTRY* rollback) __attribute__((nonnull(1,3,7)));
void add_extent(_In_ fcb* fcb, _In_ LIST_ENTRY* prevextle, _In_ __drv_aliasesMem extent* newext); void add_extent(_In_ fcb* fcb, _In_ LIST_ENTRY* prevextle, _In_ __drv_aliasesMem extent* newext) __attribute__((nonnull(1,2,3)));
// in dirctrl.c // in dirctrl.c
@ -1483,8 +1490,8 @@ NTSTATUS __stdcall drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS read_data(_In_ device_extension* Vcb, _In_ uint64_t addr, _In_ uint32_t length, _In_reads_bytes_opt_(length*sizeof(uint32_t)/Vcb->superblock.sector_size) void* csum, NTSTATUS read_data(_In_ device_extension* Vcb, _In_ uint64_t addr, _In_ uint32_t length, _In_reads_bytes_opt_(length*sizeof(uint32_t)/Vcb->superblock.sector_size) void* csum,
_In_ bool is_tree, _Out_writes_bytes_(length) uint8_t* buf, _In_opt_ chunk* c, _Out_opt_ chunk** pc, _In_opt_ PIRP Irp, _In_ uint64_t generation, _In_ bool file_read, _In_ bool is_tree, _Out_writes_bytes_(length) uint8_t* buf, _In_opt_ chunk* c, _Out_opt_ chunk** pc, _In_opt_ PIRP Irp, _In_ uint64_t generation, _In_ bool file_read,
_In_ ULONG priority); _In_ ULONG priority);
NTSTATUS read_file(fcb* fcb, uint8_t* data, uint64_t start, uint64_t length, ULONG* pbr, PIRP Irp); NTSTATUS read_file(fcb* fcb, uint8_t* data, uint64_t start, uint64_t length, ULONG* pbr, PIRP Irp) __attribute__((nonnull(1, 2)));
NTSTATUS read_stream(fcb* fcb, uint8_t* data, uint64_t start, ULONG length, ULONG* pbr); NTSTATUS read_stream(fcb* fcb, uint8_t* data, uint64_t start, ULONG length, ULONG* pbr) __attribute__((nonnull(1, 2)));
NTSTATUS do_read(PIRP Irp, bool wait, ULONG* bytes_read); NTSTATUS do_read(PIRP Irp, bool wait, ULONG* bytes_read);
NTSTATUS check_csum(device_extension* Vcb, uint8_t* data, uint32_t sectors, void* csum); NTSTATUS check_csum(device_extension* Vcb, uint8_t* data, uint32_t sectors, void* csum);
void raid6_recover2(uint8_t* sectors, uint16_t num_stripes, ULONG sector_size, uint16_t missing1, uint16_t missing2, uint8_t* out); void raid6_recover2(uint8_t* sectors, uint16_t num_stripes, ULONG sector_size, uint16_t missing1, uint16_t missing2, uint8_t* out);
@ -1511,8 +1518,9 @@ NTSTATUS update_chunk_caches_tree(device_extension* Vcb, PIRP Irp);
NTSTATUS add_space_entry(LIST_ENTRY* list, LIST_ENTRY* list_size, uint64_t offset, uint64_t size); NTSTATUS add_space_entry(LIST_ENTRY* list, LIST_ENTRY* list_size, uint64_t offset, uint64_t size);
void space_list_add(chunk* c, uint64_t address, uint64_t length, LIST_ENTRY* rollback); void space_list_add(chunk* c, uint64_t address, uint64_t length, LIST_ENTRY* rollback);
void space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, uint64_t address, uint64_t length, chunk* c, LIST_ENTRY* rollback); void space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, uint64_t address, uint64_t length, chunk* c, LIST_ENTRY* rollback);
void space_list_subtract(chunk* c, bool deleting, uint64_t address, uint64_t length, LIST_ENTRY* rollback); void space_list_subtract(chunk* c, uint64_t address, uint64_t length, LIST_ENTRY* rollback);
void space_list_subtract2(LIST_ENTRY* list, LIST_ENTRY* list_size, uint64_t address, uint64_t length, chunk* c, LIST_ENTRY* rollback); void space_list_subtract2(LIST_ENTRY* list, LIST_ENTRY* list_size, uint64_t address, uint64_t length, chunk* c, LIST_ENTRY* rollback);
void space_list_merge(LIST_ENTRY* spacelist, LIST_ENTRY* spacelist_size, LIST_ENTRY* deleting);
NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, bool load_only, PIRP Irp); NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, bool load_only, PIRP Irp);
// in extent-tree.c // in extent-tree.c

View file

@ -993,7 +993,7 @@ NTSTATUS write_compressed(fcb* fcb, uint64_t start_data, uint64_t end_data, void
else if (type == BTRFS_COMPRESSION_ZSTD) else if (type == BTRFS_COMPRESSION_ZSTD)
fcb->Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD; fcb->Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD;
if ((parts[i].outlen % fcb->Vcb->superblock.sector_size) != 0) { if ((parts[i].outlen & (fcb->Vcb->superblock.sector_size - 1)) != 0) {
unsigned int newlen = (unsigned int)sector_align(parts[i].outlen, fcb->Vcb->superblock.sector_size); unsigned int newlen = (unsigned int)sector_align(parts[i].outlen, fcb->Vcb->superblock.sector_size);
RtlZeroMemory(parts[i].buf + parts[i].outlen, newlen - parts[i].outlen); RtlZeroMemory(parts[i].buf + parts[i].outlen, newlen - parts[i].outlen);
@ -1083,7 +1083,7 @@ NTSTATUS write_compressed(fcb* fcb, uint64_t start_data, uint64_t end_data, void
if (find_data_address_in_chunk(fcb->Vcb, c2, buflen, &address)) { if (find_data_address_in_chunk(fcb->Vcb, c2, buflen, &address)) {
c = c2; c = c2;
c->used += buflen; c->used += buflen;
space_list_subtract(c, false, address, buflen, rollback); space_list_subtract(c, address, buflen, rollback);
release_chunk_lock(c2, fcb->Vcb); release_chunk_lock(c2, fcb->Vcb);
break; break;
} }
@ -1118,7 +1118,7 @@ NTSTATUS write_compressed(fcb* fcb, uint64_t start_data, uint64_t end_data, void
if (find_data_address_in_chunk(fcb->Vcb, c2, buflen, &address)) { if (find_data_address_in_chunk(fcb->Vcb, c2, buflen, &address)) {
c = c2; c = c2;
c->used += buflen; c->used += buflen;
space_list_subtract(c, false, address, buflen, rollback); space_list_subtract(c, address, buflen, rollback);
} }
release_chunk_lock(c2, fcb->Vcb); release_chunk_lock(c2, fcb->Vcb);
@ -1149,7 +1149,7 @@ NTSTATUS write_compressed(fcb* fcb, uint64_t start_data, uint64_t end_data, void
// calculate csums if necessary // calculate csums if necessary
if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) { if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) {
unsigned int sl = buflen / fcb->Vcb->superblock.sector_size; unsigned int sl = buflen >> fcb->Vcb->sector_shift;
csum = ExAllocatePoolWithTag(PagedPool, sl * fcb->Vcb->csum_size, ALLOC_TAG); csum = ExAllocatePoolWithTag(PagedPool, sl * fcb->Vcb->csum_size, ALLOC_TAG);
if (!csum) { if (!csum) {
@ -1198,7 +1198,7 @@ NTSTATUS write_compressed(fcb* fcb, uint64_t start_data, uint64_t end_data, void
ed2->num_bytes = parts[i].inlen; ed2->num_bytes = parts[i].inlen;
if (csum) { if (csum) {
csum2 = ExAllocatePoolWithTag(PagedPool, parts[i].outlen * fcb->Vcb->csum_size / fcb->Vcb->superblock.sector_size, ALLOC_TAG); csum2 = ExAllocatePoolWithTag(PagedPool, (parts[i].outlen * fcb->Vcb->csum_size) >> fcb->Vcb->sector_shift, ALLOC_TAG);
if (!csum2) { if (!csum2) {
ERR("out of memory\n"); ERR("out of memory\n");
ExFreePool(ed); ExFreePool(ed);
@ -1207,8 +1207,8 @@ NTSTATUS write_compressed(fcb* fcb, uint64_t start_data, uint64_t end_data, void
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
RtlCopyMemory(csum2, (uint8_t*)csum + ((extaddr - address) * fcb->Vcb->csum_size / fcb->Vcb->superblock.sector_size), RtlCopyMemory(csum2, (uint8_t*)csum + (((extaddr - address) * fcb->Vcb->csum_size) >> fcb->Vcb->sector_shift),
parts[i].outlen * fcb->Vcb->csum_size / fcb->Vcb->superblock.sector_size); (parts[i].outlen * fcb->Vcb->csum_size) >> fcb->Vcb->sector_shift);
} else } else
csum2 = NULL; csum2 = NULL;

View file

@ -43,6 +43,10 @@ static const WCHAR root_dir_utf16[] = L"$Root";
#define ATOMIC_CREATE_ECP_IN_OP_FLAG_CASE_SENSITIVE_FLAGS_SPECIFIED 1 #define ATOMIC_CREATE_ECP_IN_OP_FLAG_CASE_SENSITIVE_FLAGS_SPECIFIED 1
#define ATOMIC_CREATE_ECP_OUT_OP_FLAG_CASE_SENSITIVE_FLAGS_SET 1 #define ATOMIC_CREATE_ECP_OUT_OP_FLAG_CASE_SENSITIVE_FLAGS_SET 1
#ifndef SL_IGNORE_READONLY_ATTRIBUTE
#define SL_IGNORE_READONLY_ATTRIBUTE 0x40 // introduced in Windows 10, not in mingw
#endif
typedef struct _FILE_TIMESTAMPS { typedef struct _FILE_TIMESTAMPS {
LARGE_INTEGER CreationTime; LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastAccessTime;
@ -469,10 +473,10 @@ NTSTATUS load_csum(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb
if (start < tp.item->key.offset) if (start < tp.item->key.offset)
j = 0; j = 0;
else else
j = ((start - tp.item->key.offset) / Vcb->superblock.sector_size) + i; j = ((start - tp.item->key.offset) >> Vcb->sector_shift) + i;
if (j * Vcb->csum_size > tp.item->size || tp.item->key.offset > start + (i * Vcb->superblock.sector_size)) { if (j * Vcb->csum_size > tp.item->size || tp.item->key.offset > start + (i << Vcb->sector_shift)) {
ERR("checksum not found for %I64x\n", start + (i * Vcb->superblock.sector_size)); ERR("checksum not found for %I64x\n", start + (i << Vcb->sector_shift));
return STATUS_INTERNAL_ERROR; return STATUS_INTERNAL_ERROR;
} }
@ -2046,23 +2050,29 @@ static NTSTATUS file_create_parse_ea(fcb* fcb, FILE_FULL_EA_INFORMATION* ea) {
goto end; goto end;
} }
RtlCopyMemory(&val, item->value.Buffer, sizeof(uint32_t)); val = *(uint32_t*)item->value.Buffer;
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 &= ~allowed;
fcb->inode_item.st_mode |= val & allowed; fcb->inode_item.st_mode |= val & allowed;
if (fcb->type != BTRFS_TYPE_DIRECTORY) { if (fcb->type != BTRFS_TYPE_DIRECTORY) {
if ((fcb->inode_item.st_mode & __S_IFCHR) == __S_IFCHR) if (__S_ISTYPE(val, __S_IFCHR)) {
fcb->type = BTRFS_TYPE_CHARDEV; fcb->type = BTRFS_TYPE_CHARDEV;
else if ((fcb->inode_item.st_mode & __S_IFBLK) == __S_IFBLK) fcb->inode_item.st_mode &= ~__S_IFMT;
fcb->inode_item.st_mode |= __S_IFCHR;
} else if (__S_ISTYPE(val, __S_IFBLK)) {
fcb->type = BTRFS_TYPE_BLOCKDEV; fcb->type = BTRFS_TYPE_BLOCKDEV;
else if ((fcb->inode_item.st_mode & __S_IFIFO) == __S_IFIFO) fcb->inode_item.st_mode &= ~__S_IFMT;
fcb->inode_item.st_mode |= __S_IFBLK;
} else if (__S_ISTYPE(val, __S_IFIFO)) {
fcb->type = BTRFS_TYPE_FIFO; fcb->type = BTRFS_TYPE_FIFO;
else if ((fcb->inode_item.st_mode & __S_IFSOCK) == __S_IFSOCK) fcb->inode_item.st_mode &= ~__S_IFMT;
fcb->inode_item.st_mode |= __S_IFIFO;
} else if (__S_ISTYPE(val, __S_IFSOCK)) {
fcb->type = BTRFS_TYPE_SOCKET; fcb->type = BTRFS_TYPE_SOCKET;
fcb->inode_item.st_mode &= ~__S_IFMT;
fcb->inode_item.st_mode |= __S_IFSOCK;
}
} }
RemoveEntryList(&item->list_entry); RemoveEntryList(&item->list_entry);
@ -2718,7 +2728,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
} }
if (parfileref->fcb->atts & FILE_ATTRIBUTE_READONLY) { if (parfileref->fcb->atts & FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE)) {
free_fileref(parfileref); free_fileref(parfileref);
return STATUS_ACCESS_DENIED; return STATUS_ACCESS_DENIED;
} }
@ -3011,8 +3021,10 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R
if (Vcb->readonly) if (Vcb->readonly)
return STATUS_MEDIA_WRITE_PROTECTED; return STATUS_MEDIA_WRITE_PROTECTED;
if (options & FILE_DELETE_ON_CLOSE && IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_READONLY) if (options & FILE_DELETE_ON_CLOSE && IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_READONLY &&
!(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE)) {
return STATUS_CANNOT_DELETE; return STATUS_CANNOT_DELETE;
}
if (fFsRtlGetEcpListFromIrp && fFsRtlGetNextExtraCreateParameter) { if (fFsRtlGetEcpListFromIrp && fFsRtlGetNextExtraCreateParameter) {
if (NT_SUCCESS(fFsRtlGetEcpListFromIrp(Irp, &ecp_list)) && ecp_list) { if (NT_SUCCESS(fFsRtlGetEcpListFromIrp(Irp, &ecp_list)) && ecp_list) {
@ -3228,6 +3240,7 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R
if (acec->ReparseBufferLength > sizeof(uint32_t) && *(uint32_t*)acec->ReparseBuffer == IO_REPARSE_TAG_SYMLINK) { if (acec->ReparseBufferLength > sizeof(uint32_t) && *(uint32_t*)acec->ReparseBuffer == IO_REPARSE_TAG_SYMLINK) {
fileref->fcb->inode_item.st_mode &= ~(__S_IFIFO | __S_IFCHR | __S_IFBLK | __S_IFSOCK); fileref->fcb->inode_item.st_mode &= ~(__S_IFIFO | __S_IFCHR | __S_IFBLK | __S_IFSOCK);
fileref->fcb->type = BTRFS_TYPE_FILE; fileref->fcb->type = BTRFS_TYPE_FILE;
fileref->fcb->atts &= ~FILE_ATTRIBUTE_DIRECTORY;
} }
if (fileref->fcb->type == BTRFS_TYPE_SOCKET || fileref->fcb->type == BTRFS_TYPE_FIFO || if (fileref->fcb->type == BTRFS_TYPE_SOCKET || fileref->fcb->type == BTRFS_TYPE_FIFO ||
@ -3545,7 +3558,7 @@ static void fcb_load_csums(_Requires_lock_held_(_Curr_->tree_lock) device_extens
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ext->extent_data.data[0]; EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ext->extent_data.data[0];
uint64_t len; uint64_t len;
len = (ext->extent_data.compression == BTRFS_COMPRESSION_NONE ? ed2->num_bytes : ed2->size) / Vcb->superblock.sector_size; len = (ext->extent_data.compression == BTRFS_COMPRESSION_NONE ? ed2->num_bytes : ed2->size) >> Vcb->sector_shift;
ext->csum = ExAllocatePoolWithTag(NonPagedPool, (ULONG)(len * Vcb->csum_size), ALLOC_TAG); ext->csum = ExAllocatePoolWithTag(NonPagedPool, (ULONG)(len * Vcb->csum_size), ALLOC_TAG);
if (!ext->csum) { if (!ext->csum) {
@ -3633,8 +3646,9 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO
sf = sf->parent; sf = sf->parent;
} }
readonly = (!fileref->fcb->ads && fileref->fcb->atts & FILE_ATTRIBUTE_READONLY) || (fileref->fcb->ads && fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY) || readonly = (!fileref->fcb->ads && fileref->fcb->atts & FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE)) ||
is_subvol_readonly(fileref->fcb->subvol, Irp) || fileref->fcb == Vcb->dummy_fcb || Vcb->readonly; (fileref->fcb->ads && fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE)) ||
is_subvol_readonly(fileref->fcb->subvol, Irp) || fileref->fcb == Vcb->dummy_fcb || Vcb->readonly;
if (options & FILE_DELETE_ON_CLOSE && (fileref == Vcb->root_fileref || readonly)) { if (options & FILE_DELETE_ON_CLOSE && (fileref == Vcb->root_fileref || readonly)) {
free_fileref(fileref); free_fileref(fileref);
@ -4847,6 +4861,11 @@ NTSTATUS __stdcall drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
flags &= ~SL_STOP_ON_SYMLINK; flags &= ~SL_STOP_ON_SYMLINK;
} }
if (flags & SL_IGNORE_READONLY_ATTRIBUTE) {
TRACE("SL_IGNORE_READONLY_ATTRIBUTE\n");
flags &= ~SL_IGNORE_READONLY_ATTRIBUTE;
}
if (flags) if (flags)
WARN("unknown flags: %x\n", flags); WARN("unknown flags: %x\n", flags);
} else { } else {

View file

@ -1024,7 +1024,7 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, uint64_t address, uint6
} }
if (!superseded) if (!superseded)
add_checksum_entry(Vcb, address, (ULONG)(size / Vcb->superblock.sector_size), NULL, Irp); add_checksum_entry(Vcb, address, (ULONG)(size >> Vcb->sector_shift), NULL, Irp);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -1090,7 +1090,7 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, uint64_t address, uint6
} }
if (!superseded) if (!superseded)
add_checksum_entry(Vcb, address, (ULONG)(size / Vcb->superblock.sector_size), NULL, Irp); add_checksum_entry(Vcb, address, (ULONG)(size >> Vcb->sector_shift), NULL, Irp);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -1296,7 +1296,7 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, uint64_t address, uint6
} }
if (!superseded) if (!superseded)
add_checksum_entry(Vcb, address, (ULONG)(size / Vcb->superblock.sector_size), NULL, Irp); add_checksum_entry(Vcb, address, (ULONG)(size >> Vcb->sector_shift), NULL, Irp);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -1379,7 +1379,7 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, uint64_t address, uint6
} }
if (!superseded) if (!superseded)
add_checksum_entry(Vcb, address, (ULONG)(size / Vcb->superblock.sector_size), NULL, Irp); add_checksum_entry(Vcb, address, (ULONG)(size >> Vcb->sector_shift), NULL, Irp);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -1505,7 +1505,7 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, uint64_t address, uint6
} }
if (!superseded) if (!superseded)
add_checksum_entry(Vcb, address, (ULONG)(size / Vcb->superblock.sector_size), NULL, Irp); add_checksum_entry(Vcb, address, (ULONG)(size >> Vcb->sector_shift), NULL, Irp);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }

View file

@ -566,7 +566,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
else else
len = (ULONG)ed2->size; len = (ULONG)ed2->size;
len = len * sizeof(uint32_t) / Vcb->superblock.sector_size; len = (len * sizeof(uint32_t)) >> Vcb->sector_shift;
ext2->csum = ExAllocatePoolWithTag(PagedPool, len, ALLOC_TAG); ext2->csum = ExAllocatePoolWithTag(PagedPool, len, ALLOC_TAG);
if (!ext2->csum) { if (!ext2->csum) {
@ -1719,7 +1719,7 @@ static NTSTATUS rename_stream_to_file(device_extension* Vcb, file_ref* fileref,
} }
ExFreePool(ed); ExFreePool(ed);
} else if (adsdata.Length % Vcb->superblock.sector_size) { } else if (adsdata.Length & (Vcb->superblock.sector_size - 1)) {
char* newbuf = ExAllocatePoolWithTag(PagedPool, (uint16_t)sector_align(adsdata.Length, Vcb->superblock.sector_size), ALLOC_TAG); char* newbuf = ExAllocatePoolWithTag(PagedPool, (uint16_t)sector_align(adsdata.Length, Vcb->superblock.sector_size), ALLOC_TAG);
if (!newbuf) { if (!newbuf) {
ERR("out of memory\n"); ERR("out of memory\n");

View file

@ -164,33 +164,33 @@ static void add_trim_entry(device* dev, uint64_t address, uint64_t size) {
} }
static void clean_space_cache_chunk(device_extension* Vcb, chunk* c) { static void clean_space_cache_chunk(device_extension* Vcb, chunk* c) {
LIST_ENTRY* le;
ULONG type; ULONG type;
if (Vcb->trim && !Vcb->options.no_trim) { if (c->chunk_item->type & BLOCK_FLAG_DUPLICATE)
if (c->chunk_item->type & BLOCK_FLAG_DUPLICATE) type = BLOCK_FLAG_DUPLICATE;
type = BLOCK_FLAG_DUPLICATE; else if (c->chunk_item->type & BLOCK_FLAG_RAID0)
else if (c->chunk_item->type & BLOCK_FLAG_RAID0) type = BLOCK_FLAG_RAID0;
type = BLOCK_FLAG_RAID0; else if (c->chunk_item->type & BLOCK_FLAG_RAID1)
else if (c->chunk_item->type & BLOCK_FLAG_RAID1) type = BLOCK_FLAG_DUPLICATE;
type = BLOCK_FLAG_DUPLICATE; else if (c->chunk_item->type & BLOCK_FLAG_RAID10)
else if (c->chunk_item->type & BLOCK_FLAG_RAID10) type = BLOCK_FLAG_RAID10;
type = BLOCK_FLAG_RAID10; else if (c->chunk_item->type & BLOCK_FLAG_RAID5)
else if (c->chunk_item->type & BLOCK_FLAG_RAID5) type = BLOCK_FLAG_RAID5;
type = BLOCK_FLAG_RAID5; else if (c->chunk_item->type & BLOCK_FLAG_RAID6)
else if (c->chunk_item->type & BLOCK_FLAG_RAID6) type = BLOCK_FLAG_RAID6;
type = BLOCK_FLAG_RAID6; else if (c->chunk_item->type & BLOCK_FLAG_RAID1C3)
else if (c->chunk_item->type & BLOCK_FLAG_RAID1C3) type = BLOCK_FLAG_DUPLICATE;
type = BLOCK_FLAG_DUPLICATE; else if (c->chunk_item->type & BLOCK_FLAG_RAID1C4)
else if (c->chunk_item->type & BLOCK_FLAG_RAID1C4) type = BLOCK_FLAG_DUPLICATE;
type = BLOCK_FLAG_DUPLICATE; else // SINGLE
else // SINGLE type = BLOCK_FLAG_DUPLICATE;
type = BLOCK_FLAG_DUPLICATE;
}
while (!IsListEmpty(&c->deleting)) { le = c->deleting.Flink;
space* s = CONTAINING_RECORD(c->deleting.Flink, space, list_entry); while (le != &c->deleting) {
space* s = CONTAINING_RECORD(le, space, list_entry);
if (Vcb->trim && !Vcb->options.no_trim && (!Vcb->options.no_barrier || !(c->chunk_item->type & BLOCK_FLAG_METADATA))) { if (!Vcb->options.no_barrier || !(c->chunk_item->type & BLOCK_FLAG_METADATA)) {
CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1]; CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
if (type == BLOCK_FLAG_DUPLICATE) { if (type == BLOCK_FLAG_DUPLICATE) {
@ -270,8 +270,7 @@ static void clean_space_cache_chunk(device_extension* Vcb, chunk* c) {
// FIXME - RAID5(?), RAID6(?) // FIXME - RAID5(?), RAID6(?)
} }
RemoveEntryList(&s->list_entry); le = le->Flink;
ExFreePool(s);
} }
} }
@ -414,8 +413,18 @@ static void clean_space_cache(device_extension* Vcb) {
if (c->space_changed) { if (c->space_changed) {
acquire_chunk_lock(c, Vcb); acquire_chunk_lock(c, Vcb);
if (c->space_changed) if (c->space_changed) {
clean_space_cache_chunk(Vcb, c); if (Vcb->trim && !Vcb->options.no_trim)
clean_space_cache_chunk(Vcb, c);
space_list_merge(&c->space, &c->space_size, &c->deleting);
while (!IsListEmpty(&c->deleting)) {
space* s = CONTAINING_RECORD(RemoveHeadList(&c->deleting), space, list_entry);
ExFreePool(s);
}
}
c->space_changed = false; c->space_changed = false;
@ -725,7 +734,7 @@ static bool insert_tree_extent_skinny(device_extension* Vcb, uint8_t level, uint
acquire_chunk_lock(c, Vcb); acquire_chunk_lock(c, Vcb);
space_list_subtract(c, false, address, Vcb->superblock.node_size, rollback); space_list_subtract(c, address, Vcb->superblock.node_size, rollback);
release_chunk_lock(c, Vcb); release_chunk_lock(c, Vcb);
@ -857,7 +866,7 @@ static bool insert_tree_extent(device_extension* Vcb, uint8_t level, uint64_t ro
acquire_chunk_lock(c, Vcb); acquire_chunk_lock(c, Vcb);
space_list_subtract(c, false, address, Vcb->superblock.node_size, rollback); space_list_subtract(c, address, Vcb->superblock.node_size, rollback);
release_chunk_lock(c, Vcb); release_chunk_lock(c, Vcb);
@ -2639,7 +2648,7 @@ void add_checksum_entry(device_extension* Vcb, uint64_t address, ULONG length, v
length2 -= il; length2 -= il;
if (length2 > 0) { if (length2 > 0) {
off += il * Vcb->superblock.sector_size; off += (uint64_t)il << Vcb->sector_shift;
data = (uint8_t*)data + (il * Vcb->csum_size); data = (uint8_t*)data + (il * Vcb->csum_size);
} }
} while (length2 > 0); } while (length2 > 0);
@ -2653,14 +2662,14 @@ void add_checksum_entry(device_extension* Vcb, uint64_t address, ULONG length, v
// FIXME - check entry is TYPE_EXTENT_CSUM? // FIXME - check entry is TYPE_EXTENT_CSUM?
if (tp.item->key.offset < address && tp.item->key.offset + (tp.item->size * Vcb->superblock.sector_size / Vcb->csum_size) >= address) if (tp.item->key.offset < address && tp.item->key.offset + (((uint64_t)tp.item->size << Vcb->sector_shift) / Vcb->csum_size) >= address)
startaddr = tp.item->key.offset; startaddr = tp.item->key.offset;
else else
startaddr = address; startaddr = address;
searchkey.obj_id = EXTENT_CSUM_ID; searchkey.obj_id = EXTENT_CSUM_ID;
searchkey.obj_type = TYPE_EXTENT_CSUM; searchkey.obj_type = TYPE_EXTENT_CSUM;
searchkey.offset = address + (length * Vcb->superblock.sector_size); searchkey.offset = address + (length << Vcb->sector_shift);
Status = find_item(Vcb, Vcb->checksum_root, &tp, &searchkey, false, Irp); Status = find_item(Vcb, Vcb->checksum_root, &tp, &searchkey, false, Irp);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
@ -2670,16 +2679,16 @@ void add_checksum_entry(device_extension* Vcb, uint64_t address, ULONG length, v
tplen = tp.item->size / Vcb->csum_size; tplen = tp.item->size / Vcb->csum_size;
if (tp.item->key.offset + (tplen * Vcb->superblock.sector_size) >= address + (length * Vcb->superblock.sector_size)) if (tp.item->key.offset + (tplen << Vcb->sector_shift) >= address + (length << Vcb->sector_shift))
endaddr = tp.item->key.offset + (tplen * Vcb->superblock.sector_size); endaddr = tp.item->key.offset + (tplen << Vcb->sector_shift);
else else
endaddr = address + (length * Vcb->superblock.sector_size); endaddr = address + (length << Vcb->sector_shift);
TRACE("cs starts at %I64x (%lx sectors)\n", address, length); TRACE("cs starts at %I64x (%lx sectors)\n", address, length);
TRACE("startaddr = %I64x\n", startaddr); TRACE("startaddr = %I64x\n", startaddr);
TRACE("endaddr = %I64x\n", endaddr); TRACE("endaddr = %I64x\n", endaddr);
len = (ULONG)((endaddr - startaddr) / Vcb->superblock.sector_size); len = (ULONG)((endaddr - startaddr) >> Vcb->sector_shift);
checksums = ExAllocatePoolWithTag(PagedPool, Vcb->csum_size * len, ALLOC_TAG); checksums = ExAllocatePoolWithTag(PagedPool, Vcb->csum_size * len, ALLOC_TAG);
if (!checksums) { if (!checksums) {
@ -2714,11 +2723,11 @@ void add_checksum_entry(device_extension* Vcb, uint64_t address, ULONG length, v
while (tp.item->key.offset < endaddr) { while (tp.item->key.offset < endaddr) {
if (tp.item->key.offset >= startaddr) { if (tp.item->key.offset >= startaddr) {
if (tp.item->size > 0) { if (tp.item->size > 0) {
ULONG itemlen = (ULONG)min((len - (tp.item->key.offset - startaddr) / Vcb->superblock.sector_size) * Vcb->csum_size, tp.item->size); ULONG itemlen = (ULONG)min((len - ((tp.item->key.offset - startaddr) >> Vcb->sector_shift)) * Vcb->csum_size, tp.item->size);
RtlCopyMemory((uint8_t*)checksums + ((tp.item->key.offset - startaddr) * Vcb->csum_size / Vcb->superblock.sector_size), RtlCopyMemory((uint8_t*)checksums + (((tp.item->key.offset - startaddr) * Vcb->csum_size) >> Vcb->sector_shift),
tp.item->data, itemlen); tp.item->data, itemlen);
RtlClearBits(&bmp, (ULONG)((tp.item->key.offset - startaddr) / Vcb->superblock.sector_size), itemlen / Vcb->csum_size); RtlClearBits(&bmp, (ULONG)((tp.item->key.offset - startaddr) >> Vcb->sector_shift), itemlen / Vcb->csum_size);
} }
Status = delete_tree_item(Vcb, &tp); Status = delete_tree_item(Vcb, &tp);
@ -2737,11 +2746,11 @@ void add_checksum_entry(device_extension* Vcb, uint64_t address, ULONG length, v
} }
if (!csum) { // deleted if (!csum) { // deleted
RtlSetBits(&bmp, (ULONG)((address - startaddr) / Vcb->superblock.sector_size), length); RtlSetBits(&bmp, (ULONG)((address - startaddr) >> Vcb->sector_shift), length);
} else { } else {
RtlCopyMemory((uint8_t*)checksums + ((address - startaddr) * Vcb->csum_size / Vcb->superblock.sector_size), RtlCopyMemory((uint8_t*)checksums + (((address - startaddr) * Vcb->csum_size) >> Vcb->sector_shift),
csum, length * Vcb->csum_size); csum, length * Vcb->csum_size);
RtlClearBits(&bmp, (ULONG)((address - startaddr) / Vcb->superblock.sector_size), length); RtlClearBits(&bmp, (ULONG)((address - startaddr) >> Vcb->sector_shift), length);
} }
runlength = RtlFindFirstRunClear(&bmp, &index); runlength = RtlFindFirstRunClear(&bmp, &index);
@ -2777,7 +2786,7 @@ void add_checksum_entry(device_extension* Vcb, uint64_t address, ULONG length, v
RtlCopyMemory(data, (uint8_t*)checksums + (Vcb->csum_size * index), Vcb->csum_size * rl); RtlCopyMemory(data, (uint8_t*)checksums + (Vcb->csum_size * index), Vcb->csum_size * rl);
off = startaddr + UInt32x32To64(index, Vcb->superblock.sector_size); off = startaddr + ((uint64_t)index << Vcb->sector_shift);
Status = insert_tree_item(Vcb, Vcb->checksum_root, EXTENT_CSUM_ID, TYPE_EXTENT_CSUM, off, data, Vcb->csum_size * rl, NULL, Irp); Status = insert_tree_item(Vcb, Vcb->checksum_root, EXTENT_CSUM_ID, TYPE_EXTENT_CSUM, off, data, Vcb->csum_size * rl, NULL, Irp);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
@ -3661,7 +3670,7 @@ static NTSTATUS update_tree_extents_recursive(device_extension* Vcb, tree* t, PI
static NTSTATUS do_splits(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback) { static NTSTATUS do_splits(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback) {
ULONG level, max_level; ULONG level, max_level;
uint32_t min_size; uint32_t min_size, min_size_fst;
bool empty, done_deletions = false; bool empty, done_deletions = false;
NTSTATUS Status; NTSTATUS Status;
tree* t; tree* t;
@ -3770,6 +3779,7 @@ static NTSTATUS do_splits(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback)
} }
min_size = (Vcb->superblock.node_size - sizeof(tree_header)) / 2; min_size = (Vcb->superblock.node_size - sizeof(tree_header)) / 2;
min_size_fst = (Vcb->superblock.node_size - sizeof(tree_header)) / 4;
for (level = 0; level <= max_level; level++) { for (level = 0; level <= max_level; level++) {
LIST_ENTRY* le; LIST_ENTRY* le;
@ -3779,8 +3789,9 @@ static NTSTATUS do_splits(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback)
while (le != &Vcb->trees) { while (le != &Vcb->trees) {
t = CONTAINING_RECORD(le, tree, list_entry); t = CONTAINING_RECORD(le, tree, list_entry);
if (t->write && t->header.level == level && t->header.num_items > 0 && t->parent && t->size < min_size && if (t->write && t->header.level == level && t->header.num_items > 0 && t->parent &&
t->root->id != BTRFS_ROOT_FREE_SPACE && is_tree_unique(Vcb, t, Irp)) { ((t->size < min_size && t->root->id != BTRFS_ROOT_FREE_SPACE) || (t->size < min_size_fst && t->root->id == BTRFS_ROOT_FREE_SPACE)) &&
is_tree_unique(Vcb, t, Irp)) {
bool done; bool done;
do { do {
@ -4649,7 +4660,7 @@ cont:
} }
if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) 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); add_checksum_entry(fcb->Vcb, er->address, (ULONG)(er->skip_start >> fcb->Vcb->sector_shift), NULL, NULL);
acquire_chunk_lock(er->chunk, fcb->Vcb); acquire_chunk_lock(er->chunk, fcb->Vcb);
@ -4703,7 +4714,7 @@ cont:
} }
if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) 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); add_checksum_entry(fcb->Vcb, er->address + er->length - er->skip_end, (ULONG)(er->skip_end >> fcb->Vcb->sector_shift), NULL, NULL);
acquire_chunk_lock(er->chunk, fcb->Vcb); acquire_chunk_lock(er->chunk, fcb->Vcb);
@ -4902,9 +4913,9 @@ NTSTATUS flush_fcb(fcb* fcb, bool cache, LIST_ENTRY* batchlist, PIRP Irp) {
if (ed2->size > 0) { // not sparse if (ed2->size > 0) { // not sparse
if (ext->extent_data.compression == BTRFS_COMPRESSION_NONE) if (ext->extent_data.compression == BTRFS_COMPRESSION_NONE)
add_checksum_entry(fcb->Vcb, ed2->address + ed2->offset, (ULONG)(ed2->num_bytes / fcb->Vcb->superblock.sector_size), ext->csum, Irp); add_checksum_entry(fcb->Vcb, ed2->address + ed2->offset, (ULONG)(ed2->num_bytes >> fcb->Vcb->sector_shift), ext->csum, Irp);
else else
add_checksum_entry(fcb->Vcb, ed2->address, (ULONG)(ed2->size / fcb->Vcb->superblock.sector_size), ext->csum, Irp); add_checksum_entry(fcb->Vcb, ed2->address, (ULONG)(ed2->size >> fcb->Vcb->sector_shift), ext->csum, Irp);
} }
} }
@ -4933,7 +4944,7 @@ NTSTATUS flush_fcb(fcb* fcb, bool cache, LIST_ENTRY* batchlist, PIRP Irp) {
chunk* c; chunk* c;
if (ext->extent_data.compression == BTRFS_COMPRESSION_NONE && ext->csum) { if (ext->extent_data.compression == BTRFS_COMPRESSION_NONE && ext->csum) {
ULONG len = (ULONG)((ed2->num_bytes + ned2->num_bytes) / fcb->Vcb->superblock.sector_size); ULONG len = (ULONG)((ed2->num_bytes + ned2->num_bytes) >> fcb->Vcb->sector_shift);
void* csum; void* csum;
csum = ExAllocatePoolWithTag(NonPagedPool, len * fcb->Vcb->csum_size, ALLOC_TAG); csum = ExAllocatePoolWithTag(NonPagedPool, len * fcb->Vcb->csum_size, ALLOC_TAG);
@ -4943,9 +4954,9 @@ NTSTATUS flush_fcb(fcb* fcb, bool cache, LIST_ENTRY* batchlist, PIRP Irp) {
goto end; goto end;
} }
RtlCopyMemory(csum, ext->csum, (ULONG)(ed2->num_bytes * fcb->Vcb->csum_size / fcb->Vcb->superblock.sector_size)); RtlCopyMemory(csum, ext->csum, (ULONG)((ed2->num_bytes * fcb->Vcb->csum_size) >> fcb->Vcb->sector_shift));
RtlCopyMemory((uint8_t*)csum + (ed2->num_bytes * fcb->Vcb->csum_size / fcb->Vcb->superblock.sector_size), nextext->csum, RtlCopyMemory((uint8_t*)csum + ((ed2->num_bytes * fcb->Vcb->csum_size) >> fcb->Vcb->sector_shift), nextext->csum,
(ULONG)(ned2->num_bytes * fcb->Vcb->csum_size / fcb->Vcb->superblock.sector_size)); (ULONG)((ned2->num_bytes * fcb->Vcb->csum_size) >> fcb->Vcb->sector_shift));
ExFreePool(ext->csum); ExFreePool(ext->csum);
ext->csum = csum; ext->csum = csum;
@ -5738,7 +5749,7 @@ static NTSTATUS drop_chunk(device_extension* Vcb, chunk* c, LIST_ENTRY* batchlis
static NTSTATUS partial_stripe_read(device_extension* Vcb, chunk* c, partial_stripe* ps, uint64_t startoff, uint16_t parity, ULONG offset, ULONG len) { static NTSTATUS partial_stripe_read(device_extension* Vcb, chunk* c, partial_stripe* ps, uint64_t startoff, uint16_t parity, ULONG offset, ULONG len) {
NTSTATUS Status; NTSTATUS Status;
ULONG sl = (ULONG)(c->chunk_item->stripe_length / Vcb->superblock.sector_size); ULONG sl = (ULONG)(c->chunk_item->stripe_length >> Vcb->sector_shift);
CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1]; CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
while (len > 0) { while (len > 0) {
@ -5748,8 +5759,8 @@ static NTSTATUS partial_stripe_read(device_extension* Vcb, chunk* c, partial_str
stripe = (parity + (offset / sl) + 1) % c->chunk_item->num_stripes; stripe = (parity + (offset / sl) + 1) % c->chunk_item->num_stripes;
if (c->devices[stripe]->devobj) { if (c->devices[stripe]->devobj) {
Status = sync_read_phys(c->devices[stripe]->devobj, c->devices[stripe]->fileobj, cis[stripe].offset + startoff + ((offset % sl) * Vcb->superblock.sector_size), Status = sync_read_phys(c->devices[stripe]->devobj, c->devices[stripe]->fileobj, cis[stripe].offset + startoff + ((offset % sl) << Vcb->sector_shift),
readlen * Vcb->superblock.sector_size, ps->data + (offset * Vcb->superblock.sector_size), false); readlen << Vcb->sector_shift, ps->data + (offset << Vcb->sector_shift), false);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("sync_read_phys returned %08lx\n", Status); ERR("sync_read_phys returned %08lx\n", Status);
return Status; return Status;
@ -5758,7 +5769,7 @@ static NTSTATUS partial_stripe_read(device_extension* Vcb, chunk* c, partial_str
uint16_t i; uint16_t i;
uint8_t* scratch; uint8_t* scratch;
scratch = ExAllocatePoolWithTag(NonPagedPool, readlen * Vcb->superblock.sector_size, ALLOC_TAG); scratch = ExAllocatePoolWithTag(NonPagedPool, readlen << Vcb->sector_shift, ALLOC_TAG);
if (!scratch) { if (!scratch) {
ERR("out of memory\n"); ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
@ -5772,23 +5783,23 @@ static NTSTATUS partial_stripe_read(device_extension* Vcb, chunk* c, partial_str
} }
if (i == 0 || (stripe == 0 && i == 1)) { if (i == 0 || (stripe == 0 && i == 1)) {
Status = sync_read_phys(c->devices[i]->devobj, c->devices[i]->fileobj, cis[i].offset + startoff + ((offset % sl) * Vcb->superblock.sector_size), Status = sync_read_phys(c->devices[i]->devobj, c->devices[i]->fileobj, cis[i].offset + startoff + ((offset % sl) << Vcb->sector_shift),
readlen * Vcb->superblock.sector_size, ps->data + (offset * Vcb->superblock.sector_size), false); readlen << Vcb->sector_shift, ps->data + (offset << Vcb->sector_shift), false);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("sync_read_phys returned %08lx\n", Status); ERR("sync_read_phys returned %08lx\n", Status);
ExFreePool(scratch); ExFreePool(scratch);
return Status; return Status;
} }
} else { } else {
Status = sync_read_phys(c->devices[i]->devobj, c->devices[i]->fileobj, cis[i].offset + startoff + ((offset % sl) * Vcb->superblock.sector_size), Status = sync_read_phys(c->devices[i]->devobj, c->devices[i]->fileobj, cis[i].offset + startoff + ((offset % sl) << Vcb->sector_shift),
readlen * Vcb->superblock.sector_size, scratch, false); readlen << Vcb->sector_shift, scratch, false);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("sync_read_phys returned %08lx\n", Status); ERR("sync_read_phys returned %08lx\n", Status);
ExFreePool(scratch); ExFreePool(scratch);
return Status; return Status;
} }
do_xor(ps->data + (offset * Vcb->superblock.sector_size), scratch, readlen * Vcb->superblock.sector_size); do_xor(ps->data + (offset << Vcb->sector_shift), scratch, readlen << Vcb->sector_shift);
} }
} }
} }
@ -5798,7 +5809,7 @@ static NTSTATUS partial_stripe_read(device_extension* Vcb, chunk* c, partial_str
uint8_t* scratch; uint8_t* scratch;
uint16_t k, i, logstripe, error_stripe, num_errors = 0; uint16_t k, i, logstripe, error_stripe, num_errors = 0;
scratch = ExAllocatePoolWithTag(NonPagedPool, (c->chunk_item->num_stripes + 2) * readlen * Vcb->superblock.sector_size, ALLOC_TAG); scratch = ExAllocatePoolWithTag(NonPagedPool, (c->chunk_item->num_stripes + 2) * readlen << Vcb->sector_shift, ALLOC_TAG);
if (!scratch) { if (!scratch) {
ERR("out of memory\n"); ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
@ -5808,8 +5819,8 @@ static NTSTATUS partial_stripe_read(device_extension* Vcb, chunk* c, partial_str
for (k = 0; k < c->chunk_item->num_stripes; k++) { for (k = 0; k < c->chunk_item->num_stripes; k++) {
if (i != stripe) { if (i != stripe) {
if (c->devices[i]->devobj) { if (c->devices[i]->devobj) {
Status = sync_read_phys(c->devices[i]->devobj, c->devices[i]->fileobj, cis[i].offset + startoff + ((offset % sl) * Vcb->superblock.sector_size), Status = sync_read_phys(c->devices[i]->devobj, c->devices[i]->fileobj, cis[i].offset + startoff + ((offset % sl) << Vcb->sector_shift),
readlen * Vcb->superblock.sector_size, scratch + (k * readlen * Vcb->superblock.sector_size), false); readlen << Vcb->sector_shift, scratch + (k * readlen << Vcb->sector_shift), false);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("sync_read_phys returned %08lx\n", Status); ERR("sync_read_phys returned %08lx\n", Status);
num_errors++; num_errors++;
@ -5834,20 +5845,20 @@ static NTSTATUS partial_stripe_read(device_extension* Vcb, chunk* c, partial_str
for (k = 0; k < c->chunk_item->num_stripes - 1; k++) { for (k = 0; k < c->chunk_item->num_stripes - 1; k++) {
if (k != logstripe) { if (k != logstripe) {
if (k == 0 || (k == 1 && logstripe == 0)) { if (k == 0 || (k == 1 && logstripe == 0)) {
RtlCopyMemory(ps->data + (offset * Vcb->superblock.sector_size), scratch + (k * readlen * Vcb->superblock.sector_size), RtlCopyMemory(ps->data + (offset << Vcb->sector_shift), scratch + (k * readlen << Vcb->sector_shift),
readlen * Vcb->superblock.sector_size); readlen << Vcb->sector_shift);
} else { } else {
do_xor(ps->data + (offset * Vcb->superblock.sector_size), scratch + (k * readlen * Vcb->superblock.sector_size), do_xor(ps->data + (offset << Vcb->sector_shift), scratch + (k * readlen << Vcb->sector_shift),
readlen * Vcb->superblock.sector_size); readlen << Vcb->sector_shift);
} }
} }
} }
} else { } else {
raid6_recover2(scratch, c->chunk_item->num_stripes, readlen * Vcb->superblock.sector_size, logstripe, raid6_recover2(scratch, c->chunk_item->num_stripes, readlen << Vcb->sector_shift, logstripe,
error_stripe, scratch + (c->chunk_item->num_stripes * readlen * Vcb->superblock.sector_size)); error_stripe, scratch + (c->chunk_item->num_stripes * readlen << Vcb->sector_shift));
RtlCopyMemory(ps->data + (offset * Vcb->superblock.sector_size), scratch + (c->chunk_item->num_stripes * readlen * Vcb->superblock.sector_size), RtlCopyMemory(ps->data + (offset << Vcb->sector_shift), scratch + (c->chunk_item->num_stripes * readlen << Vcb->sector_shift),
readlen * Vcb->superblock.sector_size); readlen << Vcb->sector_shift);
} }
ExFreePool(scratch); ExFreePool(scratch);
@ -5907,8 +5918,8 @@ NTSTATUS flush_partial_stripe(device_extension* Vcb, chunk* c, partial_stripe* p
runlength = RtlFindNextForwardRunClear(&ps->bmp, index + runlength, &index); runlength = RtlFindNextForwardRunClear(&ps->bmp, index + runlength, &index);
} }
if (last1 < ps_length / Vcb->superblock.sector_size) { if (last1 < ps_length >> Vcb->sector_shift) {
Status = partial_stripe_read(Vcb, c, ps, startoff, parity2, last1, (ULONG)((ps_length / Vcb->superblock.sector_size) - last1)); Status = partial_stripe_read(Vcb, c, ps, startoff, parity2, last1, (ULONG)((ps_length >> Vcb->sector_shift) - last1));
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("partial_stripe_read returned %08lx\n", Status); ERR("partial_stripe_read returned %08lx\n", Status);
return Status; return Status;

View file

@ -285,8 +285,8 @@ static void load_free_space_bitmap(device_extension* Vcb, chunk* c, uint64_t off
break; break;
} }
addr = offset + (index * Vcb->superblock.sector_size); addr = offset + (index << Vcb->sector_shift);
length = Vcb->superblock.sector_size * runlength; length = runlength << Vcb->sector_shift;
add_space_entry(&c->space, &c->space_size, addr, length); add_space_entry(&c->space, &c->space_size, addr, length);
index += runlength; index += runlength;
@ -470,7 +470,7 @@ NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, bool load
uint64_t inode, *generation; uint64_t inode, *generation;
uint8_t* data; uint8_t* data;
NTSTATUS Status; NTSTATUS Status;
uint32_t *checksums, crc32, i, num_sectors, num_valid_sectors, size; uint32_t *checksums, crc32, num_sectors, num_valid_sectors, size;
FREE_SPACE_ENTRY* fse; FREE_SPACE_ENTRY* fse;
uint64_t num_entries, num_bitmaps, extent_length, bmpnum, off, total_space = 0, superblock_size; uint64_t num_entries, num_bitmaps, extent_length, bmpnum, off, total_space = 0, superblock_size;
LIST_ENTRY *le, rollback; LIST_ENTRY *le, rollback;
@ -563,7 +563,7 @@ NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, bool load
if (size > c->cache->inode_item.st_size) if (size > c->cache->inode_item.st_size)
RtlZeroMemory(&data[c->cache->inode_item.st_size], (ULONG)(size - c->cache->inode_item.st_size)); RtlZeroMemory(&data[c->cache->inode_item.st_size], (ULONG)(size - c->cache->inode_item.st_size));
num_sectors = size / Vcb->superblock.sector_size; num_sectors = size >> Vcb->sector_shift;
generation = (uint64_t*)(data + (num_sectors * sizeof(uint32_t))); generation = (uint64_t*)(data + (num_sectors * sizeof(uint32_t)));
@ -574,7 +574,7 @@ NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, bool load
extent_length = (num_sectors * sizeof(uint32_t)) + sizeof(uint64_t) + (num_entries * sizeof(FREE_SPACE_ENTRY)); extent_length = (num_sectors * sizeof(uint32_t)) + sizeof(uint64_t) + (num_entries * sizeof(FREE_SPACE_ENTRY));
num_valid_sectors = (ULONG)((sector_align(extent_length, Vcb->superblock.sector_size) / Vcb->superblock.sector_size) + num_bitmaps); num_valid_sectors = (ULONG)((sector_align(extent_length, Vcb->superblock.sector_size) >> Vcb->sector_shift) + num_bitmaps);
if (num_valid_sectors > num_sectors) { if (num_valid_sectors > num_sectors) {
ERR("free space cache for %I64x was %u sectors, expected at least %u\n", c->offset, num_sectors, num_valid_sectors); ERR("free space cache for %I64x was %u sectors, expected at least %u\n", c->offset, num_sectors, num_valid_sectors);
@ -583,13 +583,13 @@ NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, bool load
checksums = (uint32_t*)data; checksums = (uint32_t*)data;
for (i = 0; i < num_valid_sectors; i++) { for (uint32_t i = 0; i < num_valid_sectors; i++) {
if (i * Vcb->superblock.sector_size > sizeof(uint32_t) * num_sectors) if (i << Vcb->sector_shift > sizeof(uint32_t) * num_sectors)
crc32 = ~calc_crc32c(0xffffffff, &data[i * Vcb->superblock.sector_size], Vcb->superblock.sector_size); crc32 = ~calc_crc32c(0xffffffff, &data[i << Vcb->sector_shift], Vcb->superblock.sector_size);
else if ((i + 1) * Vcb->superblock.sector_size < sizeof(uint32_t) * num_sectors) else if ((i + 1) << Vcb->sector_shift < sizeof(uint32_t) * num_sectors)
crc32 = 0; // FIXME - test this crc32 = 0; // FIXME - test this
else else
crc32 = ~calc_crc32c(0xffffffff, &data[sizeof(uint32_t) * num_sectors], ((i + 1) * Vcb->superblock.sector_size) - (sizeof(uint32_t) * num_sectors)); crc32 = ~calc_crc32c(0xffffffff, &data[sizeof(uint32_t) * num_sectors], ((i + 1) << Vcb->sector_shift) - (sizeof(uint32_t) * num_sectors));
if (crc32 != checksums[i]) { if (crc32 != checksums[i]) {
WARN("checksum %u was %08x, expected %08x\n", i, crc32, checksums[i]); WARN("checksum %u was %08x, expected %08x\n", i, crc32, checksums[i]);
@ -600,8 +600,8 @@ NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, bool load
off = (sizeof(uint32_t) * num_sectors) + sizeof(uint64_t); off = (sizeof(uint32_t) * num_sectors) + sizeof(uint64_t);
bmpnum = 0; bmpnum = 0;
for (i = 0; i < num_entries; i++) { for (uint32_t i = 0; i < num_entries; i++) {
if ((off + sizeof(FREE_SPACE_ENTRY)) / Vcb->superblock.sector_size != off / Vcb->superblock.sector_size) if ((off + sizeof(FREE_SPACE_ENTRY)) >> Vcb->sector_shift != off >> Vcb->sector_shift)
off = sector_align(off, Vcb->superblock.sector_size); off = sector_align(off, Vcb->superblock.sector_size);
fse = (FREE_SPACE_ENTRY*)&data[off]; fse = (FREE_SPACE_ENTRY*)&data[off];
@ -623,18 +623,18 @@ NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, bool load
} }
if (num_bitmaps > 0) { if (num_bitmaps > 0) {
bmpnum = sector_align(off, Vcb->superblock.sector_size) / Vcb->superblock.sector_size; bmpnum = sector_align(off, Vcb->superblock.sector_size) >> Vcb->sector_shift;
off = (sizeof(uint32_t) * num_sectors) + sizeof(uint64_t); off = (sizeof(uint32_t) * num_sectors) + sizeof(uint64_t);
for (i = 0; i < num_entries; i++) { for (uint32_t i = 0; i < num_entries; i++) {
if ((off + sizeof(FREE_SPACE_ENTRY)) / Vcb->superblock.sector_size != off / Vcb->superblock.sector_size) if ((off + sizeof(FREE_SPACE_ENTRY)) >> Vcb->sector_shift != off >> Vcb->sector_shift)
off = sector_align(off, Vcb->superblock.sector_size); off = sector_align(off, Vcb->superblock.sector_size);
fse = (FREE_SPACE_ENTRY*)&data[off]; fse = (FREE_SPACE_ENTRY*)&data[off];
if (fse->type == FREE_SPACE_BITMAP) { if (fse->type == FREE_SPACE_BITMAP) {
// FIXME - make sure we don't overflow the buffer here // FIXME - make sure we don't overflow the buffer here
load_free_space_bitmap(Vcb, c, fse->offset, &data[bmpnum * Vcb->superblock.sector_size], &total_space); load_free_space_bitmap(Vcb, c, fse->offset, &data[bmpnum << Vcb->sector_shift], &total_space);
bmpnum++; bmpnum++;
} }
@ -778,7 +778,7 @@ static NTSTATUS load_stored_free_space_tree(device_extension* Vcb, chunk* c, PIR
uint64_t lastoff; uint64_t lastoff;
ULONG bmpl; ULONG bmpl;
explen = (ULONG)(tp.item->key.offset / (Vcb->superblock.sector_size * 8)); explen = (ULONG)(tp.item->key.offset >> Vcb->sector_shift) / 8;
if (tp.item->size < explen) { if (tp.item->size < explen) {
WARN("(%I64x,%x,%I64x) was %u bytes, expected %lu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, explen); WARN("(%I64x,%x,%I64x) was %u bytes, expected %lu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, explen);
@ -803,7 +803,7 @@ static NTSTATUS load_stored_free_space_tree(device_extension* Vcb, chunk* c, PIR
// We copy the bitmap because it supposedly has to be ULONG-aligned // We copy the bitmap because it supposedly has to be ULONG-aligned
RtlCopyMemory(bmparr, tp.item->data, tp.item->size); RtlCopyMemory(bmparr, tp.item->data, tp.item->size);
bmpl = (ULONG)tp.item->key.offset / Vcb->superblock.sector_size; bmpl = (ULONG)tp.item->key.offset >> Vcb->sector_shift;
RtlInitializeBitMap(&bmp, bmparr, bmpl); RtlInitializeBitMap(&bmp, bmparr, bmpl);
@ -824,8 +824,8 @@ static NTSTATUS load_stored_free_space_tree(device_extension* Vcb, chunk* c, PIR
break; break;
} }
runstart = tp.item->key.obj_id + (index * Vcb->superblock.sector_size); runstart = tp.item->key.obj_id + (index << Vcb->sector_shift);
runend = runstart + (runlength * Vcb->superblock.sector_size); runend = runstart + (runlength << Vcb->sector_shift);
if (runstart > lastoff) { if (runstart > lastoff) {
Status = add_space_entry(&c->space, &c->space_size, lastoff, runstart - lastoff); Status = add_space_entry(&c->space, &c->space_size, lastoff, runstart - lastoff);
@ -1077,20 +1077,20 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, bool* chan
new_cache_size = sizeof(uint64_t) + (num_entries * sizeof(FREE_SPACE_ENTRY)); new_cache_size = sizeof(uint64_t) + (num_entries * sizeof(FREE_SPACE_ENTRY));
num_sectors = (uint32_t)sector_align(new_cache_size, Vcb->superblock.sector_size) / Vcb->superblock.sector_size; num_sectors = (uint32_t)sector_align(new_cache_size, Vcb->superblock.sector_size) >> Vcb->sector_shift;
num_sectors = (uint32_t)sector_align(num_sectors, CACHE_INCREMENTS); num_sectors = (uint32_t)sector_align(num_sectors, CACHE_INCREMENTS);
// adjust for padding // adjust for padding
// FIXME - there must be a more efficient way of doing this // FIXME - there must be a more efficient way of doing this
new_cache_size = sizeof(uint64_t) + (sizeof(uint32_t) * num_sectors); new_cache_size = sizeof(uint64_t) + (sizeof(uint32_t) * num_sectors);
for (i = 0; i < num_entries; i++) { for (i = 0; i < num_entries; i++) {
if ((new_cache_size / Vcb->superblock.sector_size) != ((new_cache_size + sizeof(FREE_SPACE_ENTRY)) / Vcb->superblock.sector_size)) if ((new_cache_size >> Vcb->sector_shift) != ((new_cache_size + sizeof(FREE_SPACE_ENTRY)) >> Vcb->sector_shift))
new_cache_size = sector_align(new_cache_size, Vcb->superblock.sector_size); new_cache_size = sector_align(new_cache_size, Vcb->superblock.sector_size);
new_cache_size += sizeof(FREE_SPACE_ENTRY); new_cache_size += sizeof(FREE_SPACE_ENTRY);
} }
new_cache_size = sector_align(new_cache_size, CACHE_INCREMENTS * Vcb->superblock.sector_size); new_cache_size = sector_align(new_cache_size, CACHE_INCREMENTS << Vcb->sector_shift);
TRACE("chunk %I64x: cache_size = %I64x, new_cache_size = %I64x\n", c->offset, c->cache ? c->cache->inode_item.st_size : 0, new_cache_size); TRACE("chunk %I64x: cache_size = %I64x, new_cache_size = %I64x\n", c->offset, c->cache ? c->cache->inode_item.st_size : 0, new_cache_size);
@ -1651,19 +1651,41 @@ void space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, uint64_t address,
add_rollback_space(rollback, true, list, list_size, address, length, c); add_rollback_space(rollback, true, list, list_size, address, length, c);
} }
static void space_list_merge(LIST_ENTRY* spacelist, LIST_ENTRY* spacelist_size, LIST_ENTRY* deleting) { void space_list_merge(LIST_ENTRY* spacelist, LIST_ENTRY* spacelist_size, LIST_ENTRY* deleting) {
LIST_ENTRY* le = deleting->Flink;
while (le != deleting) {
space* s = CONTAINING_RECORD(le, space, list_entry);
space_list_add2(spacelist, spacelist_size, s->address, s->size, NULL, NULL);
le = le->Flink;
}
}
static NTSTATUS copy_space_list(LIST_ENTRY* old_list, LIST_ENTRY* new_list) {
LIST_ENTRY* le; LIST_ENTRY* le;
if (!IsListEmpty(deleting)) { le = old_list->Flink;
le = deleting->Flink; while (le != old_list) {
while (le != deleting) { space* s = CONTAINING_RECORD(le, space, list_entry);
space* s = CONTAINING_RECORD(le, space, list_entry); space* s2;
space_list_add2(spacelist, spacelist_size, s->address, s->size, NULL, NULL); s2 = ExAllocatePoolWithTag(PagedPool, sizeof(space), ALLOC_TAG);
if (!s2) {
le = le->Flink; ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
} }
s2->address = s->address;
s2->size = s->size;
InsertTailList(new_list, &s2->list_entry);
le = le->Flink;
} }
return STATUS_SUCCESS;
} }
static NTSTATUS update_chunk_cache(device_extension* Vcb, chunk* c, BTRFS_TIME* now, LIST_ENTRY* batchlist, PIRP Irp, LIST_ENTRY* rollback) { static NTSTATUS update_chunk_cache(device_extension* Vcb, chunk* c, BTRFS_TIME* now, LIST_ENTRY* batchlist, PIRP Irp, LIST_ENTRY* rollback) {
@ -1673,10 +1695,8 @@ static NTSTATUS update_chunk_cache(device_extension* Vcb, chunk* c, BTRFS_TIME*
FREE_SPACE_ITEM* fsi; FREE_SPACE_ITEM* fsi;
void* data; void* data;
uint64_t num_entries, *cachegen, off; uint64_t num_entries, *cachegen, off;
uint32_t *checksums, num_sectors, i; uint32_t *checksums, num_sectors;
LIST_ENTRY* le; LIST_ENTRY space_list, deleting;
space_list_merge(&c->space, &c->space_size, &c->deleting);
data = ExAllocatePoolWithTag(NonPagedPool, (ULONG)c->cache->inode_item.st_size, ALLOC_TAG); data = ExAllocatePoolWithTag(NonPagedPool, (ULONG)c->cache->inode_item.st_size, ALLOC_TAG);
if (!data) { if (!data) {
@ -1686,17 +1706,38 @@ static NTSTATUS update_chunk_cache(device_extension* Vcb, chunk* c, BTRFS_TIME*
RtlZeroMemory(data, (ULONG)c->cache->inode_item.st_size); RtlZeroMemory(data, (ULONG)c->cache->inode_item.st_size);
InitializeListHead(&space_list);
InitializeListHead(&deleting);
Status = copy_space_list(&c->space, &space_list);
if (!NT_SUCCESS(Status)) {
ERR("copy_space_list returned %08lx\n", Status);
goto end;
}
Status = copy_space_list(&c->deleting, &deleting);
if (!NT_SUCCESS(Status)) {
ERR("copy_space_list returned %08lx\n", Status);
while (!IsListEmpty(&space_list)) {
ExFreePool(CONTAINING_RECORD(RemoveHeadList(&space_list), space, list_entry));
}
goto end;
}
space_list_merge(&space_list, NULL, &deleting);
num_entries = 0; num_entries = 0;
num_sectors = (uint32_t)(c->cache->inode_item.st_size / Vcb->superblock.sector_size); num_sectors = (uint32_t)(c->cache->inode_item.st_size >> Vcb->sector_shift);
off = (sizeof(uint32_t) * num_sectors) + sizeof(uint64_t); off = (sizeof(uint32_t) * num_sectors) + sizeof(uint64_t);
le = c->space.Flink; while (!IsListEmpty(&space_list)) {
while (le != &c->space) {
FREE_SPACE_ENTRY* fse; FREE_SPACE_ENTRY* fse;
space* s = CONTAINING_RECORD(le, space, list_entry); space* s = CONTAINING_RECORD(RemoveHeadList(&space_list), space, list_entry);
if ((off + sizeof(FREE_SPACE_ENTRY)) / Vcb->superblock.sector_size != off / Vcb->superblock.sector_size) if ((off + sizeof(FREE_SPACE_ENTRY)) >> Vcb->sector_shift != off >> Vcb->sector_shift)
off = sector_align(off, Vcb->superblock.sector_size); off = sector_align(off, Vcb->superblock.sector_size);
fse = (FREE_SPACE_ENTRY*)((uint8_t*)data + off); fse = (FREE_SPACE_ENTRY*)((uint8_t*)data + off);
@ -1707,8 +1748,6 @@ static NTSTATUS update_chunk_cache(device_extension* Vcb, chunk* c, BTRFS_TIME*
num_entries++; num_entries++;
off += sizeof(FREE_SPACE_ENTRY); off += sizeof(FREE_SPACE_ENTRY);
le = le->Flink;
} }
// update INODE_ITEM // update INODE_ITEM
@ -1765,13 +1804,13 @@ static NTSTATUS update_chunk_cache(device_extension* Vcb, chunk* c, BTRFS_TIME*
// FIXME - if we know sector is fully zeroed, use cached checksum // FIXME - if we know sector is fully zeroed, use cached checksum
for (i = 0; i < num_sectors; i++) { for (uint32_t i = 0; i < num_sectors; i++) {
if (i * Vcb->superblock.sector_size > sizeof(uint32_t) * num_sectors) if (i << Vcb->sector_shift > sizeof(uint32_t) * num_sectors)
checksums[i] = ~calc_crc32c(0xffffffff, (uint8_t*)data + (i * Vcb->superblock.sector_size), Vcb->superblock.sector_size); checksums[i] = ~calc_crc32c(0xffffffff, (uint8_t*)data + (i << Vcb->sector_shift), Vcb->superblock.sector_size);
else if ((i + 1) * Vcb->superblock.sector_size < sizeof(uint32_t) * num_sectors) else if ((i + 1) << Vcb->sector_shift < sizeof(uint32_t) * num_sectors)
checksums[i] = 0; // FIXME - test this checksums[i] = 0; // FIXME - test this
else else
checksums[i] = ~calc_crc32c(0xffffffff, (uint8_t*)data + (sizeof(uint32_t) * num_sectors), ((i + 1) * Vcb->superblock.sector_size) - (sizeof(uint32_t) * num_sectors)); checksums[i] = ~calc_crc32c(0xffffffff, (uint8_t*)data + (sizeof(uint32_t) * num_sectors), ((i + 1) << Vcb->sector_shift) - (sizeof(uint32_t) * num_sectors));
} }
// write cache // write cache
@ -1792,10 +1831,192 @@ end:
return Status; return Status;
} }
static NTSTATUS update_chunk_cache_tree(device_extension* Vcb, chunk* c, LIST_ENTRY* batchlist) { static NTSTATUS update_chunk_cache_tree(device_extension* Vcb, chunk* c, PIRP Irp) {
NTSTATUS Status; NTSTATUS Status;
LIST_ENTRY* le; LIST_ENTRY space_list;
FREE_SPACE_INFO* fsi; FREE_SPACE_INFO* fsi;
KEY searchkey;
traverse_ptr tp;
uint32_t fsi_count = 0;
InitializeListHead(&space_list);
Status = copy_space_list(&c->space, &space_list);
if (!NT_SUCCESS(Status)) {
ERR("copy_space_list returned %08lx\n", Status);
return Status;
}
space_list_merge(&space_list, NULL, &c->deleting);
searchkey.obj_id = c->offset;
searchkey.obj_type = TYPE_FREE_SPACE_EXTENT;
searchkey.offset = 0xffffffffffffffff;
Status = find_item(Vcb, Vcb->space_root, &tp, &searchkey, false, Irp);
if (Status == STATUS_NOT_FOUND)
goto after_tree_walk;
else if (!NT_SUCCESS(Status)) {
ERR("find_item returned %08lx\n", Status);
while (!IsListEmpty(&space_list)) {
ExFreePool(CONTAINING_RECORD(RemoveHeadList(&space_list), space, list_entry));
}
return Status;
}
while (!IsListEmpty(&space_list) && tp.item->key.obj_id < c->offset + c->chunk_item->size) {
traverse_ptr next_tp;
if (tp.item->key.obj_type == TYPE_FREE_SPACE_EXTENT) {
space* s = CONTAINING_RECORD(space_list.Flink, space, list_entry);
if (s->address < tp.item->key.obj_id || (s->address == tp.item->key.obj_id && s->size < tp.item->key.offset)) {
// add entry
Status = insert_tree_item(Vcb, Vcb->space_root, s->address, TYPE_FREE_SPACE_EXTENT, s->size, NULL, 0,
NULL, Irp);
if (!NT_SUCCESS(Status)) {
ERR("insert_tree_item returned %08lx\n", Status);
while (!IsListEmpty(&space_list)) {
ExFreePool(CONTAINING_RECORD(RemoveHeadList(&space_list), space, list_entry));
}
return Status;
}
fsi_count++;
ExFreePool(s);
RemoveHeadList(&space_list);
continue;
} else if (s->address == tp.item->key.obj_id && s->size == tp.item->key.offset) {
// unchanged entry
fsi_count++;
ExFreePool(s);
RemoveHeadList(&space_list);
} else {
// remove entry
Status = delete_tree_item(Vcb, &tp);
if (!NT_SUCCESS(Status)) {
ERR("delete_tree_item returned %08lx\n", Status);
while (!IsListEmpty(&space_list)) {
ExFreePool(CONTAINING_RECORD(RemoveHeadList(&space_list), space, list_entry));
}
return Status;
}
}
} else if (tp.item->key.obj_type == TYPE_FREE_SPACE_BITMAP) {
Status = delete_tree_item(Vcb, &tp);
if (!NT_SUCCESS(Status)) {
ERR("delete_tree_item returned %08lx\n", Status);
while (!IsListEmpty(&space_list)) {
ExFreePool(CONTAINING_RECORD(RemoveHeadList(&space_list), space, list_entry));
}
return Status;
}
}
if (!find_next_item(Vcb, &tp, &next_tp, false, Irp))
goto after_tree_walk;
tp = next_tp;
}
// after loop, delete remaining tree items for this chunk
while (tp.item->key.obj_id < c->offset + c->chunk_item->size) {
traverse_ptr next_tp;
if (tp.item->key.obj_type == TYPE_FREE_SPACE_EXTENT || tp.item->key.obj_type == TYPE_FREE_SPACE_BITMAP) {
Status = delete_tree_item(Vcb, &tp);
if (!NT_SUCCESS(Status)) {
ERR("delete_tree_item returned %08lx\n", Status);
return Status;
}
}
if (!find_next_item(Vcb, &tp, &next_tp, false, NULL))
break;
tp = next_tp;
}
after_tree_walk:
// after loop, insert remaining space_list entries
while (!IsListEmpty(&space_list)) {
space* s = CONTAINING_RECORD(RemoveHeadList(&space_list), space, list_entry);
Status = insert_tree_item(Vcb, Vcb->space_root, s->address, TYPE_FREE_SPACE_EXTENT, s->size, NULL, 0,
NULL, Irp);
if (!NT_SUCCESS(Status)) {
ERR("insert_tree_item returned %08lx\n", Status);
while (!IsListEmpty(&space_list)) {
ExFreePool(CONTAINING_RECORD(RemoveHeadList(&space_list), space, list_entry));
}
return Status;
}
fsi_count++;
ExFreePool(s);
}
// change TYPE_FREE_SPACE_INFO in place if present, and insert otherwise
searchkey.obj_id = c->offset;
searchkey.obj_type = TYPE_FREE_SPACE_INFO;
searchkey.offset = c->chunk_item->size;
Status = find_item(Vcb, Vcb->space_root, &tp, &searchkey, false, Irp);
if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND) {
ERR("find_item returned %08lx\n", Status);
return Status;
}
if (NT_SUCCESS(Status) && !keycmp(tp.item->key, searchkey)) {
if (tp.item->size == sizeof(FREE_SPACE_INFO)) {
tree* t;
// change in place if possible
fsi = (FREE_SPACE_INFO*)tp.item->data;
fsi->count = fsi_count;
fsi->flags = 0;
tp.tree->write = true;
t = tp.tree;
while (t) {
if (t->paritem && t->paritem->ignore) {
t->paritem->ignore = false;
t->parent->header.num_items++;
t->parent->size += sizeof(internal_node);
}
t->header.generation = Vcb->superblock.generation;
t = t->parent;
}
return STATUS_SUCCESS;
} else
delete_tree_item(Vcb, &tp);
}
// insert FREE_SPACE_INFO
fsi = ExAllocatePoolWithTag(PagedPool, sizeof(FREE_SPACE_INFO), ALLOC_TAG); fsi = ExAllocatePoolWithTag(PagedPool, sizeof(FREE_SPACE_INFO), ALLOC_TAG);
if (!fsi) { if (!fsi) {
@ -1803,41 +2024,13 @@ static NTSTATUS update_chunk_cache_tree(device_extension* Vcb, chunk* c, LIST_EN
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
space_list_merge(&c->space, &c->space_size, &c->deleting); fsi->count = fsi_count;
fsi->count = 0;
fsi->flags = 0; fsi->flags = 0;
le = c->space.Flink; Status = insert_tree_item(Vcb, Vcb->space_root, c->offset, TYPE_FREE_SPACE_INFO, c->chunk_item->size, fsi, sizeof(fsi),
while (le != &c->space) { NULL, Irp);
space* s = CONTAINING_RECORD(le, space, list_entry);
fsi->count++;
Status = insert_tree_item_batch(batchlist, Vcb, Vcb->space_root, s->address, TYPE_FREE_SPACE_EXTENT, s->size,
NULL, 0, Batch_Insert);
if (!NT_SUCCESS(Status)) {
ERR("insert_tree_item_batch returned %08lx\n", Status);
ExFreePool(fsi);
return Status;
}
le = le->Flink;
}
Status = insert_tree_item_batch(batchlist, Vcb, Vcb->space_root, c->offset, TYPE_FREE_SPACE_INFO, c->chunk_item->size,
NULL, 0, Batch_DeleteFreeSpace);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("insert_tree_item_batch returned %08lx\n", Status); ERR("insert_tree_item returned %08lx\n", Status);
ExFreePool(fsi);
return Status;
}
Status = insert_tree_item_batch(batchlist, Vcb, Vcb->space_root, c->offset, TYPE_FREE_SPACE_INFO, c->chunk_item->size,
fsi, sizeof(FREE_SPACE_INFO), Batch_Insert);
if (!NT_SUCCESS(Status)) {
ERR("insert_tree_item_batch returned %08lx\n", Status);
ExFreePool(fsi);
return Status; return Status;
} }
@ -1915,14 +2108,12 @@ NTSTATUS update_chunk_caches(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollba
} }
NTSTATUS update_chunk_caches_tree(device_extension* Vcb, PIRP Irp) { NTSTATUS update_chunk_caches_tree(device_extension* Vcb, PIRP Irp) {
LIST_ENTRY *le, batchlist; LIST_ENTRY *le;
NTSTATUS Status; NTSTATUS Status;
chunk* c; chunk* c;
Vcb->superblock.compat_ro_flags |= BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID; Vcb->superblock.compat_ro_flags |= BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID;
InitializeListHead(&batchlist);
ExAcquireResourceSharedLite(&Vcb->chunk_lock, true); ExAcquireResourceSharedLite(&Vcb->chunk_lock, true);
le = Vcb->chunks.Flink; le = Vcb->chunks.Flink;
@ -1931,13 +2122,12 @@ NTSTATUS update_chunk_caches_tree(device_extension* Vcb, PIRP Irp) {
if (c->space_changed) { if (c->space_changed) {
acquire_chunk_lock(c, Vcb); acquire_chunk_lock(c, Vcb);
Status = update_chunk_cache_tree(Vcb, c, &batchlist); Status = update_chunk_cache_tree(Vcb, c, Irp);
release_chunk_lock(c, Vcb); release_chunk_lock(c, Vcb);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("update_chunk_cache_tree(%I64x) returned %08lx\n", c->offset, Status); ERR("update_chunk_cache_tree(%I64x) returned %08lx\n", c->offset, Status);
ExReleaseResourceLite(&Vcb->chunk_lock); ExReleaseResourceLite(&Vcb->chunk_lock);
clear_batch_list(Vcb, &batchlist);
return Status; return Status;
} }
} }
@ -1947,12 +2137,6 @@ NTSTATUS update_chunk_caches_tree(device_extension* Vcb, PIRP Irp) {
ExReleaseResourceLite(&Vcb->chunk_lock); ExReleaseResourceLite(&Vcb->chunk_lock);
Status = commit_batch_list(Vcb, &batchlist, Irp);
if (!NT_SUCCESS(Status)) {
ERR("commit_batch_list returned %08lx\n", Status);
return Status;
}
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -2044,13 +2228,11 @@ void space_list_subtract2(LIST_ENTRY* list, LIST_ENTRY* list_size, uint64_t addr
} }
} }
void space_list_subtract(chunk* c, bool deleting, uint64_t address, uint64_t length, LIST_ENTRY* rollback) { void space_list_subtract(chunk* c, uint64_t address, uint64_t length, LIST_ENTRY* rollback) {
LIST_ENTRY* list;
list = deleting ? &c->deleting : &c->space;
c->changed = true; c->changed = true;
c->space_changed = true; c->space_changed = true;
space_list_subtract2(list, deleting ? NULL : &c->space_size, address, length, c, rollback); space_list_subtract2(&c->space, &c->space_size, address, length, c, rollback);
space_list_subtract2(&c->deleting, NULL, address, length, c, rollback);
} }

View file

@ -2008,7 +2008,7 @@ static NTSTATUS set_zero_data(device_extension* Vcb, PFILE_OBJECT FileObject, vo
if ((uint64_t)fzdi->BeyondFinalZero.QuadPart > fcb->inode_item.st_size) if ((uint64_t)fzdi->BeyondFinalZero.QuadPart > fcb->inode_item.st_size)
end = sector_align(fcb->inode_item.st_size, Vcb->superblock.sector_size); end = sector_align(fcb->inode_item.st_size, Vcb->superblock.sector_size);
else else
end = (fzdi->BeyondFinalZero.QuadPart / Vcb->superblock.sector_size) * Vcb->superblock.sector_size; end = (fzdi->BeyondFinalZero.QuadPart >> Vcb->sector_shift) << Vcb->sector_shift;
if (end <= start) { if (end <= start) {
Status = zero_data(Vcb, fcb, fzdi->FileOffset.QuadPart, fzdi->BeyondFinalZero.QuadPart - fzdi->FileOffset.QuadPart, Irp, &rollback); Status = zero_data(Vcb, fcb, fzdi->FileOffset.QuadPart, fzdi->BeyondFinalZero.QuadPart - fzdi->FileOffset.QuadPart, Irp, &rollback);
@ -3385,7 +3385,7 @@ static NTSTATUS duplicate_extents(device_extension* Vcb, PFILE_OBJECT FileObject
dataoff = 0; dataoff = 0;
datalen2 = (ULONG)ded->ByteCount.QuadPart; datalen2 = (ULONG)ded->ByteCount.QuadPart;
} else { } else {
dataoff = ded->TargetFileOffset.QuadPart % Vcb->superblock.sector_size; dataoff = ded->TargetFileOffset.QuadPart & (Vcb->superblock.sector_size - 1);
datalen2 = (ULONG)sector_align(ded->ByteCount.QuadPart + dataoff, Vcb->superblock.sector_size); datalen2 = (ULONG)sector_align(ded->ByteCount.QuadPart + dataoff, Vcb->superblock.sector_size);
} }
@ -3469,7 +3469,7 @@ static NTSTATUS duplicate_extents(device_extension* Vcb, PFILE_OBJECT FileObject
fcb->inode_item.st_blocks += datalen2; fcb->inode_item.st_blocks += datalen2;
} else { } else {
uint64_t start = ded->TargetFileOffset.QuadPart - (ded->TargetFileOffset.QuadPart % Vcb->superblock.sector_size); uint64_t start = ded->TargetFileOffset.QuadPart - (ded->TargetFileOffset.QuadPart & (Vcb->superblock.sector_size - 1));
Status = do_write_file(fcb, start, start + datalen2, data2, Irp, false, 0, &rollback); Status = do_write_file(fcb, start, start + datalen2, data2, Irp, false, 0, &rollback);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
@ -3543,7 +3543,7 @@ static NTSTATUS duplicate_extents(device_extension* Vcb, PFILE_OBJECT FileObject
if (ext->csum) { if (ext->csum) {
if (ext->extent_data.compression == BTRFS_COMPRESSION_NONE) { if (ext->extent_data.compression == BTRFS_COMPRESSION_NONE) {
ext2->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(ed2d->num_bytes * Vcb->csum_size / Vcb->superblock.sector_size), ALLOC_TAG); ext2->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)((ed2d->num_bytes * Vcb->csum_size) >> Vcb->sector_shift), ALLOC_TAG);
if (!ext2->csum) { if (!ext2->csum) {
ERR("out of memory\n"); ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
@ -3551,10 +3551,10 @@ static NTSTATUS duplicate_extents(device_extension* Vcb, PFILE_OBJECT FileObject
goto end; goto end;
} }
RtlCopyMemory(ext2->csum, (uint8_t*)ext->csum + ((ed2d->offset - ed2s->offset) * Vcb->csum_size / Vcb->superblock.sector_size), RtlCopyMemory(ext2->csum, (uint8_t*)ext->csum + (((ed2d->offset - ed2s->offset) * Vcb->csum_size) >> Vcb->sector_shift),
(ULONG)(ed2d->num_bytes * Vcb->csum_size / Vcb->superblock.sector_size)); (ULONG)((ed2d->num_bytes * Vcb->csum_size) >> Vcb->sector_shift));
} else { } else {
ext2->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(ed2d->size * Vcb->csum_size / Vcb->superblock.sector_size), ALLOC_TAG); ext2->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)((ed2d->size * Vcb->csum_size) >> Vcb->sector_shift), ALLOC_TAG);
if (!ext2->csum) { if (!ext2->csum) {
ERR("out of memory\n"); ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
@ -3562,7 +3562,7 @@ static NTSTATUS duplicate_extents(device_extension* Vcb, PFILE_OBJECT FileObject
goto end; goto end;
} }
RtlCopyMemory(ext2->csum, ext->csum, (ULONG)(ed2s->size * Vcb->csum_size / Vcb->superblock.sector_size)); RtlCopyMemory(ext2->csum, ext->csum, (ULONG)((ed2s->size * Vcb->csum_size) >> Vcb->sector_shift));
} }
} else } else
ext2->csum = NULL; ext2->csum = NULL;
@ -4674,7 +4674,7 @@ static NTSTATUS resize_device(device_extension* Vcb, void* data, ULONG len, PIRP
TRACE("(%p, %p, %lu)\n", Vcb, data, len); TRACE("(%p, %p, %lu)\n", Vcb, data, len);
if (!data || len < sizeof(btrfs_resize) || (br->size % Vcb->superblock.sector_size) != 0) if (!data || len < sizeof(btrfs_resize) || (br->size & (Vcb->superblock.sector_size - 1)) != 0)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE), Irp->RequestorMode)) if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE), Irp->RequestorMode))

View file

@ -17,171 +17,15 @@
#include "btrfs_drv.h" #include "btrfs_drv.h"
struct pnp_context;
typedef struct {
struct pnp_context* context;
PIRP Irp;
IO_STATUS_BLOCK iosb;
NTSTATUS Status;
device* dev;
} pnp_stripe;
typedef struct {
KEVENT Event;
NTSTATUS Status;
LONG left;
pnp_stripe* stripes;
} pnp_context;
extern ERESOURCE pdo_list_lock; extern ERESOURCE pdo_list_lock;
extern LIST_ENTRY pdo_list; extern LIST_ENTRY pdo_list;
_Function_class_(IO_COMPLETION_ROUTINE)
static NTSTATUS __stdcall pnp_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
pnp_stripe* stripe = conptr;
pnp_context* context = (pnp_context*)stripe->context;
UNUSED(DeviceObject);
stripe->Status = Irp->IoStatus.Status;
InterlockedDecrement(&context->left);
if (context->left == 0)
KeSetEvent(&context->Event, 0, false);
return STATUS_MORE_PROCESSING_REQUIRED;
}
static NTSTATUS send_disks_pnp_message(device_extension* Vcb, UCHAR minor) {
pnp_context context;
ULONG num_devices, i;
NTSTATUS Status;
LIST_ENTRY* le;
RtlZeroMemory(&context, sizeof(pnp_context));
KeInitializeEvent(&context.Event, NotificationEvent, false);
num_devices = (ULONG)min(0xffffffff, Vcb->superblock.num_devices);
context.stripes = ExAllocatePoolWithTag(NonPagedPool, sizeof(pnp_stripe) * num_devices, ALLOC_TAG);
if (!context.stripes) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(context.stripes, sizeof(pnp_stripe) * num_devices);
i = 0;
le = Vcb->devices.Flink;
while (le != &Vcb->devices) {
PIO_STACK_LOCATION IrpSp;
device* dev = CONTAINING_RECORD(le, device, list_entry);
if (dev->devobj) {
context.stripes[i].context = (struct pnp_context*)&context;
context.stripes[i].Irp = IoAllocateIrp(dev->devobj->StackSize, false);
if (!context.stripes[i].Irp) {
uint64_t j;
ERR("IoAllocateIrp failed\n");
for (j = 0; j < i; j++) {
if (context.stripes[j].dev->devobj) {
IoFreeIrp(context.stripes[j].Irp);
}
}
ExFreePool(context.stripes);
return STATUS_INSUFFICIENT_RESOURCES;
}
IrpSp = IoGetNextIrpStackLocation(context.stripes[i].Irp);
IrpSp->MajorFunction = IRP_MJ_PNP;
IrpSp->MinorFunction = minor;
IrpSp->FileObject = dev->fileobj;
context.stripes[i].Irp->UserIosb = &context.stripes[i].iosb;
IoSetCompletionRoutine(context.stripes[i].Irp, pnp_completion, &context.stripes[i], true, true, true);
context.stripes[i].Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
context.stripes[i].dev = dev;
context.left++;
}
le = le->Flink;
}
if (context.left == 0) {
Status = STATUS_SUCCESS;
goto end;
}
for (i = 0; i < num_devices; i++) {
if (context.stripes[i].Irp) {
IoCallDriver(context.stripes[i].dev->devobj, context.stripes[i].Irp);
}
}
KeWaitForSingleObject(&context.Event, Executive, KernelMode, false, NULL);
Status = STATUS_SUCCESS;
for (i = 0; i < num_devices; i++) {
if (context.stripes[i].Irp) {
if (context.stripes[i].Status != STATUS_SUCCESS)
Status = context.stripes[i].Status;
}
}
end:
for (i = 0; i < num_devices; i++) {
if (context.stripes[i].Irp) {
IoFreeIrp(context.stripes[i].Irp);
}
}
ExFreePool(context.stripes);
return Status;
}
static NTSTATUS pnp_cancel_remove_device(PDEVICE_OBJECT DeviceObject) {
device_extension* Vcb = DeviceObject->DeviceExtension;
NTSTATUS Status;
ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, true);
if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) {
Status = STATUS_ACCESS_DENIED;
goto end;
}
Status = send_disks_pnp_message(Vcb, IRP_MN_CANCEL_REMOVE_DEVICE);
if (!NT_SUCCESS(Status)) {
WARN("send_disks_pnp_message returned %08lx\n", Status);
goto end;
}
end:
ExReleaseResourceLite(&Vcb->fileref_lock);
ExReleaseResourceLite(&Vcb->tree_lock);
return STATUS_SUCCESS;
}
NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) { NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
device_extension* Vcb = DeviceObject->DeviceExtension; device_extension* Vcb = DeviceObject->DeviceExtension;
NTSTATUS Status; NTSTATUS Status;
// We might be going away imminently - do a flush so we're not caught out
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true); ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) { if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) {
@ -189,15 +33,6 @@ NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
return STATUS_ACCESS_DENIED; return STATUS_ACCESS_DENIED;
} }
Status = send_disks_pnp_message(Vcb, IRP_MN_QUERY_REMOVE_DEVICE);
if (!NT_SUCCESS(Status)) {
WARN("send_disks_pnp_message returned %08lx\n", Status);
ExReleaseResourceLite(&Vcb->tree_lock);
return Status;
}
Vcb->removing = true;
if (Vcb->need_write && !Vcb->readonly) { if (Vcb->need_write && !Vcb->readonly) {
Status = do_write(Vcb, Irp); Status = do_write(Vcb, Irp);
@ -212,25 +47,13 @@ NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
ExReleaseResourceLite(&Vcb->tree_lock); ExReleaseResourceLite(&Vcb->tree_lock);
if (Vcb->open_files == 0) return STATUS_UNSUCCESSFUL;
uninit(Vcb);
return STATUS_SUCCESS;
} }
static NTSTATUS pnp_remove_device(PDEVICE_OBJECT DeviceObject) { static NTSTATUS pnp_remove_device(PDEVICE_OBJECT DeviceObject) {
device_extension* Vcb = DeviceObject->DeviceExtension; device_extension* Vcb = DeviceObject->DeviceExtension;
NTSTATUS Status; NTSTATUS Status;
ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
Status = send_disks_pnp_message(Vcb, IRP_MN_REMOVE_DEVICE);
if (!NT_SUCCESS(Status))
WARN("send_disks_pnp_message returned %08lx\n", Status);
ExReleaseResourceLite(&Vcb->tree_lock);
if (DeviceObject->Vpb->Flags & VPB_MOUNTED) { if (DeviceObject->Vpb->Flags & VPB_MOUNTED) {
Status = FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_DISMOUNT); Status = FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_DISMOUNT);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
@ -649,7 +472,7 @@ NTSTATUS __stdcall drv_pnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
switch (IrpSp->MinorFunction) { switch (IrpSp->MinorFunction) {
case IRP_MN_CANCEL_REMOVE_DEVICE: case IRP_MN_CANCEL_REMOVE_DEVICE:
Status = pnp_cancel_remove_device(DeviceObject); Status = STATUS_SUCCESS;
break; break;
case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_QUERY_REMOVE_DEVICE:

View file

@ -235,7 +235,6 @@ bool check_sector_csum(device_extension* Vcb, void* buf, void* csum) {
static NTSTATUS read_data_dup(device_extension* Vcb, uint8_t* buf, uint64_t addr, read_data_context* context, CHUNK_ITEM* ci, static NTSTATUS read_data_dup(device_extension* Vcb, uint8_t* buf, uint64_t addr, read_data_context* context, CHUNK_ITEM* ci,
device** devices, uint64_t generation) { device** devices, uint64_t generation) {
ULONG i;
bool checksum_error = false; bool checksum_error = false;
uint16_t j, stripe = 0; uint16_t j, stripe = 0;
NTSTATUS Status; NTSTATUS Status;
@ -334,7 +333,7 @@ static NTSTATUS read_data_dup(device_extension* Vcb, uint8_t* buf, uint64_t addr
ExFreePool(t2); ExFreePool(t2);
} else { } else {
ULONG sectors = (ULONG)context->stripes[stripe].Irp->IoStatus.Information / Vcb->superblock.sector_size; ULONG sectors = (ULONG)context->stripes[stripe].Irp->IoStatus.Information >> Vcb->sector_shift;
uint8_t* sector; uint8_t* sector;
void* ptr = context->csum; void* ptr = context->csum;
@ -344,27 +343,27 @@ static NTSTATUS read_data_dup(device_extension* Vcb, uint8_t* buf, uint64_t addr
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
for (i = 0; i < sectors; i++) { for (ULONG i = 0; i < sectors; i++) {
if (!check_sector_csum(Vcb, buf + (i * Vcb->superblock.sector_size), ptr)) { if (!check_sector_csum(Vcb, buf + (i << Vcb->sector_shift), ptr)) {
bool recovered = false; bool recovered = false;
for (j = 0; j < ci->num_stripes; j++) { for (j = 0; j < ci->num_stripes; j++) {
if (j != stripe && devices[j] && devices[j]->devobj) { if (j != stripe && devices[j] && devices[j]->devobj) {
Status = sync_read_phys(devices[j]->devobj, devices[j]->fileobj, Status = sync_read_phys(devices[j]->devobj, devices[j]->fileobj,
cis[j].offset + context->stripes[stripe].stripestart + UInt32x32To64(i, Vcb->superblock.sector_size), cis[j].offset + context->stripes[stripe].stripestart + ((uint64_t)i << Vcb->sector_shift),
Vcb->superblock.sector_size, sector, false); Vcb->superblock.sector_size, sector, false);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
WARN("sync_read_phys returned %08lx\n", Status); WARN("sync_read_phys returned %08lx\n", Status);
log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS);
} else { } else {
if (check_sector_csum(Vcb, sector, ptr)) { if (check_sector_csum(Vcb, sector, ptr)) {
RtlCopyMemory(buf + (i * Vcb->superblock.sector_size), sector, Vcb->superblock.sector_size); RtlCopyMemory(buf + (i << Vcb->sector_shift), sector, Vcb->superblock.sector_size);
ERR("recovering from checksum error at %I64x, device %I64x\n", addr + UInt32x32To64(i, Vcb->superblock.sector_size), devices[stripe]->devitem.dev_id); ERR("recovering from checksum error at %I64x, device %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift), devices[stripe]->devitem.dev_id);
recovered = true; recovered = true;
if (!Vcb->readonly && !devices[stripe]->readonly) { // write good data over bad if (!Vcb->readonly && !devices[stripe]->readonly) { // write good data over bad
Status = write_data_phys(devices[stripe]->devobj, devices[stripe]->fileobj, Status = write_data_phys(devices[stripe]->devobj, devices[stripe]->fileobj,
cis[stripe].offset + context->stripes[stripe].stripestart + UInt32x32To64(i, Vcb->superblock.sector_size), cis[stripe].offset + context->stripes[stripe].stripestart + ((uint64_t)i << Vcb->sector_shift),
sector, Vcb->superblock.sector_size); sector, Vcb->superblock.sector_size);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
WARN("write_data_phys returned %08lx\n", Status); WARN("write_data_phys returned %08lx\n", Status);
@ -380,7 +379,7 @@ static NTSTATUS read_data_dup(device_extension* Vcb, uint8_t* buf, uint64_t addr
} }
if (!recovered) { if (!recovered) {
ERR("unrecoverable checksum error at %I64x\n", addr + UInt32x32To64(i, Vcb->superblock.sector_size)); ERR("unrecoverable checksum error at %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift));
ExFreePool(sector); ExFreePool(sector);
return STATUS_CRC_ERROR; return STATUS_CRC_ERROR;
} }
@ -397,11 +396,9 @@ static NTSTATUS read_data_dup(device_extension* Vcb, uint8_t* buf, uint64_t addr
static NTSTATUS read_data_raid0(device_extension* Vcb, uint8_t* buf, uint64_t addr, uint32_t length, read_data_context* context, static NTSTATUS read_data_raid0(device_extension* Vcb, uint8_t* buf, uint64_t addr, uint32_t length, read_data_context* context,
CHUNK_ITEM* ci, device** devices, uint64_t generation, uint64_t offset) { CHUNK_ITEM* ci, device** devices, uint64_t generation, uint64_t offset) {
uint64_t i; for (uint16_t i = 0; i < ci->num_stripes; i++) {
for (i = 0; i < ci->num_stripes; i++) {
if (context->stripes[i].status == ReadDataStatus_Error) { if (context->stripes[i].status == ReadDataStatus_Error) {
WARN("stripe %I64u returned error %08lx\n", i, context->stripes[i].iosb.Status); WARN("stripe %u returned error %08lx\n", i, context->stripes[i].iosb.Status);
log_device_error(Vcb, devices[i], BTRFS_DEV_STAT_READ_ERRORS); log_device_error(Vcb, devices[i], BTRFS_DEV_STAT_READ_ERRORS);
return context->stripes[i].iosb.Status; return context->stripes[i].iosb.Status;
} }
@ -435,17 +432,17 @@ static NTSTATUS read_data_raid0(device_extension* Vcb, uint8_t* buf, uint64_t ad
} else if (context->csum) { } else if (context->csum) {
NTSTATUS Status; NTSTATUS Status;
Status = check_csum(Vcb, buf, length / Vcb->superblock.sector_size, context->csum); Status = check_csum(Vcb, buf, length >> Vcb->sector_shift, context->csum);
if (Status == STATUS_CRC_ERROR) { if (Status == STATUS_CRC_ERROR) {
void* ptr = context->csum; void* ptr = context->csum;
for (i = 0; i < length / Vcb->superblock.sector_size; i++) { for (uint32_t i = 0; i < length >> Vcb->sector_shift; i++) {
if (!check_sector_csum(Vcb, buf + (i * Vcb->superblock.sector_size), ptr)) { if (!check_sector_csum(Vcb, buf + (i << Vcb->sector_shift), ptr)) {
uint64_t off; uint64_t off;
uint16_t stripe; uint16_t stripe;
get_raid0_offset(addr - offset + UInt32x32To64(i, Vcb->superblock.sector_size), ci->stripe_length, ci->num_stripes, &off, &stripe); get_raid0_offset(addr - offset + ((uint64_t)i << Vcb->sector_shift), ci->stripe_length, ci->num_stripes, &off, &stripe);
ERR("unrecoverable checksum error at %I64x, device %I64x\n", addr, devices[stripe]->devitem.dev_id); ERR("unrecoverable checksum error at %I64x, device %I64x\n", addr, devices[stripe]->devitem.dev_id);
@ -469,13 +466,12 @@ static NTSTATUS read_data_raid0(device_extension* Vcb, uint8_t* buf, uint64_t ad
static NTSTATUS read_data_raid10(device_extension* Vcb, uint8_t* buf, uint64_t addr, uint32_t length, read_data_context* context, static NTSTATUS read_data_raid10(device_extension* Vcb, uint8_t* buf, uint64_t addr, uint32_t length, read_data_context* context,
CHUNK_ITEM* ci, device** devices, uint64_t generation, uint64_t offset) { CHUNK_ITEM* ci, device** devices, uint64_t generation, uint64_t offset) {
uint64_t i; uint16_t stripe;
uint16_t j, stripe;
NTSTATUS Status; NTSTATUS Status;
bool checksum_error = false; bool checksum_error = false;
CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1]; CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1];
for (j = 0; j < ci->num_stripes; j++) { for (uint16_t j = 0; j < ci->num_stripes; j++) {
if (context->stripes[j].status == ReadDataStatus_Error) { if (context->stripes[j].status == ReadDataStatus_Error) {
WARN("stripe %u returned error %08lx\n", j, context->stripes[j].iosb.Status); WARN("stripe %u returned error %08lx\n", j, context->stripes[j].iosb.Status);
log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS);
@ -500,7 +496,7 @@ static NTSTATUS read_data_raid10(device_extension* Vcb, uint8_t* buf, uint64_t a
log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_GENERATION_ERRORS); log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_GENERATION_ERRORS);
} }
} else if (context->csum) { } else if (context->csum) {
Status = check_csum(Vcb, buf, length / Vcb->superblock.sector_size, context->csum); Status = check_csum(Vcb, buf, length >> Vcb->sector_shift, context->csum);
if (Status == STATUS_CRC_ERROR) if (Status == STATUS_CRC_ERROR)
checksum_error = true; checksum_error = true;
@ -529,14 +525,14 @@ static NTSTATUS read_data_raid10(device_extension* Vcb, uint8_t* buf, uint64_t a
stripe *= ci->sub_stripes; stripe *= ci->sub_stripes;
for (j = 0; j < ci->sub_stripes; j++) { for (uint16_t j = 0; j < ci->sub_stripes; j++) {
if (context->stripes[stripe + j].status == ReadDataStatus_Success) { if (context->stripes[stripe + j].status == ReadDataStatus_Success) {
badsubstripe = j; badsubstripe = j;
break; break;
} }
} }
for (j = 0; j < ci->sub_stripes; j++) { for (uint16_t j = 0; j < ci->sub_stripes; j++) {
if (context->stripes[stripe + j].status != ReadDataStatus_Success && devices[stripe + j] && devices[stripe + j]->devobj) { if (context->stripes[stripe + j].status != ReadDataStatus_Success && devices[stripe + j] && devices[stripe + j]->devobj) {
Status = sync_read_phys(devices[stripe + j]->devobj, devices[stripe + j]->fileobj, cis[stripe + j].offset + off, Status = sync_read_phys(devices[stripe + j]->devobj, devices[stripe + j]->fileobj, cis[stripe + j].offset + off,
Vcb->superblock.node_size, (uint8_t*)t2, false); Vcb->superblock.node_size, (uint8_t*)t2, false);
@ -577,7 +573,7 @@ static NTSTATUS read_data_raid10(device_extension* Vcb, uint8_t* buf, uint64_t a
ExFreePool(t2); ExFreePool(t2);
} else { } else {
ULONG sectors = length / Vcb->superblock.sector_size; ULONG sectors = length >> Vcb->sector_shift;
uint8_t* sector; uint8_t* sector;
void* ptr = context->csum; void* ptr = context->csum;
@ -587,18 +583,18 @@ static NTSTATUS read_data_raid10(device_extension* Vcb, uint8_t* buf, uint64_t a
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
for (i = 0; i < sectors; i++) { for (ULONG i = 0; i < sectors; i++) {
if (!check_sector_csum(Vcb, buf + (i * Vcb->superblock.sector_size), ptr)) { if (!check_sector_csum(Vcb, buf + (i << Vcb->sector_shift), ptr)) {
uint64_t off; uint64_t off;
uint16_t stripe2, badsubstripe = 0; uint16_t stripe2, badsubstripe = 0;
bool recovered = false; bool recovered = false;
get_raid0_offset(addr - offset + UInt32x32To64(i, Vcb->superblock.sector_size), ci->stripe_length, get_raid0_offset(addr - offset + ((uint64_t)i << Vcb->sector_shift), ci->stripe_length,
ci->num_stripes / ci->sub_stripes, &off, &stripe2); ci->num_stripes / ci->sub_stripes, &off, &stripe2);
stripe2 *= ci->sub_stripes; stripe2 *= ci->sub_stripes;
for (j = 0; j < ci->sub_stripes; j++) { for (uint16_t j = 0; j < ci->sub_stripes; j++) {
if (context->stripes[stripe2 + j].status == ReadDataStatus_Success) { if (context->stripes[stripe2 + j].status == ReadDataStatus_Success) {
badsubstripe = j; badsubstripe = j;
break; break;
@ -607,7 +603,7 @@ static NTSTATUS read_data_raid10(device_extension* Vcb, uint8_t* buf, uint64_t a
log_device_error(Vcb, devices[stripe2 + badsubstripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS); log_device_error(Vcb, devices[stripe2 + badsubstripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
for (j = 0; j < ci->sub_stripes; j++) { for (uint16_t j = 0; j < ci->sub_stripes; j++) {
if (context->stripes[stripe2 + j].status != ReadDataStatus_Success && devices[stripe2 + j] && devices[stripe2 + j]->devobj) { if (context->stripes[stripe2 + j].status != ReadDataStatus_Success && devices[stripe2 + j] && devices[stripe2 + j]->devobj) {
Status = sync_read_phys(devices[stripe2 + j]->devobj, devices[stripe2 + j]->fileobj, cis[stripe2 + j].offset + off, Status = sync_read_phys(devices[stripe2 + j]->devobj, devices[stripe2 + j]->fileobj, cis[stripe2 + j].offset + off,
Vcb->superblock.sector_size, sector, false); Vcb->superblock.sector_size, sector, false);
@ -616,8 +612,8 @@ static NTSTATUS read_data_raid10(device_extension* Vcb, uint8_t* buf, uint64_t a
log_device_error(Vcb, devices[stripe2 + j], BTRFS_DEV_STAT_READ_ERRORS); log_device_error(Vcb, devices[stripe2 + j], BTRFS_DEV_STAT_READ_ERRORS);
} else { } else {
if (check_sector_csum(Vcb, sector, ptr)) { if (check_sector_csum(Vcb, sector, ptr)) {
RtlCopyMemory(buf + (i * Vcb->superblock.sector_size), sector, Vcb->superblock.sector_size); RtlCopyMemory(buf + (i << Vcb->sector_shift), sector, Vcb->superblock.sector_size);
ERR("recovering from checksum error at %I64x, device %I64x\n", addr + UInt32x32To64(i, Vcb->superblock.sector_size), devices[stripe2 + j]->devitem.dev_id); ERR("recovering from checksum error at %I64x, device %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift), devices[stripe2 + j]->devitem.dev_id);
recovered = true; recovered = true;
if (!Vcb->readonly && !devices[stripe2 + badsubstripe]->readonly && devices[stripe2 + badsubstripe]->devobj) { // write good data over bad if (!Vcb->readonly && !devices[stripe2 + badsubstripe]->readonly && devices[stripe2 + badsubstripe]->devobj) { // write good data over bad
@ -637,7 +633,7 @@ static NTSTATUS read_data_raid10(device_extension* Vcb, uint8_t* buf, uint64_t a
} }
if (!recovered) { if (!recovered) {
ERR("unrecoverable checksum error at %I64x\n", addr + UInt32x32To64(i, Vcb->superblock.sector_size)); ERR("unrecoverable checksum error at %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift));
ExFreePool(sector); ExFreePool(sector);
return STATUS_CRC_ERROR; return STATUS_CRC_ERROR;
} }
@ -654,7 +650,6 @@ static NTSTATUS read_data_raid10(device_extension* Vcb, uint8_t* buf, uint64_t a
static NTSTATUS read_data_raid5(device_extension* Vcb, uint8_t* buf, uint64_t addr, uint32_t length, read_data_context* context, CHUNK_ITEM* ci, static NTSTATUS read_data_raid5(device_extension* Vcb, uint8_t* buf, uint64_t addr, uint32_t length, read_data_context* context, CHUNK_ITEM* ci,
device** devices, uint64_t offset, uint64_t generation, chunk* c, bool degraded) { device** devices, uint64_t offset, uint64_t generation, chunk* c, bool degraded) {
ULONG i;
NTSTATUS Status; NTSTATUS Status;
bool checksum_error = false; bool checksum_error = false;
CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1]; CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1];
@ -700,15 +695,14 @@ static NTSTATUS read_data_raid5(device_extension* Vcb, uint8_t* buf, uint64_t ad
if (runlength == 0) if (runlength == 0)
break; break;
} }
#ifndef __REACTOS__ #ifndef __REACTOS__
uint64_t runstart = ps->address + (index * Vcb->superblock.sector_size); uint64_t runstart = ps->address + (index << Vcb->sector_shift);
uint64_t runend = runstart + (runlength * Vcb->superblock.sector_size); uint64_t runend = runstart + (runlength << Vcb->sector_shift);
uint64_t start = max(runstart, addr); uint64_t start = max(runstart, addr);
uint64_t end = min(runend, addr + length); uint64_t end = min(runend, addr + length);
#else #else
runstart = ps->address + (index * Vcb->superblock.sector_size); runstart = ps->address + (index * Vcb->sector_shift);
runend = runstart + (runlength * Vcb->superblock.sector_size); runend = runstart + (runlength * Vcb->sector_shift);
start = max(runstart, addr); start = max(runstart, addr);
end = min(runend, addr + length); end = min(runend, addr + length);
#endif #endif
@ -740,7 +734,7 @@ static NTSTATUS read_data_raid5(device_extension* Vcb, uint8_t* buf, uint64_t ad
log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_GENERATION_ERRORS); log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_GENERATION_ERRORS);
} }
} else if (context->csum) { } else if (context->csum) {
Status = check_csum(Vcb, buf, length / Vcb->superblock.sector_size, context->csum); Status = check_csum(Vcb, buf, length >> Vcb->sector_shift, context->csum);
if (Status == STATUS_CRC_ERROR) { if (Status == STATUS_CRC_ERROR) {
if (!degraded) if (!degraded)
@ -834,7 +828,7 @@ static NTSTATUS read_data_raid5(device_extension* Vcb, uint8_t* buf, uint64_t ad
ExFreePool(t2); ExFreePool(t2);
} else { } else {
ULONG sectors = length / Vcb->superblock.sector_size; ULONG sectors = length >> Vcb->sector_shift;
uint8_t* sector; uint8_t* sector;
void* ptr = context->csum; void* ptr = context->csum;
@ -844,18 +838,18 @@ static NTSTATUS read_data_raid5(device_extension* Vcb, uint8_t* buf, uint64_t ad
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
for (i = 0; i < sectors; i++) { for (ULONG i = 0; i < sectors; i++) {
uint16_t parity; uint16_t parity;
uint64_t off; uint64_t off;
get_raid0_offset(addr - offset + UInt32x32To64(i, Vcb->superblock.sector_size), ci->stripe_length, get_raid0_offset(addr - offset + ((uint64_t)i << Vcb->sector_shift), ci->stripe_length,
ci->num_stripes - 1, &off, &stripe); ci->num_stripes - 1, &off, &stripe);
parity = (((addr - offset + UInt32x32To64(i, Vcb->superblock.sector_size)) / ((ci->num_stripes - 1) * ci->stripe_length)) + ci->num_stripes - 1) % ci->num_stripes; parity = (((addr - offset + ((uint64_t)i << Vcb->sector_shift)) / ((ci->num_stripes - 1) * ci->stripe_length)) + ci->num_stripes - 1) % ci->num_stripes;
stripe = (parity + stripe + 1) % ci->num_stripes; stripe = (parity + stripe + 1) % ci->num_stripes;
if (!devices[stripe] || !devices[stripe]->devobj || (ptr && !check_sector_csum(Vcb, buf + (i * Vcb->superblock.sector_size), ptr))) { if (!devices[stripe] || !devices[stripe]->devobj || (ptr && !check_sector_csum(Vcb, buf + (i << Vcb->sector_shift), ptr))) {
bool recovered = false, first = true, failed = false; bool recovered = false, first = true, failed = false;
if (devices[stripe] && devices[stripe]->devobj) if (devices[stripe] && devices[stripe]->devobj)
@ -895,10 +889,10 @@ static NTSTATUS read_data_raid5(device_extension* Vcb, uint8_t* buf, uint64_t ad
if (!failed) { if (!failed) {
if (!ptr || check_sector_csum(Vcb, sector, ptr)) { if (!ptr || check_sector_csum(Vcb, sector, ptr)) {
RtlCopyMemory(buf + (i * Vcb->superblock.sector_size), sector, Vcb->superblock.sector_size); RtlCopyMemory(buf + (i << Vcb->sector_shift), sector, Vcb->superblock.sector_size);
if (!degraded) if (!degraded)
ERR("recovering from checksum error at %I64x, device %I64x\n", addr + UInt32x32To64(i, Vcb->superblock.sector_size), devices[stripe]->devitem.dev_id); ERR("recovering from checksum error at %I64x, device %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift), devices[stripe]->devitem.dev_id);
recovered = true; recovered = true;
@ -914,7 +908,7 @@ static NTSTATUS read_data_raid5(device_extension* Vcb, uint8_t* buf, uint64_t ad
} }
if (!recovered) { if (!recovered) {
ERR("unrecoverable checksum error at %I64x\n", addr + UInt32x32To64(i, Vcb->superblock.sector_size)); ERR("unrecoverable checksum error at %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift));
ExFreePool(sector); ExFreePool(sector);
return STATUS_CRC_ERROR; return STATUS_CRC_ERROR;
} }
@ -1019,7 +1013,6 @@ void raid6_recover2(uint8_t* sectors, uint16_t num_stripes, ULONG sector_size, u
static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uint64_t addr, uint32_t length, read_data_context* context, CHUNK_ITEM* ci, static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uint64_t addr, uint32_t length, read_data_context* context, CHUNK_ITEM* ci,
device** devices, uint64_t offset, uint64_t generation, chunk* c, bool degraded) { device** devices, uint64_t offset, uint64_t generation, chunk* c, bool degraded) {
NTSTATUS Status; NTSTATUS Status;
ULONG i;
bool checksum_error = false; bool checksum_error = false;
CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1]; CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1];
uint16_t stripe, j; uint16_t stripe, j;
@ -1068,13 +1061,13 @@ static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uint64_t ad
} }
#ifndef __REACTOS__ #ifndef __REACTOS__
uint64_t runstart = ps->address + (index * Vcb->superblock.sector_size); uint64_t runstart = ps->address + (index << Vcb->sector_shift);
uint64_t runend = runstart + (runlength * Vcb->superblock.sector_size); uint64_t runend = runstart + (runlength << Vcb->sector_shift);
uint64_t start = max(runstart, addr); uint64_t start = max(runstart, addr);
uint64_t end = min(runend, addr + length); uint64_t end = min(runend, addr + length);
#else #else
runstart = ps->address + (index * Vcb->superblock.sector_size); runstart = ps->address + (index * Vcb->sector_shift);
runend = runstart + (runlength * Vcb->superblock.sector_size); runend = runstart + (runlength * Vcb->sector_shift);
start = max(runstart, addr); start = max(runstart, addr);
end = min(runend, addr + length); end = min(runend, addr + length);
#endif #endif
@ -1106,7 +1099,7 @@ static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uint64_t ad
log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_GENERATION_ERRORS); log_device_error(Vcb, devices[stripe], BTRFS_DEV_STAT_GENERATION_ERRORS);
} }
} else if (context->csum) { } else if (context->csum) {
Status = check_csum(Vcb, buf, length / Vcb->superblock.sector_size, context->csum); Status = check_csum(Vcb, buf, length >> Vcb->sector_shift, context->csum);
if (Status == STATUS_CRC_ERROR) { if (Status == STATUS_CRC_ERROR) {
if (!degraded) if (!degraded)
@ -1305,30 +1298,30 @@ static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uint64_t ad
ExFreePool(sector); ExFreePool(sector);
} else { } else {
ULONG sectors = length / Vcb->superblock.sector_size; ULONG sectors = length >> Vcb->sector_shift;
uint8_t* sector; uint8_t* sector;
void* ptr = context->csum; void* ptr = context->csum;
sector = ExAllocatePoolWithTag(NonPagedPool, Vcb->superblock.sector_size * (ci->num_stripes + 2), ALLOC_TAG); sector = ExAllocatePoolWithTag(NonPagedPool, (ci->num_stripes + 2) << Vcb->sector_shift, ALLOC_TAG);
if (!sector) { if (!sector) {
ERR("out of memory\n"); ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
for (i = 0; i < sectors; i++) { for (ULONG i = 0; i < sectors; i++) {
uint64_t off; uint64_t off;
uint16_t physstripe, parity1, parity2; uint16_t physstripe, parity1, parity2;
get_raid0_offset(addr - offset + UInt32x32To64(i, Vcb->superblock.sector_size), ci->stripe_length, get_raid0_offset(addr - offset + ((uint64_t)i << Vcb->sector_shift), ci->stripe_length,
ci->num_stripes - 2, &off, &stripe); ci->num_stripes - 2, &off, &stripe);
parity1 = (((addr - offset + UInt32x32To64(i, Vcb->superblock.sector_size)) / ((ci->num_stripes - 2) * ci->stripe_length)) + ci->num_stripes - 2) % ci->num_stripes; parity1 = (((addr - offset + ((uint64_t)i << Vcb->sector_shift)) / ((ci->num_stripes - 2) * ci->stripe_length)) + ci->num_stripes - 2) % ci->num_stripes;
parity2 = (parity1 + 1) % ci->num_stripes; parity2 = (parity1 + 1) % ci->num_stripes;
physstripe = (parity2 + stripe + 1) % ci->num_stripes; physstripe = (parity2 + stripe + 1) % ci->num_stripes;
if (!devices[physstripe] || !devices[physstripe]->devobj || (context->csum && !check_sector_csum(Vcb, buf + (i * Vcb->superblock.sector_size), ptr))) { if (!devices[physstripe] || !devices[physstripe]->devobj || (context->csum && !check_sector_csum(Vcb, buf + (i << Vcb->sector_shift), ptr))) {
uint16_t k, error_stripe; uint16_t error_stripe;
bool recovered = false, failed = false; bool recovered = false, failed = false;
ULONG num_errors = 0; ULONG num_errors = 0;
@ -1337,11 +1330,11 @@ static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uint64_t ad
j = (parity2 + 1) % ci->num_stripes; j = (parity2 + 1) % ci->num_stripes;
for (k = 0; k < ci->num_stripes - 1; k++) { for (uint16_t k = 0; k < ci->num_stripes - 1; k++) {
if (j != physstripe) { if (j != physstripe) {
if (devices[j] && devices[j]->devobj) { if (devices[j] && devices[j]->devobj) {
Status = sync_read_phys(devices[j]->devobj, devices[j]->fileobj, cis[j].offset + off, Vcb->superblock.sector_size, Status = sync_read_phys(devices[j]->devobj, devices[j]->fileobj, cis[j].offset + off, Vcb->superblock.sector_size,
sector + (k * Vcb->superblock.sector_size), false); sector + ((ULONG)k << Vcb->sector_shift), false);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("sync_read_phys returned %08lx\n", Status); ERR("sync_read_phys returned %08lx\n", Status);
log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS); log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS);
@ -1369,25 +1362,25 @@ static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uint64_t ad
if (!failed) { if (!failed) {
if (num_errors == 0) { if (num_errors == 0) {
RtlCopyMemory(sector + (stripe * Vcb->superblock.sector_size), sector + ((ci->num_stripes - 2) * Vcb->superblock.sector_size), Vcb->superblock.sector_size); RtlCopyMemory(sector + ((unsigned int)stripe << Vcb->sector_shift), sector + ((unsigned int)(ci->num_stripes - 2) << Vcb->sector_shift), Vcb->superblock.sector_size);
for (j = 0; j < ci->num_stripes - 2; j++) { for (j = 0; j < ci->num_stripes - 2; j++) {
if (j != stripe) if (j != stripe)
do_xor(sector + (stripe * Vcb->superblock.sector_size), sector + (j * Vcb->superblock.sector_size), Vcb->superblock.sector_size); do_xor(sector + ((unsigned int)stripe << Vcb->sector_shift), sector + ((unsigned int)j << Vcb->sector_shift), Vcb->superblock.sector_size);
} }
if (!ptr || check_sector_csum(Vcb, sector + (stripe * Vcb->superblock.sector_size), ptr)) { if (!ptr || check_sector_csum(Vcb, sector + ((unsigned int)stripe << Vcb->sector_shift), ptr)) {
RtlCopyMemory(buf + (i * Vcb->superblock.sector_size), sector + (stripe * Vcb->superblock.sector_size), Vcb->superblock.sector_size); RtlCopyMemory(buf + (i << Vcb->sector_shift), sector + ((unsigned int)stripe << Vcb->sector_shift), Vcb->superblock.sector_size);
if (devices[physstripe] && devices[physstripe]->devobj) if (devices[physstripe] && devices[physstripe]->devobj)
ERR("recovering from checksum error at %I64x, device %I64x\n", addr + UInt32x32To64(i, Vcb->superblock.sector_size), ERR("recovering from checksum error at %I64x, device %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift),
devices[physstripe]->devitem.dev_id); devices[physstripe]->devitem.dev_id);
recovered = true; recovered = true;
if (!Vcb->readonly && devices[physstripe] && devices[physstripe]->devobj && !devices[physstripe]->readonly) { // write good data over bad if (!Vcb->readonly && devices[physstripe] && devices[physstripe]->devobj && !devices[physstripe]->readonly) { // write good data over bad
Status = write_data_phys(devices[physstripe]->devobj, devices[physstripe]->fileobj, cis[physstripe].offset + off, Status = write_data_phys(devices[physstripe]->devobj, devices[physstripe]->fileobj, cis[physstripe].offset + off,
sector + (stripe * Vcb->superblock.sector_size), Vcb->superblock.sector_size); sector + ((unsigned int)stripe << Vcb->sector_shift), Vcb->superblock.sector_size);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
WARN("write_data_phys returned %08lx\n", Status); WARN("write_data_phys returned %08lx\n", Status);
log_device_error(Vcb, devices[physstripe], BTRFS_DEV_STAT_WRITE_ERRORS); log_device_error(Vcb, devices[physstripe], BTRFS_DEV_STAT_WRITE_ERRORS);
@ -1401,7 +1394,7 @@ static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uint64_t ad
if (devices[parity2] && devices[parity2]->devobj) { if (devices[parity2] && devices[parity2]->devobj) {
Status = sync_read_phys(devices[parity2]->devobj, devices[parity2]->fileobj, cis[parity2].offset + off, Status = sync_read_phys(devices[parity2]->devobj, devices[parity2]->fileobj, cis[parity2].offset + off,
Vcb->superblock.sector_size, sector + ((ci->num_stripes - 1) * Vcb->superblock.sector_size), false); Vcb->superblock.sector_size, sector + ((unsigned int)(ci->num_stripes - 1) << Vcb->sector_shift), false);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("sync_read_phys returned %08lx\n", Status); ERR("sync_read_phys returned %08lx\n", Status);
log_device_error(Vcb, devices[parity2], BTRFS_DEV_STAT_READ_ERRORS); log_device_error(Vcb, devices[parity2], BTRFS_DEV_STAT_READ_ERRORS);
@ -1411,18 +1404,18 @@ static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uint64_t ad
if (read_q) { if (read_q) {
if (num_errors == 1) { if (num_errors == 1) {
raid6_recover2(sector, ci->num_stripes, Vcb->superblock.sector_size, stripe, error_stripe, sector + (ci->num_stripes * Vcb->superblock.sector_size)); raid6_recover2(sector, ci->num_stripes, Vcb->superblock.sector_size, stripe, error_stripe, sector + ((unsigned int)ci->num_stripes << Vcb->sector_shift));
if (!devices[physstripe] || !devices[physstripe]->devobj) if (!devices[physstripe] || !devices[physstripe]->devobj)
recovered = true; recovered = true;
else else
recovered = check_sector_csum(Vcb, sector + (ci->num_stripes * Vcb->superblock.sector_size), ptr); recovered = check_sector_csum(Vcb, sector + ((unsigned int)ci->num_stripes << Vcb->sector_shift), ptr);
} else { } else {
for (j = 0; j < ci->num_stripes - 1; j++) { for (j = 0; j < ci->num_stripes - 1; j++) {
if (j != stripe) { if (j != stripe) {
raid6_recover2(sector, ci->num_stripes, Vcb->superblock.sector_size, stripe, j, sector + (ci->num_stripes * Vcb->superblock.sector_size)); raid6_recover2(sector, ci->num_stripes, Vcb->superblock.sector_size, stripe, j, sector + ((unsigned int)ci->num_stripes << Vcb->sector_shift));
if (check_sector_csum(Vcb, sector + (ci->num_stripes * Vcb->superblock.sector_size), ptr)) { if (check_sector_csum(Vcb, sector + ((unsigned int)ci->num_stripes << Vcb->sector_shift), ptr)) {
recovered = true; recovered = true;
error_stripe = j; error_stripe = j;
break; break;
@ -1437,13 +1430,13 @@ static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uint64_t ad
if (devices[physstripe] && devices[physstripe]->devobj) if (devices[physstripe] && devices[physstripe]->devobj)
ERR("recovering from checksum error at %I64x, device %I64x\n", ERR("recovering from checksum error at %I64x, device %I64x\n",
addr + UInt32x32To64(i, Vcb->superblock.sector_size), devices[physstripe]->devitem.dev_id); addr + ((uint64_t)i << Vcb->sector_shift), devices[physstripe]->devitem.dev_id);
RtlCopyMemory(buf + (i * Vcb->superblock.sector_size), sector + (ci->num_stripes * Vcb->superblock.sector_size), Vcb->superblock.sector_size); RtlCopyMemory(buf + (i << Vcb->sector_shift), sector + ((unsigned int)ci->num_stripes << Vcb->sector_shift), Vcb->superblock.sector_size);
if (!Vcb->readonly && devices[physstripe] && devices[physstripe]->devobj && !devices[physstripe]->readonly) { // write good data over bad if (!Vcb->readonly && devices[physstripe] && devices[physstripe]->devobj && !devices[physstripe]->readonly) { // write good data over bad
Status = write_data_phys(devices[physstripe]->devobj, devices[physstripe]->fileobj, cis[physstripe].offset + off, Status = write_data_phys(devices[physstripe]->devobj, devices[physstripe]->fileobj, cis[physstripe].offset + off,
sector + (ci->num_stripes * Vcb->superblock.sector_size), Vcb->superblock.sector_size); sector + ((unsigned int)ci->num_stripes << Vcb->sector_shift), Vcb->superblock.sector_size);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
WARN("write_data_phys returned %08lx\n", Status); WARN("write_data_phys returned %08lx\n", Status);
log_device_error(Vcb, devices[physstripe], BTRFS_DEV_STAT_WRITE_ERRORS); log_device_error(Vcb, devices[physstripe], BTRFS_DEV_STAT_WRITE_ERRORS);
@ -1452,37 +1445,37 @@ static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uint64_t ad
if (devices[error_stripe_phys] && devices[error_stripe_phys]->devobj) { if (devices[error_stripe_phys] && devices[error_stripe_phys]->devobj) {
if (error_stripe == ci->num_stripes - 2) { if (error_stripe == ci->num_stripes - 2) {
ERR("recovering from parity error at %I64x, device %I64x\n", addr + UInt32x32To64(i, Vcb->superblock.sector_size), ERR("recovering from parity error at %I64x, device %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift),
devices[error_stripe_phys]->devitem.dev_id); devices[error_stripe_phys]->devitem.dev_id);
log_device_error(Vcb, devices[error_stripe_phys], BTRFS_DEV_STAT_CORRUPTION_ERRORS); log_device_error(Vcb, devices[error_stripe_phys], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
RtlZeroMemory(sector + ((ci->num_stripes - 2) * Vcb->superblock.sector_size), Vcb->superblock.sector_size); RtlZeroMemory(sector + ((unsigned int)(ci->num_stripes - 2) << Vcb->sector_shift), Vcb->superblock.sector_size);
for (j = 0; j < ci->num_stripes - 2; j++) { for (j = 0; j < ci->num_stripes - 2; j++) {
if (j == stripe) { if (j == stripe) {
do_xor(sector + ((ci->num_stripes - 2) * Vcb->superblock.sector_size), sector + (ci->num_stripes * Vcb->superblock.sector_size), do_xor(sector + ((unsigned int)(ci->num_stripes - 2) << Vcb->sector_shift), sector + ((unsigned int)ci->num_stripes << Vcb->sector_shift),
Vcb->superblock.sector_size); Vcb->superblock.sector_size);
} else { } else {
do_xor(sector + ((ci->num_stripes - 2) * Vcb->superblock.sector_size), sector + (j * Vcb->superblock.sector_size), do_xor(sector + ((unsigned int)(ci->num_stripes - 2) << Vcb->sector_shift), sector + ((unsigned int)j << Vcb->sector_shift),
Vcb->superblock.sector_size); Vcb->superblock.sector_size);
} }
} }
} else { } else {
ERR("recovering from checksum error at %I64x, device %I64x\n", ERR("recovering from checksum error at %I64x, device %I64x\n",
addr + UInt32x32To64(i, Vcb->superblock.sector_size) + ((error_stripe - stripe) * ci->stripe_length), addr + ((uint64_t)i << Vcb->sector_shift) + ((error_stripe - stripe) * ci->stripe_length),
devices[error_stripe_phys]->devitem.dev_id); devices[error_stripe_phys]->devitem.dev_id);
log_device_error(Vcb, devices[error_stripe_phys], BTRFS_DEV_STAT_CORRUPTION_ERRORS); log_device_error(Vcb, devices[error_stripe_phys], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
RtlCopyMemory(sector + (error_stripe * Vcb->superblock.sector_size), RtlCopyMemory(sector + ((unsigned int)error_stripe << Vcb->sector_shift),
sector + ((ci->num_stripes + 1) * Vcb->superblock.sector_size), Vcb->superblock.sector_size); sector + ((unsigned int)(ci->num_stripes + 1) << Vcb->sector_shift), Vcb->superblock.sector_size);
} }
} }
if (!Vcb->readonly && devices[error_stripe_phys] && devices[error_stripe_phys]->devobj && !devices[error_stripe_phys]->readonly) { // write good data over bad if (!Vcb->readonly && devices[error_stripe_phys] && devices[error_stripe_phys]->devobj && !devices[error_stripe_phys]->readonly) { // write good data over bad
Status = write_data_phys(devices[error_stripe_phys]->devobj, devices[error_stripe_phys]->fileobj, cis[error_stripe_phys].offset + off, Status = write_data_phys(devices[error_stripe_phys]->devobj, devices[error_stripe_phys]->fileobj, cis[error_stripe_phys].offset + off,
sector + (error_stripe * Vcb->superblock.sector_size), Vcb->superblock.sector_size); sector + ((unsigned int)error_stripe << Vcb->sector_shift), Vcb->superblock.sector_size);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
WARN("write_data_phys returned %08lx\n", Status); WARN("write_data_phys returned %08lx\n", Status);
log_device_error(Vcb, devices[error_stripe_phys], BTRFS_DEV_STAT_WRITE_ERRORS); log_device_error(Vcb, devices[error_stripe_phys], BTRFS_DEV_STAT_WRITE_ERRORS);
@ -1493,7 +1486,7 @@ static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uint64_t ad
} }
if (!recovered) { if (!recovered) {
ERR("unrecoverable checksum error at %I64x\n", addr + UInt32x32To64(i, Vcb->superblock.sector_size)); ERR("unrecoverable checksum error at %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift));
ExFreePool(sector); ExFreePool(sector);
return STATUS_CRC_ERROR; return STATUS_CRC_ERROR;
} }
@ -1796,9 +1789,9 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ uint64_t addr, _In_ uint32_t
} else } else
context.va = buf; context.va = buf;
context.firstoff = (uint16_t)((startoff % ci->stripe_length) / Vcb->superblock.sector_size); context.firstoff = (uint16_t)((startoff % ci->stripe_length) >> Vcb->sector_shift);
context.startoffstripe = startoffstripe; context.startoffstripe = startoffstripe;
context.sectors_per_stripe = (uint16_t)(ci->stripe_length / Vcb->superblock.sector_size); context.sectors_per_stripe = (uint16_t)(ci->stripe_length >> Vcb->sector_shift);
startoffstripe *= ci->sub_stripes; startoffstripe *= ci->sub_stripes;
endoffstripe *= ci->sub_stripes; endoffstripe *= ci->sub_stripes;
@ -2761,6 +2754,7 @@ exit:
return Status; return Status;
} }
__attribute__((nonnull(1, 2)))
NTSTATUS read_stream(fcb* fcb, uint8_t* data, uint64_t start, ULONG length, ULONG* pbr) { NTSTATUS read_stream(fcb* fcb, uint8_t* data, uint64_t start, ULONG length, ULONG* pbr) {
ULONG readlen; ULONG readlen;
@ -2825,6 +2819,7 @@ typedef struct {
size_t length; size_t length;
} comp_calc_job; } comp_calc_job;
__attribute__((nonnull(1, 2)))
NTSTATUS read_file(fcb* fcb, uint8_t* data, uint64_t start, uint64_t length, ULONG* pbr, PIRP Irp) { NTSTATUS read_file(fcb* fcb, uint8_t* data, uint64_t start, uint64_t length, ULONG* pbr, PIRP Irp) {
NTSTATUS Status; NTSTATUS Status;
uint32_t bytes_read = 0; uint32_t bytes_read = 0;
@ -2853,14 +2848,16 @@ NTSTATUS read_file(fcb* fcb, uint8_t* data, uint64_t start, uint64_t length, ULO
last_end = start; last_end = start;
while (le != &fcb->extents) { while (le != &fcb->extents) {
uint64_t len;
extent* ext = CONTAINING_RECORD(le, extent, list_entry); extent* ext = CONTAINING_RECORD(le, extent, list_entry);
if (!ext->ignore) { if (!ext->ignore) {
EXTENT_DATA* ed = &ext->extent_data; EXTENT_DATA* ed = &ext->extent_data;
EXTENT_DATA2* ed2 = (ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) ? (EXTENT_DATA2*)ed->data : NULL; uint64_t len;
len = ed2 ? ed2->num_bytes : ed->decoded_size; if (ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC)
len = ((EXTENT_DATA2*)ed->data)->num_bytes;
else
len = ed->decoded_size;
if (ext->offset + len <= start) { if (ext->offset + len <= start) {
last_end = ext->offset + len; last_end = ext->offset + len;
@ -2976,6 +2973,7 @@ NTSTATUS read_file(fcb* fcb, uint8_t* data, uint64_t start, uint64_t length, ULO
case EXTENT_TYPE_REGULAR: case EXTENT_TYPE_REGULAR:
{ {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;
read_part* rp; read_part* rp;
rp = ExAllocatePoolWithTag(pool_type, sizeof(read_part), ALLOC_TAG); rp = ExAllocatePoolWithTag(pool_type, sizeof(read_part), ALLOC_TAG);
@ -2998,8 +2996,8 @@ NTSTATUS read_file(fcb* fcb, uint8_t* data, uint64_t start, uint64_t length, ULO
rp->addr = ed2->address + ed2->offset + rp->extents[0].off; rp->addr = ed2->address + ed2->offset + rp->extents[0].off;
rp->to_read = (uint32_t)sector_align(rp->read, fcb->Vcb->superblock.sector_size); rp->to_read = (uint32_t)sector_align(rp->read, fcb->Vcb->superblock.sector_size);
if (rp->addr % fcb->Vcb->superblock.sector_size > 0) { if (rp->addr & (fcb->Vcb->superblock.sector_size - 1)) {
rp->bumpoff = rp->addr % fcb->Vcb->superblock.sector_size; rp->bumpoff = rp->addr & (fcb->Vcb->superblock.sector_size - 1);
rp->addr -= rp->bumpoff; rp->addr -= rp->bumpoff;
rp->to_read = (uint32_t)sector_align(rp->read + rp->bumpoff, fcb->Vcb->superblock.sector_size); rp->to_read = (uint32_t)sector_align(rp->read + rp->bumpoff, fcb->Vcb->superblock.sector_size);
} }
@ -3008,8 +3006,8 @@ NTSTATUS read_file(fcb* fcb, uint8_t* data, uint64_t start, uint64_t length, ULO
rp->to_read = (uint32_t)sector_align(ed2->size, fcb->Vcb->superblock.sector_size); rp->to_read = (uint32_t)sector_align(ed2->size, fcb->Vcb->superblock.sector_size);
} }
if (ed->compression == BTRFS_COMPRESSION_NONE && start % fcb->Vcb->superblock.sector_size == 0 && if (ed->compression == BTRFS_COMPRESSION_NONE && (start & (fcb->Vcb->superblock.sector_size - 1)) == 0 &&
length % fcb->Vcb->superblock.sector_size == 0) { (length & (fcb->Vcb->superblock.sector_size - 1)) == 0) {
rp->buf = data + bytes_read; rp->buf = data + bytes_read;
rp->buf_free = false; rp->buf_free = false;
} else { } else {
@ -3036,12 +3034,13 @@ NTSTATUS read_file(fcb* fcb, uint8_t* data, uint64_t start, uint64_t length, ULO
ExFreePool(rp); ExFreePool(rp);
Status = STATUS_INTERNAL_ERROR;
goto exit; goto exit;
} }
if (ext->csum) { if (ext->csum) {
if (ed->compression == BTRFS_COMPRESSION_NONE) { if (ed->compression == BTRFS_COMPRESSION_NONE) {
rp->csum = (uint8_t*)ext->csum + (fcb->Vcb->csum_size * (rp->extents[0].off / fcb->Vcb->superblock.sector_size)); rp->csum = (uint8_t*)ext->csum + (fcb->Vcb->csum_size * (rp->extents[0].off >> fcb->Vcb->sector_shift));
} else } else
rp->csum = ext->csum; rp->csum = ext->csum;
} else } else
@ -3114,7 +3113,7 @@ nextitem:
rp2->csum_free = false; rp2->csum_free = false;
if (last_rp->csum) { if (last_rp->csum) {
uint32_t sectors = (last_rp->to_read + rp->to_read) / fcb->Vcb->superblock.sector_size; uint32_t sectors = (last_rp->to_read + rp->to_read) >> fcb->Vcb->sector_shift;
rp2->csum = ExAllocatePoolWithTag(pool_type, sectors * fcb->Vcb->csum_size, ALLOC_TAG); rp2->csum = ExAllocatePoolWithTag(pool_type, sectors * fcb->Vcb->csum_size, ALLOC_TAG);
if (!rp2->csum) { if (!rp2->csum) {
@ -3124,9 +3123,9 @@ nextitem:
goto exit; goto exit;
} }
RtlCopyMemory(rp2->csum, last_rp->csum, last_rp->to_read * fcb->Vcb->csum_size / fcb->Vcb->superblock.sector_size); RtlCopyMemory(rp2->csum, last_rp->csum, (last_rp->to_read * fcb->Vcb->csum_size) >> fcb->Vcb->sector_shift);
RtlCopyMemory((uint8_t*)rp2->csum + (last_rp->to_read * fcb->Vcb->csum_size / fcb->Vcb->superblock.sector_size), rp->csum, RtlCopyMemory((uint8_t*)rp2->csum + ((last_rp->to_read * fcb->Vcb->csum_size) >> fcb->Vcb->sector_shift), rp->csum,
rp->to_read * fcb->Vcb->csum_size / fcb->Vcb->superblock.sector_size); (rp->to_read * fcb->Vcb->csum_size) >> fcb->Vcb->sector_shift);
rp2->csum_free = true; rp2->csum_free = true;
} else } else
@ -3189,7 +3188,7 @@ nextitem:
read_part* rp = CONTAINING_RECORD(le, read_part, list_entry); read_part* rp = CONTAINING_RECORD(le, read_part, list_entry);
Status = read_data(fcb->Vcb, rp->addr, rp->to_read, rp->csum, false, rp->buf, rp->c, NULL, Irp, 0, rp->mdl, Status = read_data(fcb->Vcb, rp->addr, rp->to_read, rp->csum, false, rp->buf, rp->c, NULL, Irp, 0, rp->mdl,
fcb && fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE ? HighPagePriority : NormalPagePriority); fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE ? HighPagePriority : NormalPagePriority);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("read_data returned %08lx\n", Status); ERR("read_data returned %08lx\n", Status);
goto exit; goto exit;
@ -3395,26 +3394,53 @@ NTSTATUS do_read(PIRP Irp, bool wait, ULONG* bytes_read) {
TRACE("FileObject %p fcb %p FileSize = %I64x st_size = %I64x (%p)\n", FileObject, fcb, fcb->Header.FileSize.QuadPart, fcb->inode_item.st_size, &fcb->inode_item.st_size); TRACE("FileObject %p fcb %p FileSize = %I64x st_size = %I64x (%p)\n", FileObject, fcb, fcb->Header.FileSize.QuadPart, fcb->inode_item.st_size, &fcb->inode_item.st_size);
if (Irp->Flags & IRP_NOCACHE || !(IrpSp->MinorFunction & IRP_MN_MDL)) { if (!(Irp->Flags & IRP_NOCACHE) && IrpSp->MinorFunction & IRP_MN_MDL) {
data = map_user_buffer(Irp, fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE ? HighPagePriority : NormalPagePriority); NTSTATUS Status = STATUS_SUCCESS;
if (Irp->MdlAddress && !data) { _SEH2_TRY {
ERR("MmGetSystemAddressForMdlSafe returned NULL\n"); if (!FileObject->PrivateCacheMap) {
return STATUS_INSUFFICIENT_RESOURCES; CC_FILE_SIZES ccfs;
}
if (start >= (uint64_t)fcb->Header.ValidDataLength.QuadPart) { ccfs.AllocationSize = fcb->Header.AllocationSize;
length = (ULONG)min(length, min(start + length, (uint64_t)fcb->Header.FileSize.QuadPart) - fcb->Header.ValidDataLength.QuadPart); ccfs.FileSize = fcb->Header.FileSize;
RtlZeroMemory(data, length); ccfs.ValidDataLength = fcb->Header.ValidDataLength;
Irp->IoStatus.Information = *bytes_read = length;
return STATUS_SUCCESS;
}
if (length + start > (uint64_t)fcb->Header.ValidDataLength.QuadPart) { init_file_cache(FileObject, &ccfs);
addon = (ULONG)(min(start + length, (uint64_t)fcb->Header.FileSize.QuadPart) - fcb->Header.ValidDataLength.QuadPart); }
RtlZeroMemory(data + (fcb->Header.ValidDataLength.QuadPart - start), addon);
length = (ULONG)(fcb->Header.ValidDataLength.QuadPart - start); CcMdlRead(FileObject, &IrpSp->Parameters.Read.ByteOffset, length, &Irp->MdlAddress, &Irp->IoStatus);
} } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
Status = _SEH2_GetExceptionCode();
} _SEH2_END;
if (NT_SUCCESS(Status)) {
Status = Irp->IoStatus.Status;
Irp->IoStatus.Information += addon;
*bytes_read = (ULONG)Irp->IoStatus.Information;
} else
ERR("EXCEPTION - %08lx\n", Status);
return Status;
}
data = map_user_buffer(Irp, fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE ? HighPagePriority : NormalPagePriority);
if (Irp->MdlAddress && !data) {
ERR("MmGetSystemAddressForMdlSafe returned NULL\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
if (start >= (uint64_t)fcb->Header.ValidDataLength.QuadPart) {
length = (ULONG)min(length, min(start + length, (uint64_t)fcb->Header.FileSize.QuadPart) - fcb->Header.ValidDataLength.QuadPart);
RtlZeroMemory(data, length);
Irp->IoStatus.Information = *bytes_read = length;
return STATUS_SUCCESS;
}
if (length + start > (uint64_t)fcb->Header.ValidDataLength.QuadPart) {
addon = (ULONG)(min(start + length, (uint64_t)fcb->Header.FileSize.QuadPart) - fcb->Header.ValidDataLength.QuadPart);
RtlZeroMemory(data + (fcb->Header.ValidDataLength.QuadPart - start), addon);
length = (ULONG)(fcb->Header.ValidDataLength.QuadPart - start);
} }
if (!(Irp->Flags & IRP_NOCACHE)) { if (!(Irp->Flags & IRP_NOCACHE)) {
@ -3431,31 +3457,27 @@ NTSTATUS do_read(PIRP Irp, bool wait, ULONG* bytes_read) {
init_file_cache(FileObject, &ccfs); init_file_cache(FileObject, &ccfs);
} }
if (IrpSp->MinorFunction & IRP_MN_MDL) { if (fCcCopyReadEx) {
CcMdlRead(FileObject,&IrpSp->Parameters.Read.ByteOffset, length, &Irp->MdlAddress, &Irp->IoStatus); TRACE("CcCopyReadEx(%p, %I64x, %lx, %u, %p, %p, %p)\n", FileObject, IrpSp->Parameters.Read.ByteOffset.QuadPart,
} else { length, wait, data, &Irp->IoStatus, Irp->Tail.Overlay.Thread);
if (fCcCopyReadEx) { TRACE("sizes = %I64x, %I64x, %I64x\n", fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
TRACE("CcCopyReadEx(%p, %I64x, %lx, %u, %p, %p, %p)\n", FileObject, IrpSp->Parameters.Read.ByteOffset.QuadPart, if (!fCcCopyReadEx(FileObject, &IrpSp->Parameters.Read.ByteOffset, length, wait, data, &Irp->IoStatus, Irp->Tail.Overlay.Thread)) {
length, wait, data, &Irp->IoStatus, Irp->Tail.Overlay.Thread); TRACE("CcCopyReadEx could not wait\n");
TRACE("sizes = %I64x, %I64x, %I64x\n", fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
if (!fCcCopyReadEx(FileObject, &IrpSp->Parameters.Read.ByteOffset, length, wait, data, &Irp->IoStatus, Irp->Tail.Overlay.Thread)) {
TRACE("CcCopyReadEx could not wait\n");
IoMarkIrpPending(Irp); IoMarkIrpPending(Irp);
return STATUS_PENDING; return STATUS_PENDING;
}
TRACE("CcCopyReadEx finished\n");
} else {
TRACE("CcCopyRead(%p, %I64x, %lx, %u, %p, %p)\n", FileObject, IrpSp->Parameters.Read.ByteOffset.QuadPart, length, wait, data, &Irp->IoStatus);
TRACE("sizes = %I64x, %I64x, %I64x\n", fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
if (!CcCopyRead(FileObject, &IrpSp->Parameters.Read.ByteOffset, length, wait, data, &Irp->IoStatus)) {
TRACE("CcCopyRead could not wait\n");
IoMarkIrpPending(Irp);
return STATUS_PENDING;
}
TRACE("CcCopyRead finished\n");
} }
TRACE("CcCopyReadEx finished\n");
} else {
TRACE("CcCopyRead(%p, %I64x, %lx, %u, %p, %p)\n", FileObject, IrpSp->Parameters.Read.ByteOffset.QuadPart, length, wait, data, &Irp->IoStatus);
TRACE("sizes = %I64x, %I64x, %I64x\n", fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
if (!CcCopyRead(FileObject, &IrpSp->Parameters.Read.ByteOffset, length, wait, data, &Irp->IoStatus)) {
TRACE("CcCopyRead could not wait\n");
IoMarkIrpPending(Irp);
return STATUS_PENDING;
}
TRACE("CcCopyRead finished\n");
} }
} _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
Status = _SEH2_GetExceptionCode(); Status = _SEH2_GetExceptionCode();

View file

@ -19,6 +19,11 @@
extern tFsRtlValidateReparsePointBuffer fFsRtlValidateReparsePointBuffer; extern tFsRtlValidateReparsePointBuffer fFsRtlValidateReparsePointBuffer;
typedef struct {
uint32_t unknown;
char name[1];
} REPARSE_DATA_BUFFER_LX_SYMLINK;
NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, void* buffer, DWORD buflen, ULONG_PTR* retlen) { NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, void* buffer, DWORD buflen, ULONG_PTR* retlen) {
USHORT subnamelen, printnamelen, i; USHORT subnamelen, printnamelen, i;
ULONG stringlen; ULONG stringlen;
@ -171,17 +176,18 @@ end:
return Status; return Status;
} }
static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, fcb* fcb, 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, LIST_ENTRY* rollback) {
NTSTATUS Status; NTSTATUS Status;
ULONG minlen;
ULONG tlength; ULONG tlength;
UNICODE_STRING subname;
ANSI_STRING target; ANSI_STRING target;
bool target_alloc = false;
LARGE_INTEGER offset, time; LARGE_INTEGER offset, time;
BTRFS_TIME now; BTRFS_TIME now;
USHORT i;
if (write) { if (rdb->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
UNICODE_STRING subname;
ULONG minlen, len;
minlen = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + sizeof(WCHAR); minlen = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + sizeof(WCHAR);
if (buflen < minlen) { if (buflen < minlen) {
WARN("buffer was less than minimum length (%lu < %lu)\n", buflen, minlen); WARN("buffer was less than minimum length (%lu < %lu)\n", buflen, minlen);
@ -197,54 +203,81 @@ static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, fcb* fcb, ccb* ccb, REP
subname.MaximumLength = subname.Length = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength; subname.MaximumLength = subname.Length = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength;
TRACE("substitute name = %.*S\n", (int)(subname.Length / sizeof(WCHAR)), subname.Buffer); TRACE("substitute name = %.*S\n", (int)(subname.Length / sizeof(WCHAR)), subname.Buffer);
}
fcb->type = BTRFS_TYPE_SYMLINK; Status = utf16_to_utf8(NULL, 0, &len, subname.Buffer, subname.Length);
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 && fileref->dc)
fileref->dc->type = fcb->type;
if (write) {
Status = truncate_file(fcb, 0, Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("truncate_file returned %08lx\n", Status);
return Status;
}
Status = utf16_to_utf8(NULL, 0, (PULONG)&target.Length, subname.Buffer, subname.Length);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("utf16_to_utf8 1 failed with error %08lx\n", Status); ERR("utf16_to_utf8 1 failed with error %08lx\n", Status);
return Status; return Status;
} }
target.MaximumLength = target.Length; target.MaximumLength = target.Length = (USHORT)len;
target.Buffer = ExAllocatePoolWithTag(PagedPool, target.MaximumLength, ALLOC_TAG); target.Buffer = ExAllocatePoolWithTag(PagedPool, target.MaximumLength, ALLOC_TAG);
if (!target.Buffer) { if (!target.Buffer) {
ERR("out of memory\n"); ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
Status = utf16_to_utf8(target.Buffer, target.Length, (PULONG)&target.Length, subname.Buffer, subname.Length); target_alloc = true;
Status = utf16_to_utf8(target.Buffer, target.Length, &len, subname.Buffer, subname.Length);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("utf16_to_utf8 2 failed with error %08lx\n", Status); ERR("utf16_to_utf8 2 failed with error %08lx\n", Status);
ExFreePool(target.Buffer); ExFreePool(target.Buffer);
return Status; return Status;
} }
for (i = 0; i < target.MaximumLength; i++) { for (USHORT i = 0; i < target.Length; i++) {
if (target.Buffer[i] == '\\') if (target.Buffer[i] == '\\')
target.Buffer[i] = '/'; target.Buffer[i] = '/';
} }
} else if (rdb->ReparseTag == IO_REPARSE_TAG_LX_SYMLINK) {
REPARSE_DATA_BUFFER_LX_SYMLINK* buf;
offset.QuadPart = 0; if (buflen < offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + rdb->ReparseDataLength) {
tlength = target.Length; WARN("buffer was less than expected length (%lu < %u)\n", buflen,
Status = write_file2(fcb->Vcb, Irp, offset, target.Buffer, &tlength, false, true, offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + rdb->ReparseDataLength);
true, false, false, rollback); return STATUS_INVALID_PARAMETER;
}
buf = (REPARSE_DATA_BUFFER_LX_SYMLINK*)rdb->GenericReparseBuffer.DataBuffer;
if (buflen < offsetof(REPARSE_DATA_BUFFER_LX_SYMLINK, name)) {
WARN("buffer was less than minimum length (%u < %u)\n", rdb->ReparseDataLength, offsetof(REPARSE_DATA_BUFFER_LX_SYMLINK, name));
return STATUS_INVALID_PARAMETER;
}
target.Buffer = buf->name;
target.Length = target.MaximumLength = rdb->ReparseDataLength - offsetof(REPARSE_DATA_BUFFER_LX_SYMLINK, name);
} else {
ERR("unexpected reparse tag %08lx\n", rdb->ReparseTag);
return STATUS_INTERNAL_ERROR;
}
fcb->type = BTRFS_TYPE_SYMLINK;
fcb->inode_item.st_mode &= ~__S_IFMT;
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 && fileref->dc)
fileref->dc->type = fcb->type;
Status = truncate_file(fcb, 0, Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("truncate_file returned %08lx\n", Status);
if (target_alloc)
ExFreePool(target.Buffer);
return Status;
}
offset.QuadPart = 0;
tlength = target.Length;
Status = write_file2(fcb->Vcb, Irp, offset, target.Buffer, &tlength, false, true,
true, false, false, rollback);
if (target_alloc)
ExFreePool(target.Buffer); ExFreePool(target.Buffer);
} else
Status = STATUS_SUCCESS;
KeQuerySystemTime(&time); KeQuerySystemTime(&time);
win_time_to_unix(time, &now); win_time_to_unix(time, &now);
@ -298,7 +331,7 @@ NTSTATUS set_reparse_point2(fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG buflen, cc
if (fcb->type == BTRFS_TYPE_FILE && if (fcb->type == BTRFS_TYPE_FILE &&
((tag == IO_REPARSE_TAG_SYMLINK && rdb->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) || tag == IO_REPARSE_TAG_LX_SYMLINK)) { ((tag == IO_REPARSE_TAG_SYMLINK && rdb->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) || tag == IO_REPARSE_TAG_LX_SYMLINK)) {
Status = set_symlink(Irp, fileref, fcb, ccb, rdb, buflen, tag == IO_REPARSE_TAG_SYMLINK, rollback); Status = set_symlink(Irp, fileref, fcb, ccb, rdb, buflen, rollback);
fcb->atts |= FILE_ATTRIBUTE_REPARSE_POINT; fcb->atts |= FILE_ATTRIBUTE_REPARSE_POINT;
} else { } else {
LARGE_INTEGER offset, time; LARGE_INTEGER offset, time;

View file

@ -687,7 +687,7 @@ static NTSTATUS scrub_extent_dup(device_extension* Vcb, chunk* c, uint64_t offse
log_device_error(Vcb, c->devices[i], BTRFS_DEV_STAT_CORRUPTION_ERRORS); log_device_error(Vcb, c->devices[i], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
} }
} else { } else {
Status = check_csum(Vcb, context->stripes[i].buf, context->stripes[i].length / Vcb->superblock.sector_size, csum); Status = check_csum(Vcb, context->stripes[i].buf, context->stripes[i].length >> Vcb->sector_shift, csum);
if (Status == STATUS_CRC_ERROR) { if (Status == STATUS_CRC_ERROR) {
context->stripes[i].csum_error = true; context->stripes[i].csum_error = true;
csum_error = true; csum_error = true;
@ -741,17 +741,17 @@ static NTSTATUS scrub_extent_dup(device_extension* Vcb, chunk* c, uint64_t offse
for (i = 0; i < c->chunk_item->num_stripes; i++) { for (i = 0; i < c->chunk_item->num_stripes; i++) {
if (context->stripes[i].csum_error) { if (context->stripes[i].csum_error) {
if (csum) { if (csum) {
context->stripes[i].bad_csums = ExAllocatePoolWithTag(PagedPool, context->stripes[i].length * Vcb->csum_size / Vcb->superblock.sector_size, ALLOC_TAG); context->stripes[i].bad_csums = ExAllocatePoolWithTag(PagedPool, (context->stripes[i].length * Vcb->csum_size) >> Vcb->sector_shift, ALLOC_TAG);
if (!context->stripes[i].bad_csums) { if (!context->stripes[i].bad_csums) {
ERR("out of memory\n"); ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
do_calc_job(Vcb, context->stripes[i].buf, context->stripes[i].length / Vcb->superblock.sector_size, context->stripes[i].bad_csums); do_calc_job(Vcb, context->stripes[i].buf, context->stripes[i].length >> Vcb->sector_shift, context->stripes[i].bad_csums);
} else { } else {
ULONG j; ULONG j;
context->stripes[i].bad_csums = ExAllocatePoolWithTag(PagedPool, context->stripes[i].length * Vcb->csum_size / Vcb->superblock.node_size, ALLOC_TAG); context->stripes[i].bad_csums = ExAllocatePoolWithTag(PagedPool, (context->stripes[i].length * Vcb->csum_size) >> Vcb->sector_shift, ALLOC_TAG);
if (!context->stripes[i].bad_csums) { if (!context->stripes[i].bad_csums) {
ERR("out of memory\n"); ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
@ -784,9 +784,9 @@ static NTSTATUS scrub_extent_dup(device_extension* Vcb, chunk* c, uint64_t offse
ULONG j; ULONG j;
if (csum) { if (csum) {
for (j = 0; j < context->stripes[i].length / Vcb->superblock.sector_size; j++) { for (j = 0; j < context->stripes[i].length >> Vcb->sector_shift; j++) {
if (RtlCompareMemory((uint8_t*)context->stripes[i].bad_csums + (j * Vcb->csum_size), (uint8_t*)csum + (j + Vcb->csum_size), Vcb->csum_size) != Vcb->csum_size) { if (RtlCompareMemory((uint8_t*)context->stripes[i].bad_csums + (j * Vcb->csum_size), (uint8_t*)csum + (j + Vcb->csum_size), Vcb->csum_size) != Vcb->csum_size) {
uint64_t addr = offset + UInt32x32To64(j, Vcb->superblock.sector_size); uint64_t addr = offset + ((uint64_t)j << Vcb->sector_shift);
log_error(Vcb, addr, c->devices[i]->devitem.dev_id, false, true, false); log_error(Vcb, addr, c->devices[i]->devitem.dev_id, false, true, false);
log_device_error(Vcb, c->devices[i], BTRFS_DEV_STAT_CORRUPTION_ERRORS); log_device_error(Vcb, c->devices[i], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
@ -827,14 +827,12 @@ static NTSTATUS scrub_extent_dup(device_extension* Vcb, chunk* c, uint64_t offse
// if csum errors on all stripes, check sector by sector // if csum errors on all stripes, check sector by sector
for (i = 0; i < c->chunk_item->num_stripes; i++) { for (i = 0; i < c->chunk_item->num_stripes; i++) {
ULONG j;
if (c->devices[i]->devobj) { if (c->devices[i]->devobj) {
if (csum) { if (csum) {
for (j = 0; j < context->stripes[i].length / Vcb->superblock.sector_size; j++) { for (ULONG j = 0; j < context->stripes[i].length >> Vcb->sector_shift; j++) {
if (RtlCompareMemory((uint8_t*)context->stripes[i].bad_csums + (j * Vcb->csum_size), (uint8_t*)csum + (j * Vcb->csum_size), Vcb->csum_size) != Vcb->csum_size) { if (RtlCompareMemory((uint8_t*)context->stripes[i].bad_csums + (j * Vcb->csum_size), (uint8_t*)csum + (j * Vcb->csum_size), Vcb->csum_size) != Vcb->csum_size) {
ULONG k; ULONG k;
uint64_t addr = offset + UInt32x32To64(j, Vcb->superblock.sector_size); uint64_t addr = offset + ((uint64_t)j << Vcb->sector_shift);
bool recovered = false; bool recovered = false;
for (k = 0; k < c->chunk_item->num_stripes; k++) { for (k = 0; k < c->chunk_item->num_stripes; k++) {
@ -844,8 +842,8 @@ static NTSTATUS scrub_extent_dup(device_extension* Vcb, chunk* c, uint64_t offse
log_error(Vcb, addr, c->devices[i]->devitem.dev_id, false, true, false); log_error(Vcb, addr, c->devices[i]->devitem.dev_id, false, true, false);
log_device_error(Vcb, c->devices[i], BTRFS_DEV_STAT_CORRUPTION_ERRORS); log_device_error(Vcb, c->devices[i], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
RtlCopyMemory(context->stripes[i].buf + (j * Vcb->superblock.sector_size), RtlCopyMemory(context->stripes[i].buf + (j << Vcb->sector_shift),
context->stripes[k].buf + (j * Vcb->superblock.sector_size), Vcb->superblock.sector_size); context->stripes[k].buf + (j << Vcb->sector_shift), Vcb->superblock.sector_size);
recovered = true; recovered = true;
break; break;
@ -859,7 +857,7 @@ static NTSTATUS scrub_extent_dup(device_extension* Vcb, chunk* c, uint64_t offse
} }
} }
} else { } else {
for (j = 0; j < context->stripes[i].length / Vcb->superblock.node_size; j++) { for (ULONG j = 0; j < context->stripes[i].length / Vcb->superblock.node_size; j++) {
tree_header* th = (tree_header*)&context->stripes[i].buf[j * Vcb->superblock.node_size]; tree_header* th = (tree_header*)&context->stripes[i].buf[j * Vcb->superblock.node_size];
uint64_t addr = offset + UInt32x32To64(j, Vcb->superblock.node_size); uint64_t addr = offset + UInt32x32To64(j, Vcb->superblock.node_size);
@ -915,9 +913,9 @@ static NTSTATUS scrub_extent_dup(device_extension* Vcb, chunk* c, uint64_t offse
ULONG j; ULONG j;
if (csum) { if (csum) {
for (j = 0; j < context->stripes[i].length / Vcb->superblock.sector_size; j++) { for (j = 0; j < context->stripes[i].length >> Vcb->sector_shift; j++) {
if (RtlCompareMemory((uint8_t*)context->stripes[i].bad_csums + (j * Vcb->csum_size), (uint8_t*)csum + (j + Vcb->csum_size), Vcb->csum_size) != Vcb->csum_size) { if (RtlCompareMemory((uint8_t*)context->stripes[i].bad_csums + (j * Vcb->csum_size), (uint8_t*)csum + (j + Vcb->csum_size), Vcb->csum_size) != Vcb->csum_size) {
uint64_t addr = offset + UInt32x32To64(j, Vcb->superblock.sector_size); uint64_t addr = offset + ((uint64_t)j << Vcb->sector_shift);
log_error(Vcb, addr, c->devices[i]->devitem.dev_id, false, false, false); log_error(Vcb, addr, c->devices[i]->devitem.dev_id, false, false, false);
} }
@ -962,7 +960,7 @@ static NTSTATUS scrub_extent_raid0(device_extension* Vcb, chunk* c, uint64_t off
if (csum) { if (csum) {
for (j = 0; j < readlen; j += Vcb->superblock.sector_size) { for (j = 0; j < readlen; j += Vcb->superblock.sector_size) {
if (!check_sector_csum(Vcb, context->stripes[stripe].buf + stripeoff[stripe], (uint8_t*)csum + (pos * Vcb->csum_size / Vcb->superblock.sector_size))) { if (!check_sector_csum(Vcb, context->stripes[stripe].buf + stripeoff[stripe], (uint8_t*)csum + ((pos * Vcb->csum_size) >> Vcb->sector_shift))) {
uint64_t addr = offset + pos; uint64_t addr = offset + pos;
log_error(Vcb, addr, c->devices[stripe]->devitem.dev_id, false, false, false); log_error(Vcb, addr, c->devices[stripe]->devitem.dev_id, false, false, false);
@ -1039,7 +1037,7 @@ static NTSTATUS scrub_extent_raid10(device_extension* Vcb, chunk* c, uint64_t of
} else { } else {
for (j = 0; j < readlen; j += Vcb->superblock.sector_size) { for (j = 0; j < readlen; j += Vcb->superblock.sector_size) {
if (!check_sector_csum(Vcb, context->stripes[(stripe * sub_stripes) + k].buf + stripeoff[stripe] + j, if (!check_sector_csum(Vcb, context->stripes[(stripe * sub_stripes) + k].buf + stripeoff[stripe] + j,
(uint8_t*)csum + ((pos + j) * Vcb->csum_size / Vcb->superblock.sector_size))) { (uint8_t*)csum + (((pos + j) * Vcb->csum_size) >> Vcb->sector_shift))) {
csum_error = true; csum_error = true;
context->stripes[(stripe * sub_stripes) + k].csum_error = true; context->stripes[(stripe * sub_stripes) + k].csum_error = true;
log_device_error(Vcb, c->devices[(stripe * sub_stripes) + k], BTRFS_DEV_STAT_CORRUPTION_ERRORS); log_device_error(Vcb, c->devices[(stripe * sub_stripes) + k], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
@ -1204,7 +1202,7 @@ static NTSTATUS scrub_extent_raid10(device_extension* Vcb, chunk* c, uint64_t of
if (csum) { if (csum) {
for (k = 0; k < sub_stripes; k++) { for (k = 0; k < sub_stripes; k++) {
if (c->devices[j + k]->devobj) { if (c->devices[j + k]->devobj) {
context->stripes[j + k].bad_csums = ExAllocatePoolWithTag(PagedPool, context->stripes[j + k].length * Vcb->csum_size / Vcb->superblock.sector_size, context->stripes[j + k].bad_csums = ExAllocatePoolWithTag(PagedPool, (context->stripes[j + k].length * Vcb->csum_size) >> Vcb->sector_shift,
ALLOC_TAG); ALLOC_TAG);
if (!context->stripes[j + k].bad_csums) { if (!context->stripes[j + k].bad_csums) {
ERR("out of memory\n"); ERR("out of memory\n");
@ -1212,7 +1210,7 @@ static NTSTATUS scrub_extent_raid10(device_extension* Vcb, chunk* c, uint64_t of
goto end; goto end;
} }
do_calc_job(Vcb, context->stripes[j + k].buf, context->stripes[j + k].length / Vcb->superblock.sector_size, context->stripes[j + k].bad_csums); do_calc_job(Vcb, context->stripes[j + k].buf, context->stripes[j + k].length >> Vcb->sector_shift, context->stripes[j + k].bad_csums);
} }
} }
} else { } else {
@ -1259,8 +1257,8 @@ static NTSTATUS scrub_extent_raid10(device_extension* Vcb, chunk* c, uint64_t of
goodstripe = 0xffffffff; goodstripe = 0xffffffff;
for (k = 0; k < sub_stripes; k++) { for (k = 0; k < sub_stripes; k++) {
if (c->devices[j + k]->devobj) { if (c->devices[j + k]->devobj) {
if (RtlCompareMemory((uint8_t*)context->stripes[j + k].bad_csums + (so * Vcb->csum_size / Vcb->superblock.sector_size), if (RtlCompareMemory((uint8_t*)context->stripes[j + k].bad_csums + ((so * Vcb->csum_size) >> Vcb->sector_shift),
(uint8_t*)csum + (pos * Vcb->csum_size / Vcb->superblock.sector_size), (uint8_t*)csum + ((pos * Vcb->csum_size) >> Vcb->sector_shift),
Vcb->csum_size) != Vcb->csum_size) { Vcb->csum_size) != Vcb->csum_size) {
has_error = true; has_error = true;
} else } else
@ -1272,8 +1270,8 @@ static NTSTATUS scrub_extent_raid10(device_extension* Vcb, chunk* c, uint64_t of
if (goodstripe != 0xffffffff) { if (goodstripe != 0xffffffff) {
for (k = 0; k < sub_stripes; k++) { for (k = 0; k < sub_stripes; k++) {
if (c->devices[j + k]->devobj && if (c->devices[j + k]->devobj &&
RtlCompareMemory((uint8_t*)context->stripes[j + k].bad_csums + (so * Vcb->csum_size / Vcb->superblock.sector_size), RtlCompareMemory((uint8_t*)context->stripes[j + k].bad_csums + ((so * Vcb->csum_size) >> Vcb->sector_shift),
(uint8_t*)csum + (pos * Vcb->csum_size / Vcb->superblock.sector_size), (uint8_t*)csum + ((pos * Vcb->csum_size) >> Vcb->sector_shift),
Vcb->csum_size) != Vcb->csum_size) { Vcb->csum_size) != Vcb->csum_size) {
uint64_t addr = offset + pos; uint64_t addr = offset + pos;
@ -1644,13 +1642,13 @@ static NTSTATUS scrub_data_extent(device_extension* Vcb, chunk* c, uint64_t offs
do { do {
ULONG rl; ULONG rl;
if (runlength * Vcb->superblock.sector_size > SCRUB_UNIT) if (runlength << Vcb->sector_shift > SCRUB_UNIT)
rl = SCRUB_UNIT / Vcb->superblock.sector_size; rl = SCRUB_UNIT >> Vcb->sector_shift;
else else
rl = runlength; rl = runlength;
Status = scrub_extent(Vcb, c, type, offset + UInt32x32To64(index, Vcb->superblock.sector_size), Status = scrub_extent(Vcb, c, type, offset + ((uint64_t)index << Vcb->sector_shift),
rl * Vcb->superblock.sector_size, (uint8_t*)csum + (index * Vcb->csum_size)); rl << Vcb->sector_shift, (uint8_t*)csum + (index * Vcb->csum_size));
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("scrub_data_extent_dup returned %08lx\n", Status); ERR("scrub_data_extent_dup returned %08lx\n", Status);
return Status; return Status;
@ -1707,7 +1705,7 @@ static NTSTATUS __stdcall scrub_read_completion_raid56(PDEVICE_OBJECT DeviceObje
static void scrub_raid5_stripe(device_extension* Vcb, chunk* c, scrub_context_raid56* context, uint64_t stripe_start, uint64_t bit_start, static void scrub_raid5_stripe(device_extension* Vcb, chunk* c, scrub_context_raid56* context, uint64_t stripe_start, uint64_t bit_start,
uint64_t num, uint16_t missing_devices) { uint64_t num, uint16_t missing_devices) {
ULONG sectors_per_stripe = (ULONG)(c->chunk_item->stripe_length / Vcb->superblock.sector_size), i, off; ULONG sectors_per_stripe = (ULONG)(c->chunk_item->stripe_length >> Vcb->sector_shift), off;
uint16_t stripe, parity = (bit_start + num + c->chunk_item->num_stripes - 1) % c->chunk_item->num_stripes; uint16_t stripe, parity = (bit_start + num + c->chunk_item->num_stripes - 1) % c->chunk_item->num_stripes;
uint64_t stripeoff; uint64_t stripeoff;
@ -1721,32 +1719,32 @@ static void scrub_raid5_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
while (stripe != parity) { while (stripe != parity) {
RtlClearAllBits(&context->stripes[stripe].error); RtlClearAllBits(&context->stripes[stripe].error);
for (i = 0; i < sectors_per_stripe; i++) { for (ULONG i = 0; i < sectors_per_stripe; i++) {
if (c->devices[stripe]->devobj && RtlCheckBit(&context->alloc, off)) { if (c->devices[stripe]->devobj && RtlCheckBit(&context->alloc, off)) {
if (RtlCheckBit(&context->is_tree, off)) { if (RtlCheckBit(&context->is_tree, off)) {
tree_header* th = (tree_header*)&context->stripes[stripe].buf[stripeoff * Vcb->superblock.sector_size]; tree_header* th = (tree_header*)&context->stripes[stripe].buf[stripeoff << Vcb->sector_shift];
uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 1) * c->chunk_item->stripe_length) + (off * Vcb->superblock.sector_size); uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 1) * c->chunk_item->stripe_length) + (off << Vcb->sector_shift);
if (!check_tree_checksum(Vcb, th) || th->address != addr) { if (!check_tree_checksum(Vcb, th) || th->address != addr) {
RtlSetBits(&context->stripes[stripe].error, i, Vcb->superblock.node_size / Vcb->superblock.sector_size); RtlSetBits(&context->stripes[stripe].error, i, Vcb->superblock.node_size >> Vcb->sector_shift);
log_device_error(Vcb, c->devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS); log_device_error(Vcb, c->devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
if (missing_devices > 0) if (missing_devices > 0)
log_error(Vcb, addr, c->devices[stripe]->devitem.dev_id, true, false, false); log_error(Vcb, addr, c->devices[stripe]->devitem.dev_id, true, false, false);
} }
off += Vcb->superblock.node_size / Vcb->superblock.sector_size; off += Vcb->superblock.node_size >> Vcb->sector_shift;
stripeoff += Vcb->superblock.node_size / Vcb->superblock.sector_size; stripeoff += Vcb->superblock.node_size >> Vcb->sector_shift;
i += (Vcb->superblock.node_size / Vcb->superblock.sector_size) - 1; i += (Vcb->superblock.node_size >> Vcb->sector_shift) - 1;
continue; continue;
} else if (RtlCheckBit(&context->has_csum, off)) { } else if (RtlCheckBit(&context->has_csum, off)) {
if (!check_sector_csum(Vcb, context->stripes[stripe].buf + (stripeoff * Vcb->superblock.sector_size), (uint8_t*)context->csum + (Vcb->csum_size * off))) { if (!check_sector_csum(Vcb, context->stripes[stripe].buf + (stripeoff << Vcb->sector_shift), (uint8_t*)context->csum + (Vcb->csum_size * off))) {
RtlSetBit(&context->stripes[stripe].error, i); RtlSetBit(&context->stripes[stripe].error, i);
log_device_error(Vcb, c->devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS); log_device_error(Vcb, c->devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
if (missing_devices > 0) { if (missing_devices > 0) {
uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 1) * c->chunk_item->stripe_length) + (off * Vcb->superblock.sector_size); uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 1) * c->chunk_item->stripe_length) + (off << Vcb->sector_shift);
log_error(Vcb, addr, c->devices[stripe]->devitem.dev_id, false, false, false); log_error(Vcb, addr, c->devices[stripe]->devitem.dev_id, false, false, false);
} }
@ -1770,10 +1768,10 @@ static void scrub_raid5_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
if (missing_devices == 0) { if (missing_devices == 0) {
RtlClearAllBits(&context->stripes[parity].error); RtlClearAllBits(&context->stripes[parity].error);
for (i = 0; i < sectors_per_stripe; i++) { for (ULONG i = 0; i < sectors_per_stripe; i++) {
ULONG o, j; ULONG o, j;
o = i * Vcb->superblock.sector_size; o = i << Vcb->sector_shift;
for (j = 0; j < Vcb->superblock.sector_size; j++) { // FIXME - use SSE for (j = 0; j < Vcb->superblock.sector_size; j++) { // FIXME - use SSE
if (context->parity_scratch[o] != 0) { if (context->parity_scratch[o] != 0) {
RtlSetBit(&context->stripes[parity].error, i); RtlSetBit(&context->stripes[parity].error, i);
@ -1789,7 +1787,7 @@ static void scrub_raid5_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
if (missing_devices > 0) if (missing_devices > 0)
return; return;
for (i = 0; i < sectors_per_stripe; i++) { for (ULONG i = 0; i < sectors_per_stripe; i++) {
ULONG num_errors = 0, bad_off; ULONG num_errors = 0, bad_off;
uint64_t bad_stripe; uint64_t bad_stripe;
bool alloc = false; bool alloc = false;
@ -1821,36 +1819,36 @@ static void scrub_raid5_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
if (num_errors == 0 && RtlCheckBit(&context->stripes[parity].error, i)) { // parity error if (num_errors == 0 && RtlCheckBit(&context->stripes[parity].error, i)) { // parity error
uint64_t addr; uint64_t addr;
do_xor(&context->stripes[parity].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], do_xor(&context->stripes[parity].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch[i * Vcb->superblock.sector_size], &context->parity_scratch[i << Vcb->sector_shift],
Vcb->superblock.sector_size); Vcb->superblock.sector_size);
bad_off = (ULONG)((bit_start + num - stripe_start) * sectors_per_stripe * (c->chunk_item->num_stripes - 1)) + i; bad_off = (ULONG)((bit_start + num - stripe_start) * sectors_per_stripe * (c->chunk_item->num_stripes - 1)) + i;
addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 1) * c->chunk_item->stripe_length) + (bad_off * Vcb->superblock.sector_size); addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 1) * c->chunk_item->stripe_length) + (bad_off << Vcb->sector_shift);
context->stripes[parity].rewrite = true; context->stripes[parity].rewrite = true;
log_error(Vcb, addr, c->devices[parity]->devitem.dev_id, false, true, true); log_error(Vcb, addr, c->devices[parity]->devitem.dev_id, false, true, true);
log_device_error(Vcb, c->devices[parity], BTRFS_DEV_STAT_CORRUPTION_ERRORS); log_device_error(Vcb, c->devices[parity], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
} else if (num_errors == 1) { } else if (num_errors == 1) {
uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 1) * c->chunk_item->stripe_length) + (bad_off * Vcb->superblock.sector_size); uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 1) * c->chunk_item->stripe_length) + (bad_off << Vcb->sector_shift);
if (RtlCheckBit(&context->is_tree, bad_off)) { if (RtlCheckBit(&context->is_tree, bad_off)) {
tree_header* th; tree_header* th;
do_xor(&context->parity_scratch[i * Vcb->superblock.sector_size], do_xor(&context->parity_scratch[i << Vcb->sector_shift],
&context->stripes[bad_stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], &context->stripes[bad_stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
Vcb->superblock.node_size); Vcb->superblock.node_size);
th = (tree_header*)&context->parity_scratch[i * Vcb->superblock.sector_size]; th = (tree_header*)&context->parity_scratch[i << Vcb->sector_shift];
if (check_tree_checksum(Vcb, th) && th->address == addr) { if (check_tree_checksum(Vcb, th) && th->address == addr) {
RtlCopyMemory(&context->stripes[bad_stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], RtlCopyMemory(&context->stripes[bad_stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch[i * Vcb->superblock.sector_size], Vcb->superblock.node_size); &context->parity_scratch[i << Vcb->sector_shift], Vcb->superblock.node_size);
context->stripes[bad_stripe].rewrite = true; context->stripes[bad_stripe].rewrite = true;
RtlClearBits(&context->stripes[bad_stripe].error, i + 1, (Vcb->superblock.node_size / Vcb->superblock.sector_size) - 1); RtlClearBits(&context->stripes[bad_stripe].error, i + 1, (Vcb->superblock.node_size >> Vcb->sector_shift) - 1);
log_error(Vcb, addr, c->devices[bad_stripe]->devitem.dev_id, true, true, false); log_error(Vcb, addr, c->devices[bad_stripe]->devitem.dev_id, true, true, false);
} else } else
@ -1858,15 +1856,15 @@ static void scrub_raid5_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
} else { } else {
uint8_t hash[MAX_HASH_SIZE]; uint8_t hash[MAX_HASH_SIZE];
do_xor(&context->parity_scratch[i * Vcb->superblock.sector_size], do_xor(&context->parity_scratch[i << Vcb->sector_shift],
&context->stripes[bad_stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], &context->stripes[bad_stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
Vcb->superblock.sector_size); Vcb->superblock.sector_size);
get_sector_csum(Vcb, &context->parity_scratch[i * Vcb->superblock.sector_size], hash); get_sector_csum(Vcb, &context->parity_scratch[i << Vcb->sector_shift], hash);
if (RtlCompareMemory(hash, (uint8_t*)context->csum + (Vcb->csum_size * bad_off), Vcb->csum_size) == Vcb->csum_size) { if (RtlCompareMemory(hash, (uint8_t*)context->csum + (Vcb->csum_size * bad_off), Vcb->csum_size) == Vcb->csum_size) {
RtlCopyMemory(&context->stripes[bad_stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], RtlCopyMemory(&context->stripes[bad_stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch[i * Vcb->superblock.sector_size], Vcb->superblock.sector_size); &context->parity_scratch[i << Vcb->sector_shift], Vcb->superblock.sector_size);
context->stripes[bad_stripe].rewrite = true; context->stripes[bad_stripe].rewrite = true;
@ -1881,7 +1879,7 @@ static void scrub_raid5_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
while (stripe != parity) { while (stripe != parity) {
if (RtlCheckBit(&context->alloc, off)) { if (RtlCheckBit(&context->alloc, off)) {
if (RtlCheckBit(&context->stripes[stripe].error, i)) { if (RtlCheckBit(&context->stripes[stripe].error, i)) {
uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 1) * c->chunk_item->stripe_length) + (off * Vcb->superblock.sector_size); uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 1) * c->chunk_item->stripe_length) + (off << Vcb->sector_shift);
log_error(Vcb, addr, c->devices[stripe]->devitem.dev_id, RtlCheckBit(&context->is_tree, off), false, false); log_error(Vcb, addr, c->devices[stripe]->devitem.dev_id, RtlCheckBit(&context->is_tree, off), false, false);
} }
@ -1896,7 +1894,7 @@ static void scrub_raid5_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_raid56* context, uint64_t stripe_start, uint64_t bit_start, static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_raid56* context, uint64_t stripe_start, uint64_t bit_start,
uint64_t num, uint16_t missing_devices) { uint64_t num, uint16_t missing_devices) {
ULONG sectors_per_stripe = (ULONG)(c->chunk_item->stripe_length / Vcb->superblock.sector_size), i, off; ULONG sectors_per_stripe = (ULONG)(c->chunk_item->stripe_length >> Vcb->sector_shift), off;
uint16_t stripe, parity1 = (bit_start + num + c->chunk_item->num_stripes - 2) % c->chunk_item->num_stripes; uint16_t stripe, parity1 = (bit_start + num + c->chunk_item->num_stripes - 2) % c->chunk_item->num_stripes;
uint16_t parity2 = (parity1 + 1) % c->chunk_item->num_stripes; uint16_t parity2 = (parity1 + 1) % c->chunk_item->num_stripes;
uint64_t stripeoff; uint64_t stripeoff;
@ -1914,32 +1912,32 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
while (stripe != parity1) { while (stripe != parity1) {
RtlClearAllBits(&context->stripes[stripe].error); RtlClearAllBits(&context->stripes[stripe].error);
for (i = 0; i < sectors_per_stripe; i++) { for (ULONG i = 0; i < sectors_per_stripe; i++) {
if (c->devices[stripe]->devobj && RtlCheckBit(&context->alloc, off)) { if (c->devices[stripe]->devobj && RtlCheckBit(&context->alloc, off)) {
if (RtlCheckBit(&context->is_tree, off)) { if (RtlCheckBit(&context->is_tree, off)) {
tree_header* th = (tree_header*)&context->stripes[stripe].buf[stripeoff * Vcb->superblock.sector_size]; tree_header* th = (tree_header*)&context->stripes[stripe].buf[stripeoff << Vcb->sector_shift];
uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (off * Vcb->superblock.sector_size); uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (off << Vcb->sector_shift);
if (!check_tree_checksum(Vcb, th) || th->address != addr) { if (!check_tree_checksum(Vcb, th) || th->address != addr) {
RtlSetBits(&context->stripes[stripe].error, i, Vcb->superblock.node_size / Vcb->superblock.sector_size); RtlSetBits(&context->stripes[stripe].error, i, Vcb->superblock.node_size >> Vcb->sector_shift);
log_device_error(Vcb, c->devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS); log_device_error(Vcb, c->devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
if (missing_devices == 2) if (missing_devices == 2)
log_error(Vcb, addr, c->devices[stripe]->devitem.dev_id, true, false, false); log_error(Vcb, addr, c->devices[stripe]->devitem.dev_id, true, false, false);
} }
off += Vcb->superblock.node_size / Vcb->superblock.sector_size; off += Vcb->superblock.node_size >> Vcb->sector_shift;
stripeoff += Vcb->superblock.node_size / Vcb->superblock.sector_size; stripeoff += Vcb->superblock.node_size >> Vcb->sector_shift;
i += (Vcb->superblock.node_size / Vcb->superblock.sector_size) - 1; i += (Vcb->superblock.node_size >> Vcb->sector_shift) - 1;
continue; continue;
} else if (RtlCheckBit(&context->has_csum, off)) { } else if (RtlCheckBit(&context->has_csum, off)) {
uint8_t hash[MAX_HASH_SIZE]; uint8_t hash[MAX_HASH_SIZE];
get_sector_csum(Vcb, context->stripes[stripe].buf + (stripeoff * Vcb->superblock.sector_size), hash); get_sector_csum(Vcb, context->stripes[stripe].buf + (stripeoff << Vcb->sector_shift), hash);
if (RtlCompareMemory(hash, (uint8_t*)context->csum + (Vcb->csum_size * off), Vcb->csum_size) != Vcb->csum_size) { if (RtlCompareMemory(hash, (uint8_t*)context->csum + (Vcb->csum_size * off), Vcb->csum_size) != Vcb->csum_size) {
uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (off * Vcb->superblock.sector_size); uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (off << Vcb->sector_shift);
RtlSetBit(&context->stripes[stripe].error, i); RtlSetBit(&context->stripes[stripe].error, i);
log_device_error(Vcb, c->devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS); log_device_error(Vcb, c->devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
@ -1966,10 +1964,10 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
if (missing_devices == 0 || (missing_devices == 1 && !c->devices[parity2]->devobj)) { if (missing_devices == 0 || (missing_devices == 1 && !c->devices[parity2]->devobj)) {
// check parity 1 // check parity 1
for (i = 0; i < sectors_per_stripe; i++) { for (ULONG i = 0; i < sectors_per_stripe; i++) {
ULONG o, j; ULONG o, j;
o = i * Vcb->superblock.sector_size; o = i << Vcb->sector_shift;
for (j = 0; j < Vcb->superblock.sector_size; j++) { // FIXME - use SSE for (j = 0; j < Vcb->superblock.sector_size; j++) { // FIXME - use SSE
if (context->parity_scratch[o] != 0) { if (context->parity_scratch[o] != 0) {
RtlSetBit(&context->stripes[parity1].error, i); RtlSetBit(&context->stripes[parity1].error, i);
@ -1994,9 +1992,9 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
stripe = stripe == 0 ? (c->chunk_item->num_stripes - 1) : (stripe - 1); stripe = stripe == 0 ? (c->chunk_item->num_stripes - 1) : (stripe - 1);
} }
for (i = 0; i < sectors_per_stripe; i++) { for (ULONG i = 0; i < sectors_per_stripe; i++) {
if (RtlCompareMemory(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], if (RtlCompareMemory(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch2[i * Vcb->superblock.sector_size], Vcb->superblock.sector_size) != Vcb->superblock.sector_size) &context->parity_scratch2[i << Vcb->sector_shift], Vcb->superblock.sector_size) != Vcb->superblock.sector_size)
RtlSetBit(&context->stripes[parity2].error, i); RtlSetBit(&context->stripes[parity2].error, i);
} }
} }
@ -2006,7 +2004,7 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
// log and fix errors // log and fix errors
for (i = 0; i < sectors_per_stripe; i++) { for (ULONG i = 0; i < sectors_per_stripe; i++) {
ULONG num_errors = 0; ULONG num_errors = 0;
uint64_t bad_stripe1, bad_stripe2; uint64_t bad_stripe1, bad_stripe2;
ULONG bad_off1, bad_off2; ULONG bad_off1, bad_off2;
@ -2045,12 +2043,12 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
uint64_t addr; uint64_t addr;
if (RtlCheckBit(&context->stripes[parity1].error, i)) { if (RtlCheckBit(&context->stripes[parity1].error, i)) {
do_xor(&context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], do_xor(&context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch[i * Vcb->superblock.sector_size], &context->parity_scratch[i << Vcb->sector_shift],
Vcb->superblock.sector_size); Vcb->superblock.sector_size);
bad_off1 = (ULONG)((bit_start + num - stripe_start) * sectors_per_stripe * (c->chunk_item->num_stripes - 2)) + i; bad_off1 = (ULONG)((bit_start + num - stripe_start) * sectors_per_stripe * (c->chunk_item->num_stripes - 2)) + i;
addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (bad_off1 * Vcb->superblock.sector_size); addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (bad_off1 << Vcb->sector_shift);
context->stripes[parity1].rewrite = true; context->stripes[parity1].rewrite = true;
@ -2059,12 +2057,12 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
} }
if (RtlCheckBit(&context->stripes[parity2].error, i)) { if (RtlCheckBit(&context->stripes[parity2].error, i)) {
RtlCopyMemory(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], RtlCopyMemory(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch2[i * Vcb->superblock.sector_size], &context->parity_scratch2[i << Vcb->sector_shift],
Vcb->superblock.sector_size); Vcb->superblock.sector_size);
bad_off1 = (ULONG)((bit_start + num - stripe_start) * sectors_per_stripe * (c->chunk_item->num_stripes - 2)) + i; bad_off1 = (ULONG)((bit_start + num - stripe_start) * sectors_per_stripe * (c->chunk_item->num_stripes - 2)) + i;
addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (bad_off1 * Vcb->superblock.sector_size); addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (bad_off1 << Vcb->sector_shift);
context->stripes[parity2].rewrite = true; context->stripes[parity2].rewrite = true;
@ -2074,10 +2072,10 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
} else if (num_errors == 1) { } else if (num_errors == 1) {
uint32_t len; uint32_t len;
uint16_t stripe_num, bad_stripe_num; uint16_t stripe_num, bad_stripe_num;
uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (bad_off1 * Vcb->superblock.sector_size); uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (bad_off1 << Vcb->sector_shift);
uint8_t* scratch; uint8_t* scratch;
len = RtlCheckBit(&context->is_tree, bad_off1)? Vcb->superblock.node_size : Vcb->superblock.sector_size; len = RtlCheckBit(&context->is_tree, bad_off1) ? Vcb->superblock.node_size : Vcb->superblock.sector_size;
scratch = ExAllocatePoolWithTag(PagedPool, len, ALLOC_TAG); scratch = ExAllocatePoolWithTag(PagedPool, len, ALLOC_TAG);
if (!scratch) { if (!scratch) {
@ -2087,8 +2085,8 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
RtlZeroMemory(scratch, len); RtlZeroMemory(scratch, len);
do_xor(&context->parity_scratch[i * Vcb->superblock.sector_size], do_xor(&context->parity_scratch[i << Vcb->sector_shift],
&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], len); &context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)], len);
stripe = parity1 == 0 ? (c->chunk_item->num_stripes - 1) : (parity1 - 1); stripe = parity1 == 0 ? (c->chunk_item->num_stripes - 1) : (parity1 - 1);
@ -2098,7 +2096,7 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
galois_double(scratch, len); galois_double(scratch, len);
if (stripe != bad_stripe1) if (stripe != bad_stripe1)
do_xor(scratch, &context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], len); do_xor(scratch, &context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)], len);
else else
bad_stripe_num = stripe_num; bad_stripe_num = stripe_num;
@ -2106,7 +2104,7 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
stripe_num--; stripe_num--;
} }
do_xor(scratch, &context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], len); do_xor(scratch, &context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)], len);
if (bad_stripe_num != 0) if (bad_stripe_num != 0)
galois_divpower(scratch, (uint8_t)bad_stripe_num, len); galois_divpower(scratch, (uint8_t)bad_stripe_num, len);
@ -2118,7 +2116,7 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
tree_header *th1 = NULL, *th2 = NULL; tree_header *th1 = NULL, *th2 = NULL;
if (c->devices[parity1]->devobj) { if (c->devices[parity1]->devobj) {
th1 = (tree_header*)&context->parity_scratch[i * Vcb->superblock.sector_size]; th1 = (tree_header*)&context->parity_scratch[i << Vcb->sector_shift];
get_tree_checksum(Vcb, th1, hash1); get_tree_checksum(Vcb, th1, hash1);
} }
@ -2130,7 +2128,7 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
if ((c->devices[parity1]->devobj && RtlCompareMemory(hash1, th1, Vcb->csum_size) == Vcb->csum_size && th1->address == addr) || if ((c->devices[parity1]->devobj && RtlCompareMemory(hash1, th1, Vcb->csum_size) == Vcb->csum_size && th1->address == addr) ||
(c->devices[parity2]->devobj && RtlCompareMemory(hash2, th2, Vcb->csum_size) == Vcb->csum_size && th2->address == addr)) { (c->devices[parity2]->devobj && RtlCompareMemory(hash2, th2, Vcb->csum_size) == Vcb->csum_size && th2->address == addr)) {
if (!c->devices[parity1]->devobj || RtlCompareMemory(hash1, th1, Vcb->csum_size) != Vcb->csum_size || th1->address != addr) { if (!c->devices[parity1]->devobj || RtlCompareMemory(hash1, th1, Vcb->csum_size) != Vcb->csum_size || th1->address != addr) {
RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
scratch, Vcb->superblock.node_size); scratch, Vcb->superblock.node_size);
if (c->devices[parity1]->devobj) { if (c->devices[parity1]->devobj) {
@ -2138,15 +2136,15 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
stripe = (parity1 + 2) % c->chunk_item->num_stripes; stripe = (parity1 + 2) % c->chunk_item->num_stripes;
RtlCopyMemory(&context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], RtlCopyMemory(&context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], &context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
Vcb->superblock.node_size); Vcb->superblock.node_size);
stripe = (stripe + 1) % c->chunk_item->num_stripes; stripe = (stripe + 1) % c->chunk_item->num_stripes;
while (stripe != parity1) { while (stripe != parity1) {
do_xor(&context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], do_xor(&context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], &context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
Vcb->superblock.node_size); Vcb->superblock.node_size);
stripe = (stripe + 1) % c->chunk_item->num_stripes; stripe = (stripe + 1) % c->chunk_item->num_stripes;
@ -2158,26 +2156,26 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
log_device_error(Vcb, c->devices[parity1], BTRFS_DEV_STAT_CORRUPTION_ERRORS); log_device_error(Vcb, c->devices[parity1], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
} }
} else { } else {
RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch[i * Vcb->superblock.sector_size], Vcb->superblock.node_size); &context->parity_scratch[i << Vcb->sector_shift], Vcb->superblock.node_size);
if (!c->devices[parity2]->devobj || RtlCompareMemory(hash2, th2, Vcb->csum_size) != Vcb->csum_size || th2->address != addr) { if (!c->devices[parity2]->devobj || RtlCompareMemory(hash2, th2, Vcb->csum_size) != Vcb->csum_size || th2->address != addr) {
// fix parity 2 // fix parity 2
stripe = parity1 == 0 ? (c->chunk_item->num_stripes - 1) : (parity1 - 1); stripe = parity1 == 0 ? (c->chunk_item->num_stripes - 1) : (parity1 - 1);
if (c->devices[parity2]->devobj) { if (c->devices[parity2]->devobj) {
RtlCopyMemory(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], RtlCopyMemory(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], &context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
Vcb->superblock.node_size); Vcb->superblock.node_size);
stripe = stripe == 0 ? (c->chunk_item->num_stripes - 1) : (stripe - 1); stripe = stripe == 0 ? (c->chunk_item->num_stripes - 1) : (stripe - 1);
while (stripe != parity2) { while (stripe != parity2) {
galois_double(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], Vcb->superblock.node_size); galois_double(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)], Vcb->superblock.node_size);
do_xor(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], do_xor(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], &context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
Vcb->superblock.node_size); Vcb->superblock.node_size);
stripe = stripe == 0 ? (c->chunk_item->num_stripes - 1) : (stripe - 1); stripe = stripe == 0 ? (c->chunk_item->num_stripes - 1) : (stripe - 1);
} }
@ -2192,7 +2190,7 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
context->stripes[bad_stripe1].rewrite = true; context->stripes[bad_stripe1].rewrite = true;
RtlClearBits(&context->stripes[bad_stripe1].error, i + 1, (Vcb->superblock.node_size / Vcb->superblock.sector_size) - 1); RtlClearBits(&context->stripes[bad_stripe1].error, i + 1, (Vcb->superblock.node_size >> Vcb->sector_shift) - 1);
log_error(Vcb, addr, c->devices[bad_stripe1]->devitem.dev_id, true, true, false); log_error(Vcb, addr, c->devices[bad_stripe1]->devitem.dev_id, true, true, false);
} else } else
@ -2202,7 +2200,7 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
uint8_t hash2[MAX_HASH_SIZE]; uint8_t hash2[MAX_HASH_SIZE];
if (c->devices[parity1]->devobj) if (c->devices[parity1]->devobj)
get_sector_csum(Vcb, &context->parity_scratch[i * Vcb->superblock.sector_size], hash1); get_sector_csum(Vcb, &context->parity_scratch[i << Vcb->sector_shift], hash1);
if (c->devices[parity2]->devobj) if (c->devices[parity2]->devobj)
get_sector_csum(Vcb, scratch, hash2); get_sector_csum(Vcb, scratch, hash2);
@ -2210,7 +2208,7 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
if ((c->devices[parity1]->devobj && RtlCompareMemory(hash1, (uint8_t*)context->csum + (bad_off1 * Vcb->csum_size), Vcb->csum_size) == Vcb->csum_size) || if ((c->devices[parity1]->devobj && RtlCompareMemory(hash1, (uint8_t*)context->csum + (bad_off1 * Vcb->csum_size), Vcb->csum_size) == Vcb->csum_size) ||
(c->devices[parity2]->devobj && RtlCompareMemory(hash2, (uint8_t*)context->csum + (bad_off1 * Vcb->csum_size), Vcb->csum_size) == Vcb->csum_size)) { (c->devices[parity2]->devobj && RtlCompareMemory(hash2, (uint8_t*)context->csum + (bad_off1 * Vcb->csum_size), Vcb->csum_size) == Vcb->csum_size)) {
if (c->devices[parity2]->devobj && RtlCompareMemory(hash2, (uint8_t*)context->csum + (bad_off1 * Vcb->csum_size), Vcb->csum_size) == Vcb->csum_size) { if (c->devices[parity2]->devobj && RtlCompareMemory(hash2, (uint8_t*)context->csum + (bad_off1 * Vcb->csum_size), Vcb->csum_size) == Vcb->csum_size) {
RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
scratch, Vcb->superblock.sector_size); scratch, Vcb->superblock.sector_size);
if (c->devices[parity1]->devobj && RtlCompareMemory(hash1, (uint8_t*)context->csum + (bad_off1 * Vcb->csum_size), Vcb->csum_size) != Vcb->csum_size) { if (c->devices[parity1]->devobj && RtlCompareMemory(hash1, (uint8_t*)context->csum + (bad_off1 * Vcb->csum_size), Vcb->csum_size) != Vcb->csum_size) {
@ -2218,16 +2216,16 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
stripe = (parity1 + 2) % c->chunk_item->num_stripes; stripe = (parity1 + 2) % c->chunk_item->num_stripes;
RtlCopyMemory(&context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], RtlCopyMemory(&context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], &context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
Vcb->superblock.sector_size); Vcb->superblock.sector_size);
stripe = (stripe + 1) % c->chunk_item->num_stripes; stripe = (stripe + 1) % c->chunk_item->num_stripes;
while (stripe != parity1) { while (stripe != parity1) {
do_xor(&context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], do_xor(&context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], &context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
Vcb->superblock.sector_size); Vcb->superblock.sector_size);
stripe = (stripe + 1) % c->chunk_item->num_stripes; stripe = (stripe + 1) % c->chunk_item->num_stripes;
} }
@ -2238,24 +2236,24 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
log_device_error(Vcb, c->devices[parity1], BTRFS_DEV_STAT_CORRUPTION_ERRORS); log_device_error(Vcb, c->devices[parity1], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
} }
} else { } else {
RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch[i * Vcb->superblock.sector_size], Vcb->superblock.sector_size); &context->parity_scratch[i << Vcb->sector_shift], Vcb->superblock.sector_size);
if (c->devices[parity2]->devobj && RtlCompareMemory(hash2, (uint8_t*)context->csum + (bad_off1 * Vcb->csum_size), Vcb->csum_size) != Vcb->csum_size) { if (c->devices[parity2]->devobj && RtlCompareMemory(hash2, (uint8_t*)context->csum + (bad_off1 * Vcb->csum_size), Vcb->csum_size) != Vcb->csum_size) {
// fix parity 2 // fix parity 2
stripe = parity1 == 0 ? (c->chunk_item->num_stripes - 1) : (parity1 - 1); stripe = parity1 == 0 ? (c->chunk_item->num_stripes - 1) : (parity1 - 1);
RtlCopyMemory(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], RtlCopyMemory(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], &context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
Vcb->superblock.sector_size); Vcb->superblock.sector_size);
stripe = stripe == 0 ? (c->chunk_item->num_stripes - 1) : (stripe - 1); stripe = stripe == 0 ? (c->chunk_item->num_stripes - 1) : (stripe - 1);
while (stripe != parity2) { while (stripe != parity2) {
galois_double(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], Vcb->superblock.sector_size); galois_double(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)], Vcb->superblock.sector_size);
do_xor(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], do_xor(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], &context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
Vcb->superblock.sector_size); Vcb->superblock.sector_size);
stripe = stripe == 0 ? (c->chunk_item->num_stripes - 1) : (stripe - 1); stripe = stripe == 0 ? (c->chunk_item->num_stripes - 1) : (stripe - 1);
@ -2290,31 +2288,31 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
k = c->chunk_item->num_stripes - 3; k = c->chunk_item->num_stripes - 3;
if (stripe == bad_stripe1 || stripe == bad_stripe2) { if (stripe == bad_stripe1 || stripe == bad_stripe2) {
RtlZeroMemory(&context->parity_scratch[i * Vcb->superblock.sector_size], len); RtlZeroMemory(&context->parity_scratch[i << Vcb->sector_shift], len);
RtlZeroMemory(&context->parity_scratch2[i * Vcb->superblock.sector_size], len); RtlZeroMemory(&context->parity_scratch2[i << Vcb->sector_shift], len);
if (stripe == bad_stripe1) if (stripe == bad_stripe1)
x = k; x = k;
else else
y = k; y = k;
} else { } else {
RtlCopyMemory(&context->parity_scratch[i * Vcb->superblock.sector_size], RtlCopyMemory(&context->parity_scratch[i << Vcb->sector_shift],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], len); &context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)], len);
RtlCopyMemory(&context->parity_scratch2[i * Vcb->superblock.sector_size], RtlCopyMemory(&context->parity_scratch2[i << Vcb->sector_shift],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], len); &context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)], len);
} }
stripe = stripe == 0 ? (c->chunk_item->num_stripes - 1) : (stripe - 1); stripe = stripe == 0 ? (c->chunk_item->num_stripes - 1) : (stripe - 1);
k--; k--;
do { do {
galois_double(&context->parity_scratch[i * Vcb->superblock.sector_size], len); galois_double(&context->parity_scratch[i << Vcb->sector_shift], len);
if (stripe != bad_stripe1 && stripe != bad_stripe2) { if (stripe != bad_stripe1 && stripe != bad_stripe2) {
do_xor(&context->parity_scratch[i * Vcb->superblock.sector_size], do_xor(&context->parity_scratch[i << Vcb->sector_shift],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], len); &context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)], len);
do_xor(&context->parity_scratch2[i * Vcb->superblock.sector_size], do_xor(&context->parity_scratch2[i << Vcb->sector_shift],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], len); &context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)], len);
} else if (stripe == bad_stripe1) } else if (stripe == bad_stripe1)
x = k; x = k;
else if (stripe == bad_stripe2) else if (stripe == bad_stripe2)
@ -2331,10 +2329,10 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
a = gmul(gyx, denom); a = gmul(gyx, denom);
b = gmul(gx, denom); b = gmul(gx, denom);
p = &context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)]; p = &context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)];
q = &context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)]; q = &context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)];
pxy = &context->parity_scratch2[i * Vcb->superblock.sector_size]; pxy = &context->parity_scratch2[i << Vcb->sector_shift];
qxy = &context->parity_scratch[i * Vcb->superblock.sector_size]; qxy = &context->parity_scratch[i << Vcb->sector_shift];
for (j = 0; j < len; j++) { for (j = 0; j < len; j++) {
*qxy = gmul(a, *p ^ *pxy) ^ gmul(b, *q ^ *qxy); *qxy = gmul(a, *p ^ *pxy) ^ gmul(b, *q ^ *qxy);
@ -2345,29 +2343,29 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
qxy++; qxy++;
} }
do_xor(&context->parity_scratch2[i * Vcb->superblock.sector_size], &context->parity_scratch[i * Vcb->superblock.sector_size], len); do_xor(&context->parity_scratch2[i << Vcb->sector_shift], &context->parity_scratch[i << Vcb->sector_shift], len);
do_xor(&context->parity_scratch2[i * Vcb->superblock.sector_size], &context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], len); do_xor(&context->parity_scratch2[i << Vcb->sector_shift], &context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)], len);
addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (bad_off1 * Vcb->superblock.sector_size); addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (bad_off1 << Vcb->sector_shift);
if (RtlCheckBit(&context->is_tree, bad_off1)) { if (RtlCheckBit(&context->is_tree, bad_off1)) {
tree_header* th = (tree_header*)&context->parity_scratch[i * Vcb->superblock.sector_size]; tree_header* th = (tree_header*)&context->parity_scratch[i << Vcb->sector_shift];
if (check_tree_checksum(Vcb, th) && th->address == addr) { if (check_tree_checksum(Vcb, th) && th->address == addr) {
RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch[i * Vcb->superblock.sector_size], Vcb->superblock.node_size); &context->parity_scratch[i << Vcb->sector_shift], Vcb->superblock.node_size);
context->stripes[bad_stripe1].rewrite = true; context->stripes[bad_stripe1].rewrite = true;
RtlClearBits(&context->stripes[bad_stripe1].error, i + 1, (Vcb->superblock.node_size / Vcb->superblock.sector_size) - 1); RtlClearBits(&context->stripes[bad_stripe1].error, i + 1, (Vcb->superblock.node_size >> Vcb->sector_shift) - 1);
log_error(Vcb, addr, c->devices[bad_stripe1]->devitem.dev_id, true, true, false); log_error(Vcb, addr, c->devices[bad_stripe1]->devitem.dev_id, true, true, false);
} else } else
log_error(Vcb, addr, c->devices[bad_stripe1]->devitem.dev_id, true, false, false); log_error(Vcb, addr, c->devices[bad_stripe1]->devitem.dev_id, true, false, false);
} else { } else {
if (check_sector_csum(Vcb, &context->parity_scratch[i * Vcb->superblock.sector_size], (uint8_t*)context->csum + (Vcb->csum_size * bad_off1))) { if (check_sector_csum(Vcb, &context->parity_scratch[i << Vcb->sector_shift], (uint8_t*)context->csum + (Vcb->csum_size * bad_off1))) {
RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch[i * Vcb->superblock.sector_size], Vcb->superblock.sector_size); &context->parity_scratch[i << Vcb->sector_shift], Vcb->superblock.sector_size);
context->stripes[bad_stripe1].rewrite = true; context->stripes[bad_stripe1].rewrite = true;
@ -2376,26 +2374,26 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
log_error(Vcb, addr, c->devices[bad_stripe1]->devitem.dev_id, false, false, false); log_error(Vcb, addr, c->devices[bad_stripe1]->devitem.dev_id, false, false, false);
} }
addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (bad_off2 * Vcb->superblock.sector_size); addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (bad_off2 << Vcb->sector_shift);
if (RtlCheckBit(&context->is_tree, bad_off2)) { if (RtlCheckBit(&context->is_tree, bad_off2)) {
tree_header* th = (tree_header*)&context->parity_scratch2[i * Vcb->superblock.sector_size]; tree_header* th = (tree_header*)&context->parity_scratch2[i << Vcb->sector_shift];
if (check_tree_checksum(Vcb, th) && th->address == addr) { if (check_tree_checksum(Vcb, th) && th->address == addr) {
RtlCopyMemory(&context->stripes[bad_stripe2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], RtlCopyMemory(&context->stripes[bad_stripe2].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch2[i * Vcb->superblock.sector_size], Vcb->superblock.node_size); &context->parity_scratch2[i << Vcb->sector_shift], Vcb->superblock.node_size);
context->stripes[bad_stripe2].rewrite = true; context->stripes[bad_stripe2].rewrite = true;
RtlClearBits(&context->stripes[bad_stripe2].error, i + 1, (Vcb->superblock.node_size / Vcb->superblock.sector_size) - 1); RtlClearBits(&context->stripes[bad_stripe2].error, i + 1, (Vcb->superblock.node_size >> Vcb->sector_shift) - 1);
log_error(Vcb, addr, c->devices[bad_stripe2]->devitem.dev_id, true, true, false); log_error(Vcb, addr, c->devices[bad_stripe2]->devitem.dev_id, true, true, false);
} else } else
log_error(Vcb, addr, c->devices[bad_stripe2]->devitem.dev_id, true, false, false); log_error(Vcb, addr, c->devices[bad_stripe2]->devitem.dev_id, true, false, false);
} else { } else {
if (check_sector_csum(Vcb, &context->parity_scratch2[i * Vcb->superblock.sector_size], (uint8_t*)context->csum + (Vcb->csum_size * bad_off2))) { if (check_sector_csum(Vcb, &context->parity_scratch2[i << Vcb->sector_shift], (uint8_t*)context->csum + (Vcb->csum_size * bad_off2))) {
RtlCopyMemory(&context->stripes[bad_stripe2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], RtlCopyMemory(&context->stripes[bad_stripe2].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch2[i * Vcb->superblock.sector_size], Vcb->superblock.sector_size); &context->parity_scratch2[i << Vcb->sector_shift], Vcb->superblock.sector_size);
context->stripes[bad_stripe2].rewrite = true; context->stripes[bad_stripe2].rewrite = true;
@ -2410,7 +2408,7 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
while (stripe != parity1) { while (stripe != parity1) {
if (c->devices[stripe]->devobj && RtlCheckBit(&context->alloc, off)) { if (c->devices[stripe]->devobj && RtlCheckBit(&context->alloc, off)) {
if (RtlCheckBit(&context->stripes[stripe].error, i)) { if (RtlCheckBit(&context->stripes[stripe].error, i)) {
uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (off * Vcb->superblock.sector_size); uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (off << Vcb->sector_shift);
log_error(Vcb, addr, c->devices[stripe]->devitem.dev_id, RtlCheckBit(&context->is_tree, off), false, false); log_error(Vcb, addr, c->devices[stripe]->devitem.dev_id, RtlCheckBit(&context->is_tree, off), false, false);
} }
@ -2451,7 +2449,7 @@ static NTSTATUS scrub_chunk_raid56_stripe_run(device_extension* Vcb, chunk* c, u
return Status; return Status;
} }
num_sectors = (uint32_t)((stripe_end - stripe_start + 1) * full_stripe_len / Vcb->superblock.sector_size); num_sectors = (uint32_t)(((stripe_end - stripe_start + 1) * full_stripe_len) >> Vcb->sector_shift);
arrlen = (ULONG)sector_align((num_sectors / 8) + 1, sizeof(ULONG)); arrlen = (ULONG)sector_align((num_sectors / 8) + 1, sizeof(ULONG));
allocarr = ExAllocatePoolWithTag(PagedPool, arrlen, ALLOC_TAG); allocarr = ExAllocatePoolWithTag(PagedPool, arrlen, ALLOC_TAG);
@ -2536,7 +2534,7 @@ static NTSTATUS scrub_chunk_raid56_stripe_run(device_extension* Vcb, chunk* c, u
uint64_t extent_end = min(tp.item->key.obj_id + size, run_end); uint64_t extent_end = min(tp.item->key.obj_id + size, run_end);
bool extent_is_tree = false; bool extent_is_tree = false;
RtlSetBits(&context.alloc, (ULONG)((extent_start - run_start) / Vcb->superblock.sector_size), (ULONG)((extent_end - extent_start) / Vcb->superblock.sector_size)); RtlSetBits(&context.alloc, (ULONG)((extent_start - run_start) >> Vcb->sector_shift), (ULONG)((extent_end - extent_start) >> Vcb->sector_shift));
if (tp.item->key.obj_type == TYPE_METADATA_ITEM) if (tp.item->key.obj_type == TYPE_METADATA_ITEM)
extent_is_tree = true; extent_is_tree = true;
@ -2554,7 +2552,7 @@ static NTSTATUS scrub_chunk_raid56_stripe_run(device_extension* Vcb, chunk* c, u
} }
if (extent_is_tree) if (extent_is_tree)
RtlSetBits(&context.is_tree, (ULONG)((extent_start - run_start) / Vcb->superblock.sector_size), (ULONG)((extent_end - extent_start) / Vcb->superblock.sector_size)); RtlSetBits(&context.is_tree, (ULONG)((extent_start - run_start) >> Vcb->sector_shift), (ULONG)((extent_end - extent_start) >> Vcb->sector_shift));
else if (c->chunk_item->type & BLOCK_FLAG_DATA) { else if (c->chunk_item->type & BLOCK_FLAG_DATA) {
traverse_ptr tp2; traverse_ptr tp2;
bool b2; bool b2;
@ -2577,13 +2575,13 @@ static NTSTATUS scrub_chunk_raid56_stripe_run(device_extension* Vcb, chunk* c, u
if (tp2.item->key.offset >= extent_start) { if (tp2.item->key.offset >= extent_start) {
uint64_t csum_start = max(extent_start, tp2.item->key.offset); uint64_t csum_start = max(extent_start, tp2.item->key.offset);
uint64_t csum_end = min(extent_end, tp2.item->key.offset + (tp2.item->size * Vcb->superblock.sector_size / Vcb->csum_size)); uint64_t csum_end = min(extent_end, tp2.item->key.offset + (((uint64_t)tp2.item->size << Vcb->sector_shift) / Vcb->csum_size));
RtlSetBits(&context.has_csum, (ULONG)((csum_start - run_start) / Vcb->superblock.sector_size), (ULONG)((csum_end - csum_start) / Vcb->superblock.sector_size)); RtlSetBits(&context.has_csum, (ULONG)((csum_start - run_start) >> Vcb->sector_shift), (ULONG)((csum_end - csum_start) >> Vcb->sector_shift));
RtlCopyMemory((uint8_t*)context.csum + ((csum_start - run_start) * Vcb->csum_size / Vcb->superblock.sector_size), RtlCopyMemory((uint8_t*)context.csum + (((csum_start - run_start) * Vcb->csum_size) >> Vcb->sector_shift),
tp2.item->data + ((csum_start - tp2.item->key.offset) * Vcb->csum_size / Vcb->superblock.sector_size), tp2.item->data + (((csum_start - tp2.item->key.offset) * Vcb->csum_size) >> Vcb->sector_shift),
(ULONG)((csum_end - csum_start) * Vcb->csum_size / Vcb->superblock.sector_size)); (ULONG)(((csum_end - csum_start) * Vcb->csum_size) >> Vcb->sector_shift));
} }
b2 = find_next_item(Vcb, &tp2, &next_tp2, false, NULL); b2 = find_next_item(Vcb, &tp2, &next_tp2, false, NULL);
@ -2626,7 +2624,7 @@ static NTSTATUS scrub_chunk_raid56_stripe_run(device_extension* Vcb, chunk* c, u
goto end; goto end;
} }
context.stripes[i].errorarr = ExAllocatePoolWithTag(PagedPool, (ULONG)sector_align(((c->chunk_item->stripe_length / Vcb->superblock.sector_size) / 8) + 1, sizeof(ULONG)), ALLOC_TAG); context.stripes[i].errorarr = ExAllocatePoolWithTag(PagedPool, (ULONG)sector_align(((c->chunk_item->stripe_length >> Vcb->sector_shift) / 8) + 1, sizeof(ULONG)), ALLOC_TAG);
if (!context.stripes[i].errorarr) { if (!context.stripes[i].errorarr) {
uint64_t j; uint64_t j;
@ -2643,7 +2641,7 @@ static NTSTATUS scrub_chunk_raid56_stripe_run(device_extension* Vcb, chunk* c, u
goto end; goto end;
} }
RtlInitializeBitMap(&context.stripes[i].error, context.stripes[i].errorarr, (ULONG)(c->chunk_item->stripe_length / Vcb->superblock.sector_size)); RtlInitializeBitMap(&context.stripes[i].error, context.stripes[i].errorarr, (ULONG)(c->chunk_item->stripe_length >> Vcb->sector_shift));
context.stripes[i].context = &context; context.stripes[i].context = &context;
context.stripes[i].rewrite = false; context.stripes[i].rewrite = false;
@ -3006,14 +3004,14 @@ static NTSTATUS scrub_chunk(device_extension* Vcb, chunk* c, uint64_t* offset, b
if (!is_tree) { if (!is_tree) {
traverse_ptr tp2; traverse_ptr tp2;
csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(Vcb->csum_size * size / Vcb->superblock.sector_size), ALLOC_TAG); csum = ExAllocatePoolWithTag(PagedPool, (ULONG)((Vcb->csum_size * size) >> Vcb->sector_shift), ALLOC_TAG);
if (!csum) { if (!csum) {
ERR("out of memory\n"); ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
goto end; goto end;
} }
bmplen = (ULONG)(size / Vcb->superblock.sector_size); bmplen = (ULONG)(size >> Vcb->sector_shift);
bmparr = ExAllocatePoolWithTag(PagedPool, (ULONG)(sector_align((bmplen >> 3) + 1, sizeof(ULONG))), ALLOC_TAG); bmparr = ExAllocatePoolWithTag(PagedPool, (ULONG)(sector_align((bmplen >> 3) + 1, sizeof(ULONG))), ALLOC_TAG);
if (!bmparr) { if (!bmparr) {
@ -3045,15 +3043,15 @@ static NTSTATUS scrub_chunk(device_extension* Vcb, chunk* c, uint64_t* offset, b
if (tp2.item->key.obj_type == TYPE_EXTENT_CSUM) { if (tp2.item->key.obj_type == TYPE_EXTENT_CSUM) {
if (tp2.item->key.offset >= tp.item->key.obj_id + size) if (tp2.item->key.offset >= tp.item->key.obj_id + size)
break; break;
else if (tp2.item->size >= Vcb->csum_size && tp2.item->key.offset + (tp2.item->size * Vcb->superblock.sector_size / Vcb->csum_size) >= tp.item->key.obj_id) { else if (tp2.item->size >= Vcb->csum_size && tp2.item->key.offset + (((uint64_t)tp2.item->size << Vcb->sector_shift) / Vcb->csum_size) >= tp.item->key.obj_id) {
uint64_t cs = max(tp.item->key.obj_id, tp2.item->key.offset); uint64_t cs = max(tp.item->key.obj_id, tp2.item->key.offset);
uint64_t ce = min(tp.item->key.obj_id + size, tp2.item->key.offset + (tp2.item->size * Vcb->superblock.sector_size / Vcb->csum_size)); uint64_t ce = min(tp.item->key.obj_id + size, tp2.item->key.offset + (((uint64_t)tp2.item->size << Vcb->sector_shift) / Vcb->csum_size));
RtlCopyMemory((uint8_t*)csum + ((cs - tp.item->key.obj_id) * Vcb->csum_size / Vcb->superblock.sector_size), RtlCopyMemory((uint8_t*)csum + (((cs - tp.item->key.obj_id) * Vcb->csum_size) >> Vcb->sector_shift),
tp2.item->data + ((cs - tp2.item->key.offset) * Vcb->csum_size / Vcb->superblock.sector_size), tp2.item->data + (((cs - tp2.item->key.offset) * Vcb->csum_size) >> Vcb->sector_shift),
(ULONG)((ce - cs) * Vcb->csum_size / Vcb->superblock.sector_size)); (ULONG)(((ce - cs) * Vcb->csum_size) >> Vcb->sector_shift));
RtlClearBits(&bmp, (ULONG)((cs - tp.item->key.obj_id) / Vcb->superblock.sector_size), (ULONG)((ce - cs) / Vcb->superblock.sector_size)); RtlClearBits(&bmp, (ULONG)((cs - tp.item->key.obj_id) >> Vcb->sector_shift), (ULONG)((ce - cs) >> Vcb->sector_shift));
if (ce == tp.item->key.obj_id + size) if (ce == tp.item->key.obj_id + size)
break; break;

View file

@ -1988,7 +1988,7 @@ static bool try_clone_edr(send_context* context, send_ext* se, EXTENT_DATA_REF*
uint64_t clone_offset = tp.item->key.offset + ed2->offset - seed2->offset; uint64_t clone_offset = tp.item->key.offset + ed2->offset - seed2->offset;
uint64_t clone_len = min(context->lastinode.size - se->offset, ed2->num_bytes); uint64_t clone_len = min(context->lastinode.size - se->offset, ed2->num_bytes);
if (clone_offset % context->Vcb->superblock.sector_size == 0 && clone_len % context->Vcb->superblock.sector_size == 0) { if ((clone_offset & (context->Vcb->superblock.sector_size - 1)) == 0 && (clone_len & (context->Vcb->superblock.sector_size - 1)) == 0) {
ULONG pos = context->datalen; ULONG pos = context->datalen;
send_command(context, BTRFS_SEND_CMD_CLONE); send_command(context, BTRFS_SEND_CMD_CLONE);
@ -2323,7 +2323,7 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr* tp1, traverse
} }
} }
skip_start = addr % context->Vcb->superblock.sector_size; skip_start = addr & (context->Vcb->superblock.sector_size - 1);
addr -= skip_start; addr -= skip_start;
if (context->lastinode.flags & BTRFS_INODE_NODATASUM) if (context->lastinode.flags & BTRFS_INODE_NODATASUM)
@ -2331,7 +2331,7 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr* tp1, traverse
else { else {
uint32_t len; uint32_t len;
len = (uint32_t)sector_align(length + skip_start, context->Vcb->superblock.sector_size) / context->Vcb->superblock.sector_size; len = (uint32_t)sector_align(length + skip_start, context->Vcb->superblock.sector_size) >> context->Vcb->sector_shift;
csum = ExAllocatePoolWithTag(PagedPool, len * context->Vcb->csum_size, ALLOC_TAG); csum = ExAllocatePoolWithTag(PagedPool, len * context->Vcb->csum_size, ALLOC_TAG);
if (!csum) { if (!csum) {
@ -2410,7 +2410,7 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr* tp1, traverse
else { else {
uint32_t len; uint32_t len;
len = (uint32_t)(ed2->size / context->Vcb->superblock.sector_size); len = (uint32_t)(ed2->size >> context->Vcb->sector_shift);
csum = ExAllocatePoolWithTag(PagedPool, len * context->Vcb->csum_size, ALLOC_TAG); csum = ExAllocatePoolWithTag(PagedPool, len * context->Vcb->csum_size, ALLOC_TAG);
if (!csum) { if (!csum) {

View file

@ -18,6 +18,7 @@
#include "btrfs_drv.h" #include "btrfs_drv.h"
#include "crc32c.h" #include "crc32c.h"
__attribute__((nonnull(1,3,4,5)))
NTSTATUS load_tree(device_extension* Vcb, uint64_t addr, uint8_t* buf, root* r, tree** pt) { NTSTATUS load_tree(device_extension* Vcb, uint64_t addr, uint8_t* buf, root* r, tree** pt) {
tree_header* th; tree_header* th;
tree* t; tree* t;
@ -191,6 +192,7 @@ NTSTATUS load_tree(device_extension* Vcb, uint64_t addr, uint8_t* buf, root* r,
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
__attribute__((nonnull(1,2,3,4)))
static NTSTATUS do_load_tree2(device_extension* Vcb, tree_holder* th, uint8_t* buf, root* r, tree* t, tree_data* td) { static NTSTATUS do_load_tree2(device_extension* Vcb, tree_holder* th, uint8_t* buf, root* r, tree* t, tree_data* td) {
if (!th->tree) { if (!th->tree) {
NTSTATUS Status; NTSTATUS Status;
@ -216,6 +218,7 @@ static NTSTATUS do_load_tree2(device_extension* Vcb, tree_holder* th, uint8_t* b
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
__attribute__((nonnull(1,2,3)))
NTSTATUS do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, PIRP Irp) { NTSTATUS do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, PIRP Irp) {
NTSTATUS Status; NTSTATUS Status;
uint8_t* buf; uint8_t* buf;
@ -258,6 +261,7 @@ NTSTATUS do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t,
return Status; return Status;
} }
__attribute__((nonnull(1)))
void free_tree(tree* t) { void free_tree(tree* t) {
tree* par; tree* par;
root* r = t->root; root* r = t->root;
@ -314,6 +318,7 @@ void free_tree(tree* t) {
ExFreePool(t); ExFreePool(t);
} }
__attribute__((nonnull(1)))
static __inline tree_data* first_item(tree* t) { static __inline tree_data* first_item(tree* t) {
LIST_ENTRY* le = t->itemlist.Flink; LIST_ENTRY* le = t->itemlist.Flink;
@ -323,6 +328,7 @@ static __inline tree_data* first_item(tree* t) {
return CONTAINING_RECORD(le, tree_data, list_entry); return CONTAINING_RECORD(le, tree_data, list_entry);
} }
__attribute__((nonnull(1,2)))
static __inline tree_data* prev_item(tree* t, tree_data* td) { static __inline tree_data* prev_item(tree* t, tree_data* td) {
LIST_ENTRY* le = td->list_entry.Blink; LIST_ENTRY* le = td->list_entry.Blink;
@ -332,6 +338,7 @@ static __inline tree_data* prev_item(tree* t, tree_data* td) {
return CONTAINING_RECORD(le, tree_data, list_entry); return CONTAINING_RECORD(le, tree_data, list_entry);
} }
__attribute__((nonnull(1,2)))
static __inline tree_data* next_item(tree* t, tree_data* td) { static __inline tree_data* next_item(tree* t, tree_data* td) {
LIST_ENTRY* le = td->list_entry.Flink; LIST_ENTRY* le = td->list_entry.Flink;
@ -341,6 +348,7 @@ static __inline tree_data* next_item(tree* t, tree_data* td) {
return CONTAINING_RECORD(le, tree_data, list_entry); return CONTAINING_RECORD(le, tree_data, list_entry);
} }
__attribute__((nonnull(1,2,3,4)))
static NTSTATUS next_item2(device_extension* Vcb, tree* t, tree_data* td, traverse_ptr* tp) { static NTSTATUS next_item2(device_extension* Vcb, tree* t, tree_data* td, traverse_ptr* tp) {
tree_data* td2 = next_item(t, td); tree_data* td2 = next_item(t, td);
tree* t2; tree* t2;
@ -366,6 +374,7 @@ static NTSTATUS next_item2(device_extension* Vcb, tree* t, tree_data* td, traver
return find_item_to_level(Vcb, t2->root, tp, &td2->key, false, t->header.level, NULL); return find_item_to_level(Vcb, t2->root, tp, &td2->key, false, t->header.level, NULL);
} }
__attribute__((nonnull(1,2,3,4,5)))
NTSTATUS skip_to_difference(device_extension* Vcb, traverse_ptr* tp, traverse_ptr* tp2, bool* ended1, bool* ended2) { NTSTATUS skip_to_difference(device_extension* Vcb, traverse_ptr* tp, traverse_ptr* tp2, bool* ended1, bool* ended2) {
NTSTATUS Status; NTSTATUS Status;
tree *t1, *t2; tree *t1, *t2;
@ -441,6 +450,7 @@ NTSTATUS skip_to_difference(device_extension* Vcb, traverse_ptr* tp, traverse_pt
} }
} }
__attribute__((nonnull(1,2,3,4)))
static NTSTATUS find_item_in_tree(device_extension* Vcb, tree* t, traverse_ptr* tp, const KEY* searchkey, bool ignore, uint8_t level, PIRP Irp) { static NTSTATUS find_item_in_tree(device_extension* Vcb, tree* t, traverse_ptr* tp, const KEY* searchkey, bool ignore, uint8_t level, PIRP Irp) {
int cmp; int cmp;
tree_data *td, *lasttd; tree_data *td, *lasttd;
@ -546,6 +556,7 @@ static NTSTATUS find_item_in_tree(device_extension* Vcb, tree* t, traverse_ptr*
} }
} }
__attribute__((nonnull(1,2,3,4)))
NTSTATUS find_item(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _Out_ traverse_ptr* tp, 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) { _In_ const KEY* searchkey, _In_ bool ignore, _In_opt_ PIRP Irp) {
NTSTATUS Status; NTSTATUS Status;
@ -566,6 +577,7 @@ NTSTATUS find_item(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension
return Status; return Status;
} }
__attribute__((nonnull(1,2,3,4)))
NTSTATUS find_item_to_level(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, bool ignore, uint8_t level, PIRP Irp) { NTSTATUS find_item_to_level(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, bool ignore, uint8_t level, PIRP Irp) {
NTSTATUS Status; NTSTATUS Status;
@ -590,6 +602,7 @@ NTSTATUS find_item_to_level(device_extension* Vcb, root* r, traverse_ptr* tp, co
return Status; return Status;
} }
__attribute__((nonnull(1,2,3)))
bool find_next_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* next_tp, bool ignore, PIRP Irp) { bool find_next_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* next_tp, bool ignore, PIRP Irp) {
tree* t; tree* t;
tree_data *td = NULL, *next; tree_data *td = NULL, *next;
@ -648,6 +661,9 @@ bool find_next_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vc
fi = first_item(t); fi = first_item(t);
if (!fi)
return false;
if (!fi->treeholder.tree) { if (!fi->treeholder.tree) {
Status = do_load_tree(Vcb, &fi->treeholder, t->parent->root, t, fi, Irp); Status = do_load_tree(Vcb, &fi->treeholder, t->parent->root, t, fi, Irp);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
@ -662,6 +678,9 @@ bool find_next_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vc
next_tp->tree = t; next_tp->tree = t;
next_tp->item = first_item(t); next_tp->item = first_item(t);
if (!next_tp->item)
return false;
if (!ignore && next_tp->item->ignore) { if (!ignore && next_tp->item->ignore) {
traverse_ptr ntp2; traverse_ptr ntp2;
bool b; bool b;
@ -687,6 +706,7 @@ bool find_next_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vc
return true; return true;
} }
__attribute__((nonnull(1)))
static __inline tree_data* last_item(tree* t) { static __inline tree_data* last_item(tree* t) {
LIST_ENTRY* le = t->itemlist.Blink; LIST_ENTRY* le = t->itemlist.Blink;
@ -696,6 +716,7 @@ static __inline tree_data* last_item(tree* t) {
return CONTAINING_RECORD(le, tree_data, list_entry); return CONTAINING_RECORD(le, tree_data, list_entry);
} }
__attribute__((nonnull(1,2,3)))
bool find_prev_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* prev_tp, PIRP Irp) { bool find_prev_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* prev_tp, PIRP Irp) {
tree* t; tree* t;
tree_data* td; tree_data* td;
@ -754,6 +775,7 @@ bool find_prev_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vc
return true; return true;
} }
__attribute__((nonnull(1,2)))
void free_trees_root(device_extension* Vcb, root* r) { void free_trees_root(device_extension* Vcb, root* r) {
LIST_ENTRY* le; LIST_ENTRY* le;
ULONG level; ULONG level;
@ -791,6 +813,7 @@ void free_trees_root(device_extension* Vcb, root* r) {
} }
} }
__attribute__((nonnull(1)))
void free_trees(device_extension* Vcb) { void free_trees(device_extension* Vcb) {
LIST_ENTRY* le; LIST_ENTRY* le;
ULONG level; ULONG level;
@ -834,6 +857,7 @@ void free_trees(device_extension* Vcb) {
#pragma warning(push) #pragma warning(push)
#pragma warning(suppress: 28194) #pragma warning(suppress: 28194)
#endif #endif
__attribute__((nonnull(1,3)))
void add_rollback(_In_ LIST_ENTRY* rollback, _In_ enum rollback_type type, _In_ __drv_aliasesMem void* ptr) { void add_rollback(_In_ LIST_ENTRY* rollback, _In_ enum rollback_type type, _In_ __drv_aliasesMem void* ptr) {
rollback_item* ri; rollback_item* ri;
@ -855,6 +879,7 @@ void add_rollback(_In_ LIST_ENTRY* rollback, _In_ enum rollback_type type, _In_
#pragma warning(push) #pragma warning(push)
#pragma warning(suppress: 28194) #pragma warning(suppress: 28194)
#endif #endif
__attribute__((nonnull(1,2)))
NTSTATUS insert_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _In_ uint64_t obj_id, NTSTATUS insert_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _In_ uint64_t obj_id,
_In_ uint8_t obj_type, _In_ uint64_t offset, _In_reads_bytes_opt_(size) _When_(return >= 0, __drv_aliasesMem) void* data, _In_ uint8_t obj_type, _In_ uint64_t offset, _In_reads_bytes_opt_(size) _When_(return >= 0, __drv_aliasesMem) void* data,
_In_ uint16_t size, _Out_opt_ traverse_ptr* ptp, _In_opt_ PIRP Irp) { _In_ uint16_t size, _Out_opt_ traverse_ptr* ptp, _In_opt_ PIRP Irp) {
@ -877,25 +902,20 @@ NTSTATUS insert_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock)
Status = find_item(Vcb, r, &tp, &searchkey, true, Irp); Status = find_item(Vcb, r, &tp, &searchkey, true, Irp);
if (Status == STATUS_NOT_FOUND) { if (Status == STATUS_NOT_FOUND) {
if (r) { if (!r->treeholder.tree) {
if (!r->treeholder.tree) { Status = do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, Irp);
Status = do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, Irp); if (!NT_SUCCESS(Status)) {
if (!NT_SUCCESS(Status)) { ERR("do_load_tree returned %08lx\n", Status);
ERR("do_load_tree returned %08lx\n", Status); return Status;
return Status;
}
} }
}
if (r->treeholder.tree && r->treeholder.tree->header.num_items == 0) { if (r->treeholder.tree && r->treeholder.tree->header.num_items == 0) {
tp.tree = r->treeholder.tree; tp.tree = r->treeholder.tree;
tp.item = NULL; tp.item = NULL;
} else {
ERR("error: unable to load tree for root %I64x\n", r->id);
return STATUS_INTERNAL_ERROR;
}
} else { } else {
ERR("error: find_item returned %08lx\n", Status); ERR("error: unable to load tree for root %I64x\n", r->id);
return Status; return STATUS_INTERNAL_ERROR;
} }
} else if (!NT_SUCCESS(Status)) { } else if (!NT_SUCCESS(Status)) {
ERR("find_item returned %08lx\n", Status); ERR("find_item returned %08lx\n", Status);
@ -987,6 +1007,7 @@ NTSTATUS insert_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock)
#pragma warning(pop) #pragma warning(pop)
#endif #endif
__attribute__((nonnull(1,2)))
NTSTATUS delete_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _Inout_ traverse_ptr* tp) { NTSTATUS delete_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _Inout_ traverse_ptr* tp) {
tree* t; tree* t;
uint64_t gen; uint64_t gen;
@ -1026,6 +1047,7 @@ NTSTATUS delete_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock)
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
__attribute__((nonnull(1)))
void clear_rollback(LIST_ENTRY* rollback) { void clear_rollback(LIST_ENTRY* rollback) {
while (!IsListEmpty(rollback)) { while (!IsListEmpty(rollback)) {
LIST_ENTRY* le = RemoveHeadList(rollback); LIST_ENTRY* le = RemoveHeadList(rollback);
@ -1047,6 +1069,7 @@ void clear_rollback(LIST_ENTRY* rollback) {
} }
} }
__attribute__((nonnull(1,2)))
void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) { void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) {
NTSTATUS Status; NTSTATUS Status;
rollback_item* ri; rollback_item* ri;
@ -1062,23 +1085,32 @@ void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) {
re->ext->ignore = true; re->ext->ignore = true;
if (re->ext->extent_data.type == EXTENT_TYPE_REGULAR || re->ext->extent_data.type == EXTENT_TYPE_PREALLOC) { switch (re->ext->extent_data.type) {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)re->ext->extent_data.data; case EXTENT_TYPE_REGULAR:
case EXTENT_TYPE_PREALLOC: {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)re->ext->extent_data.data;
if (ed2->size != 0) { if (ed2->size != 0) {
chunk* c = get_chunk_from_address(Vcb, ed2->address); chunk* c = get_chunk_from_address(Vcb, ed2->address);
if (c) { if (c) {
Status = update_changed_extent_ref(Vcb, c, ed2->address, ed2->size, re->fcb->subvol->id, Status = update_changed_extent_ref(Vcb, c, ed2->address, ed2->size, re->fcb->subvol->id,
re->fcb->inode, re->ext->offset - ed2->offset, -1, re->fcb->inode, re->ext->offset - ed2->offset, -1,
re->fcb->inode_item.flags & BTRFS_INODE_NODATASUM, false, NULL); re->fcb->inode_item.flags & BTRFS_INODE_NODATASUM, false, NULL);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
ERR("update_changed_extent_ref returned %08lx\n", Status); ERR("update_changed_extent_ref returned %08lx\n", Status);
}
re->fcb->inode_item.st_blocks -= ed2->num_bytes;
} }
re->fcb->inode_item.st_blocks -= ed2->num_bytes; break;
} }
case EXTENT_TYPE_INLINE:
re->fcb->inode_item.st_blocks -= re->ext->extent_data.decoded_size;
break;
} }
ExFreePool(re); ExFreePool(re);
@ -1091,23 +1123,32 @@ void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) {
re->ext->ignore = false; re->ext->ignore = false;
if (re->ext->extent_data.type == EXTENT_TYPE_REGULAR || re->ext->extent_data.type == EXTENT_TYPE_PREALLOC) { switch (re->ext->extent_data.type) {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)re->ext->extent_data.data; case EXTENT_TYPE_REGULAR:
case EXTENT_TYPE_PREALLOC: {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)re->ext->extent_data.data;
if (ed2->size != 0) { if (ed2->size != 0) {
chunk* c = get_chunk_from_address(Vcb, ed2->address); chunk* c = get_chunk_from_address(Vcb, ed2->address);
if (c) { if (c) {
Status = update_changed_extent_ref(Vcb, c, ed2->address, ed2->size, re->fcb->subvol->id, Status = update_changed_extent_ref(Vcb, c, ed2->address, ed2->size, re->fcb->subvol->id,
re->fcb->inode, re->ext->offset - ed2->offset, 1, re->fcb->inode, re->ext->offset - ed2->offset, 1,
re->fcb->inode_item.flags & BTRFS_INODE_NODATASUM, false, NULL); re->fcb->inode_item.flags & BTRFS_INODE_NODATASUM, false, NULL);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
ERR("update_changed_extent_ref returned %08lx\n", Status); ERR("update_changed_extent_ref returned %08lx\n", Status);
}
re->fcb->inode_item.st_blocks += ed2->num_bytes;
} }
re->fcb->inode_item.st_blocks += ed2->num_bytes; break;
} }
case EXTENT_TYPE_INLINE:
re->fcb->inode_item.st_blocks += re->ext->extent_data.decoded_size;
break;
} }
ExFreePool(re); ExFreePool(re);
@ -1175,7 +1216,8 @@ void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) {
} }
} }
static void find_tree_end(tree* t, KEY* tree_end, bool* no_end) { __attribute__((nonnull(1,2,3)))
static NTSTATUS find_tree_end(tree* t, KEY* tree_end, bool* no_end) {
tree* p; tree* p;
p = t; p = t;
@ -1183,8 +1225,11 @@ static void find_tree_end(tree* t, KEY* tree_end, bool* no_end) {
tree_data* pi; tree_data* pi;
if (!p->parent) { if (!p->parent) {
tree_end->obj_id = 0xffffffffffffffff;
tree_end->obj_type = 0xff;
tree_end->offset = 0xffffffffffffffff;
*no_end = true; *no_end = true;
return; return STATUS_SUCCESS;
} }
pi = p->paritem; pi = p->paritem;
@ -1194,13 +1239,16 @@ static void find_tree_end(tree* t, KEY* tree_end, bool* no_end) {
*tree_end = td->key; *tree_end = td->key;
*no_end = false; *no_end = false;
return; return STATUS_SUCCESS;
} }
p = p->parent; p = p->parent;
} while (p); } while (p);
return STATUS_INTERNAL_ERROR;
} }
__attribute__((nonnull(1,2)))
void clear_batch_list(device_extension* Vcb, LIST_ENTRY* batchlist) { void clear_batch_list(device_extension* Vcb, LIST_ENTRY* batchlist) {
while (!IsListEmpty(batchlist)) { while (!IsListEmpty(batchlist)) {
LIST_ENTRY* le = RemoveHeadList(batchlist); LIST_ENTRY* le = RemoveHeadList(batchlist);
@ -1217,6 +1265,7 @@ void clear_batch_list(device_extension* Vcb, LIST_ENTRY* batchlist) {
} }
} }
__attribute__((nonnull(1,2,3)))
static void add_delete_inode_extref(device_extension* Vcb, batch_item* bi, LIST_ENTRY* listhead) { static void add_delete_inode_extref(device_extension* Vcb, batch_item* bi, LIST_ENTRY* listhead) {
batch_item* bi2; batch_item* bi2;
LIST_ENTRY* le; LIST_ENTRY* le;
@ -1265,6 +1314,7 @@ static void add_delete_inode_extref(device_extension* Vcb, batch_item* bi, LIST_
InsertTailList(listhead, &bi2->list_entry); InsertTailList(listhead, &bi2->list_entry);
} }
__attribute__((nonnull(1,2,3,4,6,7)))
static NTSTATUS handle_batch_collision(device_extension* Vcb, batch_item* bi, tree* t, tree_data* td, tree_data* newtd, LIST_ENTRY* listhead, bool* ignore) { static NTSTATUS handle_batch_collision(device_extension* Vcb, batch_item* bi, tree* t, tree_data* td, tree_data* newtd, LIST_ENTRY* listhead, bool* ignore) {
if (bi->operation == Batch_Delete || bi->operation == Batch_SetXattr || bi->operation == Batch_DirItem || bi->operation == Batch_InodeRef || if (bi->operation == Batch_Delete || bi->operation == Batch_SetXattr || bi->operation == Batch_DirItem || bi->operation == Batch_InodeRef ||
bi->operation == Batch_InodeExtRef || bi->operation == Batch_DeleteDirItem || bi->operation == Batch_DeleteInodeRef || bi->operation == Batch_InodeExtRef || bi->operation == Batch_DeleteDirItem || bi->operation == Batch_DeleteInodeRef ||
@ -1849,6 +1899,7 @@ static NTSTATUS handle_batch_collision(device_extension* Vcb, batch_item* bi, tr
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
__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* le; LIST_ENTRY* le;
NTSTATUS Status; NTSTATUS Status;
@ -1875,7 +1926,11 @@ static NTSTATUS commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tr
return Status; return Status;
} }
find_tree_end(tp.tree, &tree_end, &no_end); Status = find_tree_end(tp.tree, &tree_end, &no_end);
if (!NT_SUCCESS(Status)) {
ERR("find_tree_end returned %08lx\n", Status);
return Status;
}
if (bi->operation == Batch_DeleteInode) { if (bi->operation == Batch_DeleteInode) {
if (tp.item->key.obj_id == bi->key.obj_id) { if (tp.item->key.obj_id == bi->key.obj_id) {
@ -1946,7 +2001,11 @@ static NTSTATUS commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tr
if (find_next_item(Vcb, &tp, &tp2, false, Irp)) { if (find_next_item(Vcb, &tp, &tp2, false, Irp)) {
if (tp2.item->key.obj_id == bi->key.obj_id && tp2.item->key.obj_type == bi->key.obj_type) { if (tp2.item->key.obj_id == bi->key.obj_id && tp2.item->key.obj_type == bi->key.obj_type) {
tp = tp2; tp = tp2;
find_tree_end(tp.tree, &tree_end, &no_end); Status = find_tree_end(tp.tree, &tree_end, &no_end);
if (!NT_SUCCESS(Status)) {
ERR("find_tree_end returned %08lx\n", Status);
return Status;
}
} }
} }
} }
@ -2278,6 +2337,7 @@ static NTSTATUS commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tr
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
__attribute__((nonnull(1,2)))
NTSTATUS commit_batch_list(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, LIST_ENTRY* batchlist, PIRP Irp) { NTSTATUS commit_batch_list(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, LIST_ENTRY* batchlist, PIRP Irp) {
NTSTATUS Status; NTSTATUS Status;

View file

@ -953,7 +953,7 @@ NTSTATUS __stdcall pnp_removal(PVOID NotificationStructure, PVOID Context) {
TRACE("GUID_TARGET_DEVICE_QUERY_REMOVE\n"); TRACE("GUID_TARGET_DEVICE_QUERY_REMOVE\n");
if (pdode->vde && pdode->vde->mounted_device) if (pdode->vde && pdode->vde->mounted_device)
return pnp_query_remove_device(pdode->vde->mounted_device, NULL); pnp_query_remove_device(pdode->vde->mounted_device, NULL);
} }
return STATUS_SUCCESS; return STATUS_SUCCESS;

View file

@ -28,13 +28,14 @@ typedef struct {
_Function_class_(IO_COMPLETION_ROUTINE) _Function_class_(IO_COMPLETION_ROUTINE)
static NTSTATUS __stdcall write_data_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr); static NTSTATUS __stdcall write_data_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr);
static void remove_fcb_extent(fcb* fcb, extent* ext, LIST_ENTRY* rollback); static void remove_fcb_extent(fcb* fcb, extent* ext, LIST_ENTRY* rollback) __attribute__((nonnull(1, 2, 3)));
extern tPsUpdateDiskCounters fPsUpdateDiskCounters; extern tPsUpdateDiskCounters fPsUpdateDiskCounters;
extern tCcCopyWriteEx fCcCopyWriteEx; extern tCcCopyWriteEx fCcCopyWriteEx;
extern tFsRtlUpdateDiskCounters fFsRtlUpdateDiskCounters; extern tFsRtlUpdateDiskCounters fFsRtlUpdateDiskCounters;
extern bool diskacc; extern bool diskacc;
__attribute__((nonnull(1, 2, 4)))
bool find_data_address_in_chunk(device_extension* Vcb, chunk* c, uint64_t length, uint64_t* address) { bool find_data_address_in_chunk(device_extension* Vcb, chunk* c, uint64_t length, uint64_t* address) {
LIST_ENTRY* le; LIST_ENTRY* le;
space* s; space* s;
@ -86,6 +87,7 @@ bool find_data_address_in_chunk(device_extension* Vcb, chunk* c, uint64_t length
return false; return false;
} }
__attribute__((nonnull(1)))
chunk* get_chunk_from_address(device_extension* Vcb, uint64_t address) { chunk* get_chunk_from_address(device_extension* Vcb, uint64_t address) {
LIST_ENTRY* le2; LIST_ENTRY* le2;
@ -113,6 +115,7 @@ typedef struct {
device* device; device* device;
} stripe; } stripe;
__attribute__((nonnull(1)))
static uint64_t find_new_chunk_address(device_extension* Vcb, uint64_t size) { static uint64_t find_new_chunk_address(device_extension* Vcb, uint64_t size) {
uint64_t lastaddr; uint64_t lastaddr;
LIST_ENTRY* le; LIST_ENTRY* le;
@ -134,6 +137,7 @@ static uint64_t find_new_chunk_address(device_extension* Vcb, uint64_t size) {
return lastaddr; return lastaddr;
} }
__attribute__((nonnull(1,2)))
static bool find_new_dup_stripes(device_extension* Vcb, stripe* stripes, uint64_t max_stripe_size, bool full_size) { static bool find_new_dup_stripes(device_extension* Vcb, stripe* stripes, uint64_t max_stripe_size, bool full_size) {
uint64_t devusage = 0xffffffffffffffff; uint64_t devusage = 0xffffffffffffffff;
space *devdh1 = NULL, *devdh2 = NULL; space *devdh1 = NULL, *devdh2 = NULL;
@ -245,6 +249,7 @@ static bool find_new_dup_stripes(device_extension* Vcb, stripe* stripes, uint64_
return true; return true;
} }
__attribute__((nonnull(1,2)))
static bool find_new_stripe(device_extension* Vcb, stripe* stripes, uint16_t i, uint64_t max_stripe_size, bool allow_missing, bool full_size) { static bool find_new_stripe(device_extension* Vcb, stripe* stripes, uint16_t i, uint64_t max_stripe_size, bool allow_missing, bool full_size) {
uint64_t k, devusage = 0xffffffffffffffff; uint64_t k, devusage = 0xffffffffffffffff;
space* devdh = NULL; space* devdh = NULL;
@ -358,6 +363,7 @@ static bool find_new_stripe(device_extension* Vcb, stripe* stripes, uint16_t i,
return true; return true;
} }
__attribute__((nonnull(1,3)))
NTSTATUS alloc_chunk(device_extension* Vcb, uint64_t flags, chunk** pc, bool full_size) { NTSTATUS alloc_chunk(device_extension* Vcb, uint64_t flags, chunk** pc, bool full_size) {
NTSTATUS Status; NTSTATUS Status;
uint64_t max_stripe_size, max_chunk_size, stripe_size, stripe_length, factor; uint64_t max_stripe_size, max_chunk_size, stripe_size, stripe_length, factor;
@ -703,6 +709,7 @@ end:
return Status; return Status;
} }
__attribute__((nonnull(1,3,5,8)))
static NTSTATUS prepare_raid0_write(_Pre_satisfies_(_Curr_->chunk_item->num_stripes>0) _In_ chunk* c, _In_ uint64_t address, _In_reads_bytes_(length) void* data, static NTSTATUS prepare_raid0_write(_Pre_satisfies_(_Curr_->chunk_item->num_stripes>0) _In_ chunk* c, _In_ uint64_t address, _In_reads_bytes_(length) void* data,
_In_ uint32_t length, _In_ write_stripe* stripes, _In_ PIRP Irp, _In_ uint64_t irp_offset, _In_ write_data_context* wtc) { _In_ uint32_t length, _In_ write_stripe* stripes, _In_ PIRP Irp, _In_ uint64_t irp_offset, _In_ write_data_context* wtc) {
uint64_t startoff, endoff; uint64_t startoff, endoff;
@ -832,6 +839,7 @@ static NTSTATUS prepare_raid0_write(_Pre_satisfies_(_Curr_->chunk_item->num_stri
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
__attribute__((nonnull(1,3,5,8)))
static NTSTATUS prepare_raid10_write(_Pre_satisfies_(_Curr_->chunk_item->sub_stripes>0&&_Curr_->chunk_item->num_stripes>=_Curr_->chunk_item->sub_stripes) _In_ chunk* c, static NTSTATUS prepare_raid10_write(_Pre_satisfies_(_Curr_->chunk_item->sub_stripes>0&&_Curr_->chunk_item->num_stripes>=_Curr_->chunk_item->sub_stripes) _In_ chunk* c,
_In_ uint64_t address, _In_reads_bytes_(length) void* data, _In_ uint32_t length, _In_ write_stripe* stripes, _In_ uint64_t address, _In_reads_bytes_(length) void* data, _In_ uint32_t length, _In_ write_stripe* stripes,
_In_ PIRP Irp, _In_ uint64_t irp_offset, _In_ write_data_context* wtc) { _In_ PIRP Irp, _In_ uint64_t irp_offset, _In_ write_data_context* wtc) {
@ -971,7 +979,8 @@ static NTSTATUS prepare_raid10_write(_Pre_satisfies_(_Curr_->chunk_item->sub_str
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS add_partial_stripe(device_extension* Vcb, chunk *c, uint64_t address, uint32_t length, void* data) { __attribute__((nonnull(1,2,5)))
static NTSTATUS add_partial_stripe(device_extension* Vcb, chunk* c, uint64_t address, uint32_t length, void* data) {
NTSTATUS Status; NTSTATUS Status;
LIST_ENTRY* le; LIST_ENTRY* le;
partial_stripe* ps; partial_stripe* ps;
@ -991,10 +1000,10 @@ static NTSTATUS add_partial_stripe(device_extension* Vcb, chunk *c, uint64_t add
// update existing entry // update existing entry
RtlCopyMemory(ps->data + address - stripe_addr, data, length); RtlCopyMemory(ps->data + address - stripe_addr, data, length);
RtlClearBits(&ps->bmp, (ULONG)((address - stripe_addr) / Vcb->superblock.sector_size), length / Vcb->superblock.sector_size); RtlClearBits(&ps->bmp, (ULONG)((address - stripe_addr) >> Vcb->sector_shift), length >> Vcb->sector_shift);
// if now filled, flush // if now filled, flush
if (RtlAreBitsClear(&ps->bmp, 0, (ULONG)((num_data_stripes * c->chunk_item->stripe_length) / Vcb->superblock.sector_size))) { if (RtlAreBitsClear(&ps->bmp, 0, (ULONG)((num_data_stripes * c->chunk_item->stripe_length) >> Vcb->sector_shift))) {
Status = flush_partial_stripe(Vcb, c, ps); Status = flush_partial_stripe(Vcb, c, ps);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("flush_partial_stripe returned %08lx\n", Status); ERR("flush_partial_stripe returned %08lx\n", Status);
@ -1026,7 +1035,7 @@ static NTSTATUS add_partial_stripe(device_extension* Vcb, chunk *c, uint64_t add
goto end; goto end;
} }
ps->bmplen = (ULONG)(num_data_stripes * c->chunk_item->stripe_length) / Vcb->superblock.sector_size; ps->bmplen = (ULONG)(num_data_stripes * c->chunk_item->stripe_length) >> Vcb->sector_shift;
ps->address = stripe_addr; ps->address = stripe_addr;
ps->bmparr = ExAllocatePoolWithTag(NonPagedPool, (size_t)sector_align(((ps->bmplen / 8) + 1), sizeof(ULONG)), ALLOC_TAG); ps->bmparr = ExAllocatePoolWithTag(NonPagedPool, (size_t)sector_align(((ps->bmplen / 8) + 1), sizeof(ULONG)), ALLOC_TAG);
@ -1041,7 +1050,7 @@ static NTSTATUS add_partial_stripe(device_extension* Vcb, chunk *c, uint64_t add
RtlSetAllBits(&ps->bmp); RtlSetAllBits(&ps->bmp);
RtlCopyMemory(ps->data + address - stripe_addr, data, length); RtlCopyMemory(ps->data + address - stripe_addr, data, length);
RtlClearBits(&ps->bmp, (ULONG)((address - stripe_addr) / Vcb->superblock.sector_size), length / Vcb->superblock.sector_size); RtlClearBits(&ps->bmp, (ULONG)((address - stripe_addr) >> Vcb->sector_shift), length >> Vcb->sector_shift);
InsertHeadList(le->Blink, &ps->list_entry); InsertHeadList(le->Blink, &ps->list_entry);
@ -1058,6 +1067,7 @@ typedef struct {
PFN_NUMBER* pfns; PFN_NUMBER* pfns;
} log_stripe; } log_stripe;
__attribute__((nonnull(1,2,4,6,10)))
static NTSTATUS prepare_raid5_write(device_extension* Vcb, chunk* c, uint64_t address, void* data, uint32_t length, write_stripe* stripes, PIRP Irp, static NTSTATUS prepare_raid5_write(device_extension* Vcb, chunk* c, uint64_t address, void* data, uint32_t length, write_stripe* stripes, PIRP Irp,
uint64_t irp_offset, ULONG priority, write_data_context* wtc) { uint64_t irp_offset, ULONG priority, write_data_context* wtc) {
uint64_t startoff, endoff, parity_start, parity_end; uint64_t startoff, endoff, parity_start, parity_end;
@ -1456,6 +1466,7 @@ exit:
return Status; return Status;
} }
__attribute__((nonnull(1,2,4,6,10)))
static NTSTATUS prepare_raid6_write(device_extension* Vcb, chunk* c, uint64_t address, void* data, uint32_t length, write_stripe* stripes, PIRP Irp, static NTSTATUS prepare_raid6_write(device_extension* Vcb, chunk* c, uint64_t address, void* data, uint32_t length, write_stripe* stripes, PIRP Irp,
uint64_t irp_offset, ULONG priority, write_data_context* wtc) { uint64_t irp_offset, ULONG priority, write_data_context* wtc) {
uint64_t startoff, endoff, parity_start, parity_end; uint64_t startoff, endoff, parity_start, parity_end;
@ -1894,6 +1905,7 @@ exit:
return Status; return Status;
} }
__attribute__((nonnull(1,3,5)))
NTSTATUS write_data(_In_ device_extension* Vcb, _In_ uint64_t address, _In_reads_bytes_(length) void* data, _In_ uint32_t length, _In_ write_data_context* wtc, NTSTATUS write_data(_In_ device_extension* Vcb, _In_ uint64_t address, _In_reads_bytes_(length) void* data, _In_ uint32_t length, _In_ write_data_context* wtc,
_In_opt_ PIRP Irp, _In_opt_ chunk* c, _In_ bool file_write, _In_ uint64_t irp_offset, _In_ ULONG priority) { _In_opt_ PIRP Irp, _In_opt_ chunk* c, _In_ bool file_write, _In_ uint64_t irp_offset, _In_ ULONG priority) {
NTSTATUS Status; NTSTATUS Status;
@ -2163,6 +2175,7 @@ prepare_failed:
return Status; return Status;
} }
__attribute__((nonnull(1,4,5)))
void get_raid56_lock_range(chunk* c, uint64_t address, uint64_t length, uint64_t* lockaddr, uint64_t* locklen) { void get_raid56_lock_range(chunk* c, uint64_t address, uint64_t length, uint64_t* lockaddr, uint64_t* locklen) {
uint64_t startoff, endoff; uint64_t startoff, endoff;
uint16_t startoffstripe, endoffstripe, datastripes; uint16_t startoffstripe, endoffstripe, datastripes;
@ -2179,6 +2192,7 @@ void get_raid56_lock_range(chunk* c, uint64_t address, uint64_t length, uint64_t
*locklen = (endoff - startoff) * datastripes; *locklen = (endoff - startoff) * datastripes;
} }
__attribute__((nonnull(1,3)))
NTSTATUS write_data_complete(device_extension* Vcb, uint64_t address, void* data, uint32_t length, PIRP Irp, chunk* c, bool file_write, uint64_t irp_offset, ULONG priority) { NTSTATUS write_data_complete(device_extension* Vcb, uint64_t address, void* data, uint32_t length, PIRP Irp, chunk* c, bool file_write, uint64_t irp_offset, ULONG priority) {
write_data_context wtc; write_data_context wtc;
NTSTATUS Status; NTSTATUS Status;
@ -2261,6 +2275,7 @@ NTSTATUS write_data_complete(device_extension* Vcb, uint64_t address, void* data
return Status; return Status;
} }
__attribute__((nonnull(2,3)))
_Function_class_(IO_COMPLETION_ROUTINE) _Function_class_(IO_COMPLETION_ROUTINE)
static NTSTATUS __stdcall write_data_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) { static NTSTATUS __stdcall write_data_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
write_data_stripe* stripe = conptr; write_data_stripe* stripe = conptr;
@ -2304,6 +2319,7 @@ end:
return STATUS_MORE_PROCESSING_REQUIRED; return STATUS_MORE_PROCESSING_REQUIRED;
} }
__attribute__((nonnull(1)))
void free_write_data_stripes(write_data_context* wtc) { void free_write_data_stripes(write_data_context* wtc) {
LIST_ENTRY* le; LIST_ENTRY* le;
PMDL last_mdl = NULL; PMDL last_mdl = NULL;
@ -2364,6 +2380,7 @@ void free_write_data_stripes(write_data_context* wtc) {
} }
} }
__attribute__((nonnull(1,2,3)))
void add_extent(_In_ fcb* fcb, _In_ LIST_ENTRY* prevextle, _In_ __drv_aliasesMem extent* newext) { void add_extent(_In_ fcb* fcb, _In_ LIST_ENTRY* prevextle, _In_ __drv_aliasesMem extent* newext) {
LIST_ENTRY* le = prevextle->Flink; LIST_ENTRY* le = prevextle->Flink;
@ -2381,6 +2398,7 @@ void add_extent(_In_ fcb* fcb, _In_ LIST_ENTRY* prevextle, _In_ __drv_aliasesMem
InsertTailList(&fcb->extents, &newext->list_entry); InsertTailList(&fcb->extents, &newext->list_entry);
} }
__attribute__((nonnull(1,2,6)))
NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, uint64_t end_data, PIRP Irp, LIST_ENTRY* rollback) { NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, uint64_t end_data, PIRP Irp, LIST_ENTRY* rollback) {
NTSTATUS Status; NTSTATUS Status;
LIST_ENTRY* le; LIST_ENTRY* le;
@ -2390,15 +2408,15 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
while (le != &fcb->extents) { while (le != &fcb->extents) {
LIST_ENTRY* le2 = le->Flink; LIST_ENTRY* le2 = le->Flink;
extent* ext = CONTAINING_RECORD(le, extent, list_entry); extent* ext = CONTAINING_RECORD(le, extent, list_entry);
EXTENT_DATA* ed = &ext->extent_data;
EXTENT_DATA2* ed2 = NULL;
uint64_t len;
if (!ext->ignore) { if (!ext->ignore) {
if (ed->type != EXTENT_TYPE_INLINE) EXTENT_DATA* ed = &ext->extent_data;
ed2 = (EXTENT_DATA2*)ed->data; uint64_t len;
len = ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes; if (ed->type == EXTENT_TYPE_INLINE)
len = ed->decoded_size;
else
len = ((EXTENT_DATA2*)ed->data)->num_bytes;
if (ext->offset < end_data && ext->offset + len > start_data) { if (ext->offset < end_data && ext->offset + len > start_data) {
if (ed->type == EXTENT_TYPE_INLINE) { if (ed->type == EXTENT_TYPE_INLINE) {
@ -2414,7 +2432,9 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
#endif #endif
return STATUS_INTERNAL_ERROR; return STATUS_INTERNAL_ERROR;
} }
} else if (ed->type != EXTENT_TYPE_INLINE) { } else {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;
if (start_data <= ext->offset && end_data >= ext->offset + len) { // remove all if (start_data <= ext->offset && end_data >= ext->offset + len) { // remove all
if (ed2->size != 0) { if (ed2->size != 0) {
chunk* c; chunk* c;
@ -2474,7 +2494,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
if (ext->csum) { if (ext->csum) {
if (ed->compression == BTRFS_COMPRESSION_NONE) { if (ed->compression == BTRFS_COMPRESSION_NONE) {
newext->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(ned2->num_bytes * Vcb->csum_size / Vcb->superblock.sector_size), ALLOC_TAG); newext->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)((ned2->num_bytes * Vcb->csum_size) >> Vcb->sector_shift), ALLOC_TAG);
if (!newext->csum) { if (!newext->csum) {
ERR("out of memory\n"); ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2482,10 +2502,10 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
goto end; goto end;
} }
RtlCopyMemory(newext->csum, (uint8_t*)ext->csum + ((end_data - ext->offset) * Vcb->csum_size / Vcb->superblock.sector_size), RtlCopyMemory(newext->csum, (uint8_t*)ext->csum + (((end_data - ext->offset) * Vcb->csum_size) >> Vcb->sector_shift),
(ULONG)(ned2->num_bytes * Vcb->csum_size / Vcb->superblock.sector_size)); (ULONG)((ned2->num_bytes * Vcb->csum_size) >> Vcb->sector_shift));
} else { } else {
newext->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(ed2->size * Vcb->csum_size / Vcb->superblock.sector_size), ALLOC_TAG); newext->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)((ed2->size * Vcb->csum_size) >> Vcb->sector_shift), ALLOC_TAG);
if (!newext->csum) { if (!newext->csum) {
ERR("out of memory\n"); ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2493,7 +2513,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
goto end; goto end;
} }
RtlCopyMemory(newext->csum, ext->csum, (ULONG)(ed2->size * Vcb->csum_size / Vcb->superblock.sector_size)); RtlCopyMemory(newext->csum, ext->csum, (ULONG)((ed2->size * Vcb->csum_size) >> Vcb->sector_shift));
} }
} else } else
newext->csum = NULL; newext->csum = NULL;
@ -2538,7 +2558,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
if (ext->csum) { if (ext->csum) {
if (ed->compression == BTRFS_COMPRESSION_NONE) { if (ed->compression == BTRFS_COMPRESSION_NONE) {
newext->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(ned2->num_bytes * Vcb->csum_size / Vcb->superblock.sector_size), ALLOC_TAG); newext->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)((ned2->num_bytes * Vcb->csum_size) >> Vcb->sector_shift), ALLOC_TAG);
if (!newext->csum) { if (!newext->csum) {
ERR("out of memory\n"); ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2546,9 +2566,9 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
goto end; goto end;
} }
RtlCopyMemory(newext->csum, ext->csum, (ULONG)(ned2->num_bytes * Vcb->csum_size / Vcb->superblock.sector_size)); RtlCopyMemory(newext->csum, ext->csum, (ULONG)((ned2->num_bytes * Vcb->csum_size) >> Vcb->sector_shift));
} else { } else {
newext->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(ed2->size * Vcb->csum_size / Vcb->superblock.sector_size), ALLOC_TAG); newext->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)((ed2->size * Vcb->csum_size) >> Vcb->sector_shift), ALLOC_TAG);
if (!newext->csum) { if (!newext->csum) {
ERR("out of memory\n"); ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2556,7 +2576,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
goto end; goto end;
} }
RtlCopyMemory(newext->csum, ext->csum, (ULONG)(ed2->size * Vcb->csum_size / Vcb->superblock.sector_size)); RtlCopyMemory(newext->csum, ext->csum, (ULONG)((ed2->size * Vcb->csum_size) >> Vcb->sector_shift));
} }
} else } else
newext->csum = NULL; newext->csum = NULL;
@ -2643,7 +2663,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
if (ext->csum) { if (ext->csum) {
if (ed->compression == BTRFS_COMPRESSION_NONE) { if (ed->compression == BTRFS_COMPRESSION_NONE) {
newext1->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(neda2->num_bytes * Vcb->csum_size / Vcb->superblock.sector_size), ALLOC_TAG); newext1->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)((neda2->num_bytes * Vcb->csum_size) >> Vcb->sector_shift), ALLOC_TAG);
if (!newext1->csum) { if (!newext1->csum) {
ERR("out of memory\n"); ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2652,7 +2672,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
goto end; goto end;
} }
newext2->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(nedb2->num_bytes * Vcb->csum_size / Vcb->superblock.sector_size), ALLOC_TAG); newext2->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)((nedb2->num_bytes * Vcb->csum_size) >> Vcb->sector_shift), ALLOC_TAG);
if (!newext2->csum) { if (!newext2->csum) {
ERR("out of memory\n"); ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2662,11 +2682,11 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
goto end; goto end;
} }
RtlCopyMemory(newext1->csum, ext->csum, (ULONG)(neda2->num_bytes * Vcb->csum_size / Vcb->superblock.sector_size)); RtlCopyMemory(newext1->csum, ext->csum, (ULONG)((neda2->num_bytes * Vcb->csum_size) >> Vcb->sector_shift));
RtlCopyMemory(newext2->csum, (uint8_t*)ext->csum + ((end_data - ext->offset) * Vcb->csum_size / Vcb->superblock.sector_size), RtlCopyMemory(newext2->csum, (uint8_t*)ext->csum + (((end_data - ext->offset) * Vcb->csum_size) >> Vcb->sector_shift),
(ULONG)(nedb2->num_bytes * Vcb->csum_size / Vcb->superblock.sector_size)); (ULONG)((nedb2->num_bytes * Vcb->csum_size) >> Vcb->sector_shift));
} else { } else {
newext1->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(ed2->size * Vcb->csum_size / Vcb->superblock.sector_size), ALLOC_TAG); newext1->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)((ed2->size * Vcb->csum_size) >> Vcb->sector_shift), ALLOC_TAG);
if (!newext1->csum) { if (!newext1->csum) {
ERR("out of memory\n"); ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2675,7 +2695,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
goto end; goto end;
} }
newext2->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(ed2->size * Vcb->csum_size / Vcb->superblock.sector_size), ALLOC_TAG); newext2->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)((ed2->size * Vcb->csum_size) >> Vcb->sector_shift), ALLOC_TAG);
if (!newext2->csum) { if (!newext2->csum) {
ERR("out of memory\n"); ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2685,8 +2705,8 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
goto end; goto end;
} }
RtlCopyMemory(newext1->csum, ext->csum, (ULONG)(ed2->size * Vcb->csum_size / Vcb->superblock.sector_size)); RtlCopyMemory(newext1->csum, ext->csum, (ULONG)((ed2->size * Vcb->csum_size) >> Vcb->sector_shift));
RtlCopyMemory(newext2->csum, ext->csum, (ULONG)(ed2->size * Vcb->csum_size / Vcb->superblock.sector_size)); RtlCopyMemory(newext2->csum, ext->csum, (ULONG)((ed2->size * Vcb->csum_size) >> Vcb->sector_shift));
} }
} else { } else {
newext1->csum = NULL; newext1->csum = NULL;
@ -2714,7 +2734,8 @@ end:
return Status; return Status;
} }
void add_insert_extent_rollback(LIST_ENTRY* rollback, fcb* fcb, extent* ext) { __attribute__((nonnull(1,2,3)))
static void add_insert_extent_rollback(LIST_ENTRY* rollback, fcb* fcb, extent* ext) {
rollback_extent* re; rollback_extent* re;
re = ExAllocatePoolWithTag(NonPagedPool, sizeof(rollback_extent), ALLOC_TAG); re = ExAllocatePoolWithTag(NonPagedPool, sizeof(rollback_extent), ALLOC_TAG);
@ -2733,6 +2754,7 @@ void add_insert_extent_rollback(LIST_ENTRY* rollback, fcb* fcb, extent* ext) {
#pragma warning(push) #pragma warning(push)
#pragma warning(suppress: 28194) #pragma warning(suppress: 28194)
#endif #endif
__attribute__((nonnull(1,3,7)))
NTSTATUS add_extent_to_fcb(_In_ fcb* fcb, _In_ uint64_t offset, _In_reads_bytes_(edsize) EXTENT_DATA* ed, _In_ uint16_t edsize, NTSTATUS add_extent_to_fcb(_In_ fcb* fcb, _In_ uint64_t offset, _In_reads_bytes_(edsize) EXTENT_DATA* ed, _In_ uint16_t edsize,
_In_ bool unique, _In_opt_ _When_(return >= 0, __drv_aliasesMem) void* csum, _In_ LIST_ENTRY* rollback) { _In_ bool unique, _In_opt_ _When_(return >= 0, __drv_aliasesMem) void* csum, _In_ LIST_ENTRY* rollback) {
extent* ext; extent* ext;
@ -2776,6 +2798,7 @@ end:
#pragma warning(pop) #pragma warning(pop)
#endif #endif
__attribute__((nonnull(1, 2, 3)))
static void remove_fcb_extent(fcb* fcb, extent* ext, LIST_ENTRY* rollback) { static void remove_fcb_extent(fcb* fcb, extent* ext, LIST_ENTRY* rollback) {
if (!ext->ignore) { if (!ext->ignore) {
rollback_extent* re; rollback_extent* re;
@ -2797,6 +2820,7 @@ static void remove_fcb_extent(fcb* fcb, extent* ext, LIST_ENTRY* rollback) {
_Requires_lock_held_(c->lock) _Requires_lock_held_(c->lock)
_When_(return != 0, _Releases_lock_(c->lock)) _When_(return != 0, _Releases_lock_(c->lock))
__attribute__((nonnull(1,2,3,9)))
bool insert_extent_chunk(_In_ device_extension* Vcb, _In_ fcb* fcb, _In_ chunk* c, _In_ uint64_t start_data, _In_ uint64_t length, _In_ bool prealloc, _In_opt_ void* data, bool insert_extent_chunk(_In_ device_extension* Vcb, _In_ fcb* fcb, _In_ chunk* c, _In_ uint64_t start_data, _In_ uint64_t length, _In_ bool prealloc, _In_opt_ void* data,
_In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback, _In_ uint8_t compression, _In_ uint64_t decoded_size, _In_ bool file_write, _In_ uint64_t irp_offset) { _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback, _In_ uint8_t compression, _In_ uint64_t decoded_size, _In_ bool file_write, _In_ uint64_t irp_offset) {
uint64_t address; uint64_t address;
@ -2832,7 +2856,7 @@ bool insert_extent_chunk(_In_ device_extension* Vcb, _In_ fcb* fcb, _In_ chunk*
ed2->num_bytes = decoded_size; ed2->num_bytes = decoded_size;
if (!prealloc && data && !(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) { if (!prealloc && data && !(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) {
ULONG sl = (ULONG)(length / Vcb->superblock.sector_size); ULONG sl = (ULONG)(length >> Vcb->sector_shift);
csum = ExAllocatePoolWithTag(PagedPool, sl * Vcb->csum_size, ALLOC_TAG); csum = ExAllocatePoolWithTag(PagedPool, sl * Vcb->csum_size, ALLOC_TAG);
if (!csum) { if (!csum) {
@ -2855,7 +2879,7 @@ bool insert_extent_chunk(_In_ device_extension* Vcb, _In_ fcb* fcb, _In_ chunk*
ExFreePool(ed); ExFreePool(ed);
c->used += length; c->used += length;
space_list_subtract(c, false, address, length, rollback); space_list_subtract(c, address, length, rollback);
fcb->inode_item.st_blocks += decoded_size; fcb->inode_item.st_blocks += decoded_size;
@ -2881,6 +2905,7 @@ bool insert_extent_chunk(_In_ device_extension* Vcb, _In_ fcb* fcb, _In_ chunk*
return true; return true;
} }
__attribute__((nonnull(1,2,5,7,10)))
static bool try_extend_data(device_extension* Vcb, fcb* fcb, uint64_t start_data, uint64_t length, void* data, static bool try_extend_data(device_extension* Vcb, fcb* fcb, uint64_t start_data, uint64_t length, void* data,
PIRP Irp, uint64_t* written, bool file_write, uint64_t irp_offset, LIST_ENTRY* rollback) { PIRP Irp, uint64_t* written, bool file_write, uint64_t irp_offset, LIST_ENTRY* rollback) {
bool success = false; bool success = false;
@ -2973,6 +2998,7 @@ static bool try_extend_data(device_extension* Vcb, fcb* fcb, uint64_t start_data
return false; return false;
} }
__attribute__((nonnull(1)))
static NTSTATUS insert_chunk_fragmented(fcb* fcb, uint64_t start, uint64_t length, uint8_t* data, bool prealloc, LIST_ENTRY* rollback) { static NTSTATUS insert_chunk_fragmented(fcb* fcb, uint64_t start, uint64_t length, uint8_t* data, bool prealloc, LIST_ENTRY* rollback) {
LIST_ENTRY* le; LIST_ENTRY* le;
uint64_t flags = fcb->Vcb->data_flags; uint64_t flags = fcb->Vcb->data_flags;
@ -3029,6 +3055,7 @@ static NTSTATUS insert_chunk_fragmented(fcb* fcb, uint64_t start, uint64_t lengt
return length == 0 ? STATUS_SUCCESS : STATUS_DISK_FULL; return length == 0 ? STATUS_SUCCESS : STATUS_DISK_FULL;
} }
__attribute__((nonnull(1,4)))
static NTSTATUS insert_prealloc_extent(fcb* fcb, uint64_t start, uint64_t length, LIST_ENTRY* rollback) { static NTSTATUS insert_prealloc_extent(fcb* fcb, uint64_t start, uint64_t length, LIST_ENTRY* rollback) {
LIST_ENTRY* le; LIST_ENTRY* le;
chunk* c; chunk* c;
@ -3102,6 +3129,7 @@ end:
return Status; return Status;
} }
__attribute__((nonnull(1,2,5,9)))
static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, uint64_t start_data, uint64_t length, void* data, static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, uint64_t start_data, uint64_t length, void* data,
PIRP Irp, bool file_write, uint64_t irp_offset, LIST_ENTRY* rollback) { PIRP Irp, bool file_write, uint64_t irp_offset, LIST_ENTRY* rollback) {
NTSTATUS Status; NTSTATUS Status;
@ -3213,6 +3241,7 @@ static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, uint64_t start_da
return STATUS_DISK_FULL; return STATUS_DISK_FULL;
} }
__attribute__((nonnull(1,4)))
NTSTATUS truncate_file(fcb* fcb, uint64_t end, PIRP Irp, LIST_ENTRY* rollback) { NTSTATUS truncate_file(fcb* fcb, uint64_t end, PIRP Irp, LIST_ENTRY* rollback) {
NTSTATUS Status; NTSTATUS Status;
@ -3296,6 +3325,7 @@ NTSTATUS truncate_file(fcb* fcb, uint64_t end, PIRP Irp, LIST_ENTRY* rollback) {
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
__attribute__((nonnull(1,6)))
NTSTATUS extend_file(fcb* fcb, file_ref* fileref, uint64_t end, bool prealloc, PIRP Irp, LIST_ENTRY* rollback) { NTSTATUS extend_file(fcb* fcb, file_ref* fileref, uint64_t end, bool prealloc, PIRP Irp, LIST_ENTRY* rollback) {
uint64_t oldalloc, newalloc; uint64_t oldalloc, newalloc;
bool cur_inline; bool cur_inline;
@ -3529,6 +3559,7 @@ NTSTATUS extend_file(fcb* fcb, file_ref* fileref, uint64_t end, bool prealloc, P
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
__attribute__((nonnull(1,2,5,6,11)))
static NTSTATUS do_write_file_prealloc(fcb* fcb, extent* ext, uint64_t start_data, uint64_t end_data, void* data, uint64_t* written, static NTSTATUS do_write_file_prealloc(fcb* fcb, extent* ext, uint64_t start_data, uint64_t end_data, void* data, uint64_t* written,
PIRP Irp, bool file_write, uint64_t irp_offset, ULONG priority, LIST_ENTRY* rollback) { PIRP Irp, bool file_write, uint64_t irp_offset, ULONG priority, LIST_ENTRY* rollback) {
EXTENT_DATA* ed = &ext->extent_data; EXTENT_DATA* ed = &ext->extent_data;
@ -3557,7 +3588,7 @@ static NTSTATUS do_write_file_prealloc(fcb* fcb, extent* ext, uint64_t start_dat
} }
if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) { if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) {
ULONG sl = (ULONG)(ed2->num_bytes / fcb->Vcb->superblock.sector_size); ULONG sl = (ULONG)(ed2->num_bytes >> fcb->Vcb->sector_shift);
void* csum = ExAllocatePoolWithTag(PagedPool, sl * fcb->Vcb->csum_size, ALLOC_TAG); void* csum = ExAllocatePoolWithTag(PagedPool, sl * fcb->Vcb->csum_size, ALLOC_TAG);
if (!csum) { if (!csum) {
@ -3623,7 +3654,7 @@ static NTSTATUS do_write_file_prealloc(fcb* fcb, extent* ext, uint64_t start_dat
} }
if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) { if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) {
ULONG sl = (ULONG)((end_data - ext->offset) / fcb->Vcb->superblock.sector_size); ULONG sl = (ULONG)((end_data - ext->offset) >> fcb->Vcb->sector_shift);
void* csum = ExAllocatePoolWithTag(PagedPool, sl * fcb->Vcb->csum_size, ALLOC_TAG); void* csum = ExAllocatePoolWithTag(PagedPool, sl * fcb->Vcb->csum_size, ALLOC_TAG);
if (!csum) { if (!csum) {
@ -3713,7 +3744,7 @@ static NTSTATUS do_write_file_prealloc(fcb* fcb, extent* ext, uint64_t start_dat
} }
if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) { if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) {
ULONG sl = (ULONG)(ned2->num_bytes / fcb->Vcb->superblock.sector_size); ULONG sl = (ULONG)(ned2->num_bytes >> fcb->Vcb->sector_shift);
void* csum = ExAllocatePoolWithTag(PagedPool, sl * fcb->Vcb->csum_size, ALLOC_TAG); void* csum = ExAllocatePoolWithTag(PagedPool, sl * fcb->Vcb->csum_size, ALLOC_TAG);
if (!csum) { if (!csum) {
@ -3817,7 +3848,7 @@ static NTSTATUS do_write_file_prealloc(fcb* fcb, extent* ext, uint64_t start_dat
} }
if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) { if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) {
ULONG sl = (ULONG)((end_data - start_data) / fcb->Vcb->superblock.sector_size); ULONG sl = (ULONG)((end_data - start_data) >> fcb->Vcb->sector_shift);
void* csum = ExAllocatePoolWithTag(PagedPool, sl * fcb->Vcb->csum_size, ALLOC_TAG); void* csum = ExAllocatePoolWithTag(PagedPool, sl * fcb->Vcb->csum_size, ALLOC_TAG);
if (!csum) { if (!csum) {
@ -3888,6 +3919,7 @@ static NTSTATUS do_write_file_prealloc(fcb* fcb, extent* ext, uint64_t start_dat
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
__attribute__((nonnull(1, 4)))
NTSTATUS do_write_file(fcb* fcb, uint64_t start, uint64_t end_data, void* data, PIRP Irp, bool file_write, uint32_t irp_offset, LIST_ENTRY* rollback) { NTSTATUS do_write_file(fcb* fcb, uint64_t start, uint64_t end_data, void* data, PIRP Irp, bool file_write, uint32_t irp_offset, LIST_ENTRY* rollback) {
NTSTATUS Status; NTSTATUS Status;
LIST_ENTRY *le, *le2; LIST_ENTRY *le, *le2;
@ -3909,10 +3941,12 @@ NTSTATUS do_write_file(fcb* fcb, uint64_t start, uint64_t end_data, void* data,
if (!ext->ignore) { if (!ext->ignore) {
EXTENT_DATA* ed = &ext->extent_data; EXTENT_DATA* ed = &ext->extent_data;
EXTENT_DATA2* ed2 = ed->type == EXTENT_TYPE_INLINE ? NULL : (EXTENT_DATA2*)ed->data;
uint64_t len; uint64_t len;
len = ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes; if (ed->type == EXTENT_TYPE_INLINE)
len = ed->decoded_size;
else
len = ((EXTENT_DATA2*)ed->data)->num_bytes;
if (ext->offset + len <= start) if (ext->offset + len <= start)
goto nextitem; goto nextitem;
@ -3946,6 +3980,7 @@ NTSTATUS do_write_file(fcb* fcb, uint64_t start, uint64_t end_data, void* data,
} }
if (ed->type == EXTENT_TYPE_REGULAR) { if (ed->type == EXTENT_TYPE_REGULAR) {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;
uint64_t writeaddr = ed2->address + ed2->offset + start + written - ext->offset; uint64_t writeaddr = ed2->address + ed2->offset + start + written - ext->offset;
uint64_t write_len = min(len, length); uint64_t write_len = min(len, length);
chunk* c; chunk* c;
@ -3964,8 +3999,8 @@ NTSTATUS do_write_file(fcb* fcb, uint64_t start, uint64_t end_data, void* data,
// This shouldn't ever get called - nocow files should always also be nosum. // This shouldn't ever get called - nocow files should always also be nosum.
if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) { if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) {
do_calc_job(fcb->Vcb, (uint8_t*)data + written, (uint32_t)(write_len / fcb->Vcb->superblock.sector_size), do_calc_job(fcb->Vcb, (uint8_t*)data + written, (uint32_t)(write_len >> fcb->Vcb->sector_shift),
(uint8_t*)ext->csum + ((start + written - ext->offset) * fcb->Vcb->csum_size / fcb->Vcb->superblock.sector_size)); (uint8_t*)ext->csum + (((start + written - ext->offset) * fcb->Vcb->csum_size) >> fcb->Vcb->sector_shift));
ext->inserted = true; ext->inserted = true;
extents_changed = true; extents_changed = true;
@ -4052,6 +4087,7 @@ nextitem:
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
__attribute__((nonnull(1,2,4,5,11)))
NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void* buf, ULONG* length, bool paging_io, bool no_cache, NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void* buf, ULONG* length, bool paging_io, bool no_cache,
bool wait, bool deferred_write, bool write_irp, LIST_ENTRY* rollback) { bool wait, bool deferred_write, bool write_irp, LIST_ENTRY* rollback) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
@ -4542,6 +4578,7 @@ end:
return Status; return Status;
} }
__attribute__((nonnull(1,2)))
NTSTATUS write_file(device_extension* Vcb, PIRP Irp, bool wait, bool deferred_write) { NTSTATUS write_file(device_extension* Vcb, PIRP Irp, bool wait, bool deferred_write) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
void* buf; void* buf;
@ -4616,6 +4653,7 @@ exit:
_Dispatch_type_(IRP_MJ_WRITE) _Dispatch_type_(IRP_MJ_WRITE)
_Function_class_(DRIVER_DISPATCH) _Function_class_(DRIVER_DISPATCH)
__attribute__((nonnull(1,2)))
NTSTATUS __stdcall drv_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS __stdcall drv_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
NTSTATUS Status; NTSTATUS Status;
bool top_level; bool top_level;