[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
FILEVERSION 1,7,2,0
PRODUCTVERSION 1,7,2,0
FILEVERSION 1,7,3,0
PRODUCTVERSION 1,7,3,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -78,12 +78,12 @@ BEGIN
BLOCK "080904b0"
BEGIN
VALUE "FileDescription", "WinBtrfs shell extension"
VALUE "FileVersion", "1.7.2"
VALUE "FileVersion", "1.7.3"
VALUE "InternalName", "btrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-20"
VALUE "OriginalFilename", "shellbtrfs.dll"
VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "1.7.2"
VALUE "ProductVersion", "1.7.3"
END
END
BLOCK "VarFileInfo"
@ -221,7 +221,7 @@ BEGIN
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
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
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
@ -244,7 +244,7 @@ BEGIN
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
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
END
@ -376,7 +376,7 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,7,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
END

View file

@ -25,18 +25,18 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
// TEXTINCLUDE
//
1 TEXTINCLUDE
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
@ -51,8 +51,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,7,2,0
PRODUCTVERSION 1,7,2,0
FILEVERSION 1,7,3,0
PRODUCTVERSION 1,7,3,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -68,12 +68,12 @@ BEGIN
BLOCK "080904b0"
BEGIN
VALUE "FileDescription", "Btrfs utility DLL"
VALUE "FileVersion", "1.7.2"
VALUE "FileVersion", "1.7.3"
VALUE "InternalName", "ubtrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-20"
VALUE "OriginalFilename", "ubtrfs.dll"
VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "1.7.2"
VALUE "ProductVersion", "1.7.3"
END
END
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)) {
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;
}
@ -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 (find_metadata_address_in_chunk(Vcb, c2, &mr->new_address)) {
c2->used += Vcb->superblock.node_size;
space_list_subtract(c2, false, mr->new_address, Vcb->superblock.node_size, rollback);
space_list_subtract(c2, mr->new_address, Vcb->superblock.node_size, rollback);
release_chunk_lock(c2, Vcb);
newchunk = c2;
done = true;
@ -806,7 +806,7 @@ static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree
goto end;
} else {
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);
@ -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)) {
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;
}
@ -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 (find_data_address_in_chunk(Vcb, c2, dr->size, &dr->new_address)) {
c2->used += dr->size;
space_list_subtract(c2, false, dr->new_address, dr->size, &rollback);
space_list_subtract(c2, dr->new_address, dr->size, &rollback);
release_chunk_lock(c2, Vcb);
newchunk = c2;
done = true;
@ -1823,7 +1823,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* change
goto end;
} else {
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);
@ -1834,7 +1834,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* change
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);
if (!bmparr) {
@ -1843,7 +1843,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* change
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) {
ERR("out of memory\n");
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.offset >= dr->address + dr->size)
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 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),
tp.item->data + ((cs - tp.item->key.offset) * Vcb->csum_size / Vcb->superblock.sector_size),
(ULONG)((ce - cs) * 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->sector_shift),
(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)
break;
@ -1917,12 +1917,12 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c, bool* change
do {
ULONG rl;
if (size * Vcb->superblock.sector_size > BALANCE_UNIT)
rl = BALANCE_UNIT / Vcb->superblock.sector_size;
if (size << Vcb->sector_shift > BALANCE_UNIT)
rl = BALANCE_UNIT >> Vcb->sector_shift;
else
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);
if (!NT_SUCCESS(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;
}
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);
if (!NT_SUCCESS(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);
}
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->address + (index * Vcb->superblock.sector_size), runlength, NULL, 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->sector_shift), runlength, NULL, NULL);
// handle csum run
do {
ULONG rl;
if (runlength * Vcb->superblock.sector_size > BALANCE_UNIT)
rl = BALANCE_UNIT / Vcb->superblock.sector_size;
if (runlength << Vcb->sector_shift > BALANCE_UNIT)
rl = BALANCE_UNIT >> Vcb->sector_shift;
else
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);
if (!NT_SUCCESS(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;
}
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);
if (!NT_SUCCESS(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);
// handle final nocsum run
if (lastoff < dr->size / Vcb->superblock.sector_size) {
if (lastoff < dr->size >> Vcb->sector_shift) {
ULONG off = lastoff;
ULONG size = (ULONG)((dr->size / Vcb->superblock.sector_size) - lastoff);
ULONG size = (ULONG)((dr->size >> Vcb->sector_shift) - lastoff);
do {
ULONG rl;
if (size * Vcb->superblock.sector_size > BALANCE_UNIT)
rl = BALANCE_UNIT / Vcb->superblock.sector_size;
if (size << Vcb->sector_shift > BALANCE_UNIT)
rl = BALANCE_UNIT >> Vcb->sector_shift;
else
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);
if (!NT_SUCCESS(Status)) {
ERR("read_data returned %08lx\n", Status);
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);
if (!NT_SUCCESS(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
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.
#define DOE_START_PENDING 0x10
@ -244,6 +240,34 @@ static void get_system_root(system_root* sr) {
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) {
NTSTATUS Status;
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;
#endif
static const WCHAR dev_path1[] = L"\\Device\\Harddisk";
static const WCHAR dev_path2[] = L"\\Partition";
us.Buffer = symlink;
us.Length = 0;
us.Length = sizeof(dev_path1) - sizeof(WCHAR);
us.MaximumLength = sizeof(symlink);
Status = RtlUnicodeStringPrintf(&us, L"\\Device\\Harddisk%u\\Partition%u", disk_num, partition_num);
if (!NT_SUCCESS(Status)) {
ERR("RtlUnicodeStringPrintf returned %08lx\n", Status);
return;
}
RtlCopyMemory(symlink, dev_path1, sizeof(dev_path1) - sizeof(WCHAR));
append_int_to_us(&us, disk_num);
RtlCopyMemory(&us.Buffer[us.Length / sizeof(WCHAR)], dev_path2, sizeof(dev_path2) - sizeof(WCHAR));
us.Length += sizeof(dev_path2) - sizeof(WCHAR);
append_int_to_us(&us, partition_num);
Status = IoDeleteSymbolicLink(&us);
if (!NT_SUCCESS(Status))

View file

@ -48,11 +48,7 @@
#undef INITGUID
#endif
#ifdef _MSC_VER
#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 | \
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;
bool shutting_down = false;
ERESOURCE boot_lock;
bool is_windows_8;
extern uint64_t boot_subvol;
#ifdef _DEBUG
@ -597,9 +594,9 @@ static void calculate_total_space(_In_ device_extension* Vcb, _Out_ uint64_t* to
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);
}
@ -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) {
NTSTATUS Status;
root* r;
tree* t = NULL;
ROOT_ITEM* ri;
traverse_ptr tp;
@ -1217,29 +1213,10 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi
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);
if (!ri) {
ERR("out of memory\n");
if (t)
ExFreePool(t);
ExFreePool(r->nonpaged);
ExFreePool(r);
return STATUS_INSUFFICIENT_RESOURCES;
@ -1248,7 +1225,7 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi
r->id = id;
r->treeholder.address = 0;
r->treeholder.generation = Vcb->superblock.generation;
r->treeholder.tree = t;
r->treeholder.tree = NULL;
r->lastinode = 0;
r->dirty = false;
r->received = false;
@ -1272,10 +1249,6 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi
if (!NT_SUCCESS(Status)) {
ERR("insert_tree_item returned %08lx\n", Status);
ExFreePool(ri);
if (t)
ExFreePool(t);
ExFreePool(r->nonpaged);
ExFreePool(r);
return Status;
@ -1286,6 +1259,26 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi
InsertTailList(&Vcb->roots, &r->list_entry);
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));
t->header.fs_uuid = tp.tree->header.fs_uuid;
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
if (fileref->fcb->inode_item.st_nlink == 1) {
ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, true);
send_notification_fileref(fileref, filter_match, action, stream);
ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
return;
}
@ -2417,7 +2412,6 @@ static NTSTATUS __stdcall drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIR
// messages belonging to other devices.
if (FileObject && FileObject->FsContext) {
LONG oc;
ccb* ccb;
file_ref* fileref;
bool locked = true;
@ -2439,13 +2433,6 @@ static NTSTATUS __stdcall drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIR
if (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)
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
}
if (fileref && (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;
if (fileref) {
LONG oc = InterlockedDecrement(&fileref->open_count);
#ifdef DEBUG_FCB_REFCOUNTS
ERR("fileref %p: open_count now %i\n", fileref, oc);
#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);
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;
}
InitializeListHead(&rollback);
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);
} else if (fileref->delete_on_close && fileref != fcb->Vcb->root_fileref && fcb != fcb->Vcb->volume_fcb) {
LIST_ENTRY rollback;
clear_rollback(&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) {
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);
}
InitializeListHead(&rollback);
ExReleaseResourceLite(fcb->Header.Resource);
locked = false;
if (!fileref->fcb->ads || fileref->dc) {
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);
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)
CcUninitializeCacheMap(FileObject, NULL, NULL);
if (fcb->Vcb && fcb != fcb->Vcb->volume_fcb)
CcUninitializeCacheMap(FileObject, NULL, NULL);
}
}
if (locked)
@ -2860,6 +2854,8 @@ static NTSTATUS read_superblock(_In_ device_extension* Vcb, _In_ PDEVICE_OBJECT
if (sb->sector_size == 0)
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)
WARN("invalid node size %x\n", sb->node_size);
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 -
// evidently Linux assumes the chunk at 0 is always SINGLE.
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) {
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]);
#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) {
@ -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);
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) {
@ -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);
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
@ -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_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;
}
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) {
PIO_STACK_LOCATION IrpSp;
PDEVICE_OBJECT NewDeviceObject = NULL;
@ -4561,6 +4568,8 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
if (Vcb->options.readonly)
Vcb->readonly = true;
calculate_sector_shift(Vcb);
Vcb->superblock.generation++;
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;
}
Status = STATUS_SUCCESS;
InterlockedIncrement(&Vcb->open_files); // so pnp_surprise_removal doesn't uninit the device while we're still using it
le = Vcb->devices.Flink;
@ -5877,17 +5888,24 @@ static void init_serial(bool first_time) {
#if !defined(__REACTOS__) && (defined(_X86_) || defined(_AMD64_))
static void check_cpu() {
unsigned int cpuInfo[4];
bool have_sse42;
#ifndef _MSC_VER
__get_cpuid(1, &cpuInfo[0], &cpuInfo[1], &cpuInfo[2], &cpuInfo[3]);
have_sse42 = cpuInfo[2] & bit_SSE4_2;
have_sse2 = cpuInfo[3] & bit_SSE2;
{
uint32_t eax, ebx, ecx, edx;
__cpuid(1, eax, ebx, ecx, edx);
have_sse42 = ecx & bit_SSE4_2;
have_sse2 = edx & bit_SSE2;
}
#else
__cpuid(cpuInfo, 1);
have_sse42 = cpuInfo[2] & (1 << 20);
have_sse2 = cpuInfo[3] & (1 << 26);
{
unsigned int cpu_info[4];
__cpuid(cpu_info, 1);
have_sse42 = cpu_info[2] & (1 << 20);
have_sse2 = cpu_info[3] & (1 << 26);
}
#endif
if (have_sse42) {
@ -6091,7 +6109,7 @@ NTSTATUS __stdcall AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT Physica
*anp = ')';
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)) {
ERR("IoCreateDevice returned %08lx\n", Status);
goto end2;
@ -6162,6 +6180,17 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S
HANDLE regh;
OBJECT_ATTRIBUTES oa, system_thread_attributes;
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(&gid_map_list);
@ -6201,7 +6230,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S
check_cpu();
#endif
if (WdmlibRtlIsNtDdiVersionAvailable(NTDDI_WIN8)) {
if (ver.dwMajorVersion > 6 || (ver.dwMajorVersion == 6 && ver.dwMinorVersion >= 2)) { // Windows 8 or above
UNICODE_STRING name;
tPsIsDiskCountersEnabled fPsIsDiskCountersEnabled;
@ -6241,7 +6270,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S
fFsRtlCheckLockForOplockRequest = NULL;
}
if (WdmlibRtlIsNtDdiVersionAvailable(NTDDI_WIN7)) {
if (ver.dwMajorVersion > 6 || (ver.dwMajorVersion == 6 && ver.dwMinorVersion >= 1)) { // Windows 7 or above
UNICODE_STRING name;
RtlInitUnicodeString(&name, L"IoUnregisterPlugPlayNotificationEx");
@ -6254,7 +6283,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S
fFsRtlAreThereCurrentOrInProgressFileLocks = NULL;
}
if (WdmlibRtlIsNtDdiVersionAvailable(NTDDI_VISTA)) {
if (ver.dwMajorVersion >= 6) { // Windows Vista or above
UNICODE_STRING name;
RtlInitUnicodeString(&name, L"FsRtlGetEcpListFromIrp");

View file

@ -10,7 +10,7 @@ Signature = "$Windows NT$"
Class = Volume
ClassGuid = {71a27cdd-812a-11d0-bec7-08002be2092f}
Provider = %Me%
DriverVer = 04/10/2020,1.7.2.0
DriverVer = 05/24/2020,1.7.3.0
CatalogFile = btrfs.cat
[DestinationDirs]

View file

@ -25,18 +25,18 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
// TEXTINCLUDE
//
1 TEXTINCLUDE
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
@ -51,8 +51,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,7,2,0
PRODUCTVERSION 1,7,2,0
FILEVERSION 1,7,3,0
PRODUCTVERSION 1,7,3,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -68,12 +68,12 @@ BEGIN
BLOCK "080904b0"
BEGIN
VALUE "FileDescription", "WinBtrfs"
VALUE "FileVersion", "1.7.2"
VALUE "FileVersion", "1.7.3"
VALUE "InternalName", "btrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-20"
VALUE "OriginalFilename", "btrfs.sys"
VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "1.7.2"
VALUE "ProductVersion", "1.7.3"
END
END
BLOCK "VarFileInfo"

View file

@ -775,6 +775,7 @@ typedef struct _device_extension {
#endif
uint64_t devices_loaded;
superblock superblock;
unsigned int sector_shift;
unsigned int csum_size;
bool readonly;
bool removing;
@ -1291,25 +1292,30 @@ static const char lxdev[] = "$LXDEV";
// in treefuncs.c
NTSTATUS find_item(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _Out_ traverse_ptr* tp,
_In_ const KEY* searchkey, _In_ bool ignore, _In_opt_ PIRP Irp);
NTSTATUS find_item_to_level(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, bool ignore, uint8_t level, 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);
bool find_prev_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* prev_tp, PIRP Irp);
void free_trees(device_extension* Vcb);
_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) __attribute__((nonnull(1,2,3,4)));
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) __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,
_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);
NTSTATUS delete_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _Inout_ traverse_ptr* tp);
void free_tree(tree* t);
NTSTATUS load_tree(device_extension* Vcb, uint64_t addr, uint8_t* buf, root* r, tree** pt);
NTSTATUS do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, PIRP Irp);
void clear_rollback(LIST_ENTRY* rollback);
void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback);
void free_trees_root(device_extension* Vcb, root* r);
void add_rollback(_In_ LIST_ENTRY* rollback, _In_ enum rollback_type type, _In_ __drv_aliasesMem void* ptr);
NTSTATUS commit_batch_list(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, LIST_ENTRY* batchlist, PIRP Irp);
void clear_batch_list(device_extension* Vcb, LIST_ENTRY* batchlist);
NTSTATUS skip_to_difference(device_extension* Vcb, traverse_ptr* tp, traverse_ptr* tp2, bool* ended1, bool* ended2);
_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) __attribute__((nonnull(1,2)));
void free_tree(tree* t) __attribute__((nonnull(1)));
NTSTATUS load_tree(device_extension* Vcb, uint64_t addr, uint8_t* buf, root* r, tree** pt) __attribute__((nonnull(1,3,4,5)));
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 clear_rollback(LIST_ENTRY* rollback) __attribute__((nonnull(1)));
void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) __attribute__((nonnull(1,2)));
void free_trees_root(device_extension* Vcb, root* r) __attribute__((nonnull(1,2)));
void add_rollback(_In_ LIST_ENTRY* rollback, _In_ enum rollback_type type, _In_ __drv_aliasesMem void* ptr) __attribute__((nonnull(1,3)));
NTSTATUS commit_batch_list(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb,
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
NTSTATUS remove_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath);
@ -1335,35 +1341,36 @@ void init_cache();
extern CACHE_MANAGER_CALLBACKS cache_callbacks;
// 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,
bool wait, bool deferred_write, bool write_irp, LIST_ENTRY* rollback);
NTSTATUS truncate_file(fcb* fcb, uint64_t end, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS extend_file(fcb* fcb, file_ref* fileref, uint64_t end, bool prealloc, 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);
chunk* get_chunk_from_address(device_extension* Vcb, uint64_t address);
NTSTATUS alloc_chunk(device_extension* Vcb, uint64_t flags, chunk** pc, bool full_size);
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) __attribute__((nonnull(1,4)));
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) __attribute__((nonnull(1,2,6)));
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) __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,
_In_opt_ PIRP Irp, _In_opt_ chunk* c, _In_ bool file_write, _In_ uint64_t irp_offset, _In_ 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);
void free_write_data_stripes(write_data_context* wtc);
_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) __attribute__((nonnull(1,3)));
void free_write_data_stripes(write_data_context* wtc) __attribute__((nonnull(1)));
_Dispatch_type_(IRP_MJ_WRITE)
_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)
_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,
_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);
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) __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);
bool find_data_address_in_chunk(device_extension* Vcb, chunk* c, uint64_t length, uint64_t* address);
void get_raid56_lock_range(chunk* c, uint64_t address, uint64_t length, uint64_t* lockaddr, uint64_t* locklen);
void add_insert_extent_rollback(LIST_ENTRY* rollback, fcb* fcb, extent* ext);
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) __attribute__((nonnull(1, 2, 4)));
void get_raid56_lock_range(chunk* c, uint64_t address, uint64_t length, uint64_t* lockaddr, uint64_t* locklen) __attribute__((nonnull(1,4,5)));
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);
void add_extent(_In_ fcb* fcb, _In_ LIST_ENTRY* prevextle, _In_ __drv_aliasesMem extent* newext);
_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) __attribute__((nonnull(1,2,3)));
// 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,
_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);
NTSTATUS read_file(fcb* fcb, uint8_t* data, uint64_t start, uint64_t length, ULONG* pbr, PIRP Irp);
NTSTATUS read_stream(fcb* fcb, uint8_t* data, uint64_t start, ULONG length, ULONG* pbr);
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) __attribute__((nonnull(1, 2)));
NTSTATUS do_read(PIRP Irp, bool wait, ULONG* bytes_read);
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);
@ -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);
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_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_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);
// 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)
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);
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)) {
c = c2;
c->used += buflen;
space_list_subtract(c, false, address, buflen, rollback);
space_list_subtract(c, address, buflen, rollback);
release_chunk_lock(c2, fcb->Vcb);
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)) {
c = c2;
c->used += buflen;
space_list_subtract(c, false, address, buflen, rollback);
space_list_subtract(c, address, buflen, rollback);
}
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
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);
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;
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) {
ERR("out of memory\n");
ExFreePool(ed);
@ -1207,8 +1207,8 @@ NTSTATUS write_compressed(fcb* fcb, uint64_t start_data, uint64_t end_data, void
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(csum2, (uint8_t*)csum + ((extaddr - address) * fcb->Vcb->csum_size / fcb->Vcb->superblock.sector_size),
parts[i].outlen * 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->sector_shift);
} else
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_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 {
LARGE_INTEGER CreationTime;
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)
j = 0;
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)) {
ERR("checksum not found for %I64x\n", 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->sector_shift));
return STATUS_INTERNAL_ERROR;
}
@ -2046,23 +2050,29 @@ static NTSTATUS file_create_parse_ea(fcb* fcb, FILE_FULL_EA_INFORMATION* ea) {
goto end;
}
RtlCopyMemory(&val, item->value.Buffer, sizeof(uint32_t));
if (fcb->type != BTRFS_TYPE_DIRECTORY)
allowed |= __S_IFIFO | __S_IFCHR | __S_IFBLK | __S_IFSOCK;
val = *(uint32_t*)item->value.Buffer;
fcb->inode_item.st_mode &= ~allowed;
fcb->inode_item.st_mode |= val & allowed;
if (fcb->type != BTRFS_TYPE_DIRECTORY) {
if ((fcb->inode_item.st_mode & __S_IFCHR) == __S_IFCHR)
if (__S_ISTYPE(val, __S_IFCHR)) {
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;
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;
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->inode_item.st_mode &= ~__S_IFMT;
fcb->inode_item.st_mode |= __S_IFSOCK;
}
}
RemoveEntryList(&item->list_entry);
@ -2718,7 +2728,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
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);
return STATUS_ACCESS_DENIED;
}
@ -3011,8 +3021,10 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R
if (Vcb->readonly)
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;
}
if (fFsRtlGetEcpListFromIrp && fFsRtlGetNextExtraCreateParameter) {
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) {
fileref->fcb->inode_item.st_mode &= ~(__S_IFIFO | __S_IFCHR | __S_IFBLK | __S_IFSOCK);
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 ||
@ -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];
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);
if (!ext->csum) {
@ -3633,8 +3646,9 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO
sf = sf->parent;
}
readonly = (!fileref->fcb->ads && fileref->fcb->atts & FILE_ATTRIBUTE_READONLY) || (fileref->fcb->ads && fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY) ||
is_subvol_readonly(fileref->fcb->subvol, Irp) || fileref->fcb == Vcb->dummy_fcb || Vcb->readonly;
readonly = (!fileref->fcb->ads && fileref->fcb->atts & FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE)) ||
(fileref->fcb->ads && fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE)) ||
is_subvol_readonly(fileref->fcb->subvol, Irp) || fileref->fcb == Vcb->dummy_fcb || Vcb->readonly;
if (options & FILE_DELETE_ON_CLOSE && (fileref == Vcb->root_fileref || readonly)) {
free_fileref(fileref);
@ -4847,6 +4861,11 @@ NTSTATUS __stdcall drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
flags &= ~SL_STOP_ON_SYMLINK;
}
if (flags & SL_IGNORE_READONLY_ATTRIBUTE) {
TRACE("SL_IGNORE_READONLY_ATTRIBUTE\n");
flags &= ~SL_IGNORE_READONLY_ATTRIBUTE;
}
if (flags)
WARN("unknown flags: %x\n", flags);
} else {

View file

@ -1024,7 +1024,7 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, uint64_t address, uint6
}
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;
}
@ -1090,7 +1090,7 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, uint64_t address, uint6
}
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;
}
@ -1296,7 +1296,7 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, uint64_t address, uint6
}
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;
}
@ -1379,7 +1379,7 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, uint64_t address, uint6
}
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;
}
@ -1505,7 +1505,7 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, uint64_t address, uint6
}
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;
}

View file

@ -566,7 +566,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
else
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);
if (!ext2->csum) {
@ -1719,7 +1719,7 @@ static NTSTATUS rename_stream_to_file(device_extension* Vcb, file_ref* fileref,
}
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);
if (!newbuf) {
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) {
LIST_ENTRY* le;
ULONG type;
if (Vcb->trim && !Vcb->options.no_trim) {
if (c->chunk_item->type & BLOCK_FLAG_DUPLICATE)
type = BLOCK_FLAG_DUPLICATE;
else if (c->chunk_item->type & BLOCK_FLAG_RAID0)
type = BLOCK_FLAG_RAID0;
else if (c->chunk_item->type & BLOCK_FLAG_RAID1)
type = BLOCK_FLAG_DUPLICATE;
else if (c->chunk_item->type & BLOCK_FLAG_RAID10)
type = BLOCK_FLAG_RAID10;
else if (c->chunk_item->type & BLOCK_FLAG_RAID5)
type = BLOCK_FLAG_RAID5;
else if (c->chunk_item->type & BLOCK_FLAG_RAID6)
type = BLOCK_FLAG_RAID6;
else if (c->chunk_item->type & BLOCK_FLAG_RAID1C3)
type = BLOCK_FLAG_DUPLICATE;
else if (c->chunk_item->type & BLOCK_FLAG_RAID1C4)
type = BLOCK_FLAG_DUPLICATE;
else // SINGLE
type = BLOCK_FLAG_DUPLICATE;
}
if (c->chunk_item->type & BLOCK_FLAG_DUPLICATE)
type = BLOCK_FLAG_DUPLICATE;
else if (c->chunk_item->type & BLOCK_FLAG_RAID0)
type = BLOCK_FLAG_RAID0;
else if (c->chunk_item->type & BLOCK_FLAG_RAID1)
type = BLOCK_FLAG_DUPLICATE;
else if (c->chunk_item->type & BLOCK_FLAG_RAID10)
type = BLOCK_FLAG_RAID10;
else if (c->chunk_item->type & BLOCK_FLAG_RAID5)
type = BLOCK_FLAG_RAID5;
else if (c->chunk_item->type & BLOCK_FLAG_RAID6)
type = BLOCK_FLAG_RAID6;
else if (c->chunk_item->type & BLOCK_FLAG_RAID1C3)
type = BLOCK_FLAG_DUPLICATE;
else if (c->chunk_item->type & BLOCK_FLAG_RAID1C4)
type = BLOCK_FLAG_DUPLICATE;
else // SINGLE
type = BLOCK_FLAG_DUPLICATE;
while (!IsListEmpty(&c->deleting)) {
space* s = CONTAINING_RECORD(c->deleting.Flink, space, list_entry);
le = c->deleting.Flink;
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];
if (type == BLOCK_FLAG_DUPLICATE) {
@ -270,8 +270,7 @@ static void clean_space_cache_chunk(device_extension* Vcb, chunk* c) {
// FIXME - RAID5(?), RAID6(?)
}
RemoveEntryList(&s->list_entry);
ExFreePool(s);
le = le->Flink;
}
}
@ -414,8 +413,18 @@ static void clean_space_cache(device_extension* Vcb) {
if (c->space_changed) {
acquire_chunk_lock(c, Vcb);
if (c->space_changed)
clean_space_cache_chunk(Vcb, c);
if (c->space_changed) {
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;
@ -725,7 +734,7 @@ static bool insert_tree_extent_skinny(device_extension* Vcb, uint8_t level, uint
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);
@ -857,7 +866,7 @@ static bool insert_tree_extent(device_extension* Vcb, uint8_t level, uint64_t ro
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);
@ -2639,7 +2648,7 @@ void add_checksum_entry(device_extension* Vcb, uint64_t address, ULONG length, v
length2 -= il;
if (length2 > 0) {
off += il * Vcb->superblock.sector_size;
off += (uint64_t)il << Vcb->sector_shift;
data = (uint8_t*)data + (il * Vcb->csum_size);
}
} 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?
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;
else
startaddr = address;
searchkey.obj_id = EXTENT_CSUM_ID;
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);
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;
if (tp.item->key.offset + (tplen * Vcb->superblock.sector_size) >= address + (length * Vcb->superblock.sector_size))
endaddr = tp.item->key.offset + (tplen * 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->sector_shift);
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("startaddr = %I64x\n", startaddr);
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);
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) {
if (tp.item->key.offset >= startaddr) {
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);
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);
@ -2737,11 +2746,11 @@ void add_checksum_entry(device_extension* Vcb, uint64_t address, ULONG length, v
}
if (!csum) { // deleted
RtlSetBits(&bmp, (ULONG)((address - startaddr) / Vcb->superblock.sector_size), length);
RtlSetBits(&bmp, (ULONG)((address - startaddr) >> Vcb->sector_shift), length);
} 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);
RtlClearBits(&bmp, (ULONG)((address - startaddr) / Vcb->superblock.sector_size), length);
RtlClearBits(&bmp, (ULONG)((address - startaddr) >> Vcb->sector_shift), length);
}
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);
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);
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) {
ULONG level, max_level;
uint32_t min_size;
uint32_t min_size, min_size_fst;
bool empty, done_deletions = false;
NTSTATUS Status;
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_fst = (Vcb->superblock.node_size - sizeof(tree_header)) / 4;
for (level = 0; level <= max_level; level++) {
LIST_ENTRY* le;
@ -3779,8 +3789,9 @@ static NTSTATUS do_splits(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback)
while (le != &Vcb->trees) {
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 &&
t->root->id != BTRFS_ROOT_FREE_SPACE && is_tree_unique(Vcb, t, Irp)) {
if (t->write && t->header.level == level && t->header.num_items > 0 && t->parent &&
((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;
do {
@ -4649,7 +4660,7 @@ cont:
}
if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM))
add_checksum_entry(fcb->Vcb, er->address, (ULONG)(er->skip_start / fcb->Vcb->superblock.sector_size), NULL, NULL);
add_checksum_entry(fcb->Vcb, er->address, (ULONG)(er->skip_start >> fcb->Vcb->sector_shift), NULL, NULL);
acquire_chunk_lock(er->chunk, fcb->Vcb);
@ -4703,7 +4714,7 @@ cont:
}
if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM))
add_checksum_entry(fcb->Vcb, er->address + er->length - er->skip_end, (ULONG)(er->skip_end / fcb->Vcb->superblock.sector_size), NULL, NULL);
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);
@ -4902,9 +4913,9 @@ NTSTATUS flush_fcb(fcb* fcb, bool cache, LIST_ENTRY* batchlist, PIRP Irp) {
if (ed2->size > 0) { // not sparse
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
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;
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;
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;
}
RtlCopyMemory(csum, ext->csum, (ULONG)(ed2->num_bytes * fcb->Vcb->csum_size / fcb->Vcb->superblock.sector_size));
RtlCopyMemory((uint8_t*)csum + (ed2->num_bytes * fcb->Vcb->csum_size / fcb->Vcb->superblock.sector_size), nextext->csum,
(ULONG)(ned2->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->sector_shift), nextext->csum,
(ULONG)((ned2->num_bytes * fcb->Vcb->csum_size) >> fcb->Vcb->sector_shift));
ExFreePool(ext->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) {
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];
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;
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),
readlen * Vcb->superblock.sector_size, ps->data + (offset * Vcb->superblock.sector_size), false);
Status = sync_read_phys(c->devices[stripe]->devobj, c->devices[stripe]->fileobj, cis[stripe].offset + startoff + ((offset % sl) << Vcb->sector_shift),
readlen << Vcb->sector_shift, ps->data + (offset << Vcb->sector_shift), false);
if (!NT_SUCCESS(Status)) {
ERR("sync_read_phys returned %08lx\n", Status);
return Status;
@ -5758,7 +5769,7 @@ static NTSTATUS partial_stripe_read(device_extension* Vcb, chunk* c, partial_str
uint16_t i;
uint8_t* scratch;
scratch = ExAllocatePoolWithTag(NonPagedPool, readlen * Vcb->superblock.sector_size, ALLOC_TAG);
scratch = ExAllocatePoolWithTag(NonPagedPool, readlen << Vcb->sector_shift, ALLOC_TAG);
if (!scratch) {
ERR("out of memory\n");
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)) {
Status = sync_read_phys(c->devices[i]->devobj, c->devices[i]->fileobj, cis[i].offset + startoff + ((offset % sl) * Vcb->superblock.sector_size),
readlen * Vcb->superblock.sector_size, ps->data + (offset * Vcb->superblock.sector_size), false);
Status = sync_read_phys(c->devices[i]->devobj, c->devices[i]->fileobj, cis[i].offset + startoff + ((offset % sl) << Vcb->sector_shift),
readlen << Vcb->sector_shift, ps->data + (offset << Vcb->sector_shift), false);
if (!NT_SUCCESS(Status)) {
ERR("sync_read_phys returned %08lx\n", Status);
ExFreePool(scratch);
return Status;
}
} else {
Status = sync_read_phys(c->devices[i]->devobj, c->devices[i]->fileobj, cis[i].offset + startoff + ((offset % sl) * Vcb->superblock.sector_size),
readlen * Vcb->superblock.sector_size, scratch, false);
Status = sync_read_phys(c->devices[i]->devobj, c->devices[i]->fileobj, cis[i].offset + startoff + ((offset % sl) << Vcb->sector_shift),
readlen << Vcb->sector_shift, scratch, false);
if (!NT_SUCCESS(Status)) {
ERR("sync_read_phys returned %08lx\n", Status);
ExFreePool(scratch);
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;
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) {
ERR("out of memory\n");
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++) {
if (i != stripe) {
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),
readlen * Vcb->superblock.sector_size, scratch + (k * readlen * Vcb->superblock.sector_size), false);
Status = sync_read_phys(c->devices[i]->devobj, c->devices[i]->fileobj, cis[i].offset + startoff + ((offset % sl) << Vcb->sector_shift),
readlen << Vcb->sector_shift, scratch + (k * readlen << Vcb->sector_shift), false);
if (!NT_SUCCESS(Status)) {
ERR("sync_read_phys returned %08lx\n", Status);
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++) {
if (k != logstripe) {
if (k == 0 || (k == 1 && logstripe == 0)) {
RtlCopyMemory(ps->data + (offset * Vcb->superblock.sector_size), scratch + (k * readlen * Vcb->superblock.sector_size),
readlen * Vcb->superblock.sector_size);
RtlCopyMemory(ps->data + (offset << Vcb->sector_shift), scratch + (k * readlen << Vcb->sector_shift),
readlen << Vcb->sector_shift);
} else {
do_xor(ps->data + (offset * Vcb->superblock.sector_size), scratch + (k * readlen * Vcb->superblock.sector_size),
readlen * Vcb->superblock.sector_size);
do_xor(ps->data + (offset << Vcb->sector_shift), scratch + (k * readlen << Vcb->sector_shift),
readlen << Vcb->sector_shift);
}
}
}
} else {
raid6_recover2(scratch, c->chunk_item->num_stripes, readlen * Vcb->superblock.sector_size, logstripe,
error_stripe, scratch + (c->chunk_item->num_stripes * readlen * Vcb->superblock.sector_size));
raid6_recover2(scratch, c->chunk_item->num_stripes, readlen << Vcb->sector_shift, logstripe,
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),
readlen * Vcb->superblock.sector_size);
RtlCopyMemory(ps->data + (offset << Vcb->sector_shift), scratch + (c->chunk_item->num_stripes * readlen << Vcb->sector_shift),
readlen << Vcb->sector_shift);
}
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);
}
if (last1 < ps_length / Vcb->superblock.sector_size) {
Status = partial_stripe_read(Vcb, c, ps, startoff, parity2, last1, (ULONG)((ps_length / Vcb->superblock.sector_size) - last1));
if (last1 < ps_length >> Vcb->sector_shift) {
Status = partial_stripe_read(Vcb, c, ps, startoff, parity2, last1, (ULONG)((ps_length >> Vcb->sector_shift) - last1));
if (!NT_SUCCESS(Status)) {
ERR("partial_stripe_read returned %08lx\n", Status);
return Status;

View file

@ -285,8 +285,8 @@ static void load_free_space_bitmap(device_extension* Vcb, chunk* c, uint64_t off
break;
}
addr = offset + (index * Vcb->superblock.sector_size);
length = Vcb->superblock.sector_size * runlength;
addr = offset + (index << Vcb->sector_shift);
length = runlength << Vcb->sector_shift;
add_space_entry(&c->space, &c->space_size, addr, length);
index += runlength;
@ -470,7 +470,7 @@ NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, bool load
uint64_t inode, *generation;
uint8_t* data;
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;
uint64_t num_entries, num_bitmaps, extent_length, bmpnum, off, total_space = 0, superblock_size;
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)
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)));
@ -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));
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) {
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;
for (i = 0; i < num_valid_sectors; i++) {
if (i * Vcb->superblock.sector_size > sizeof(uint32_t) * num_sectors)
crc32 = ~calc_crc32c(0xffffffff, &data[i * Vcb->superblock.sector_size], Vcb->superblock.sector_size);
else if ((i + 1) * Vcb->superblock.sector_size < sizeof(uint32_t) * num_sectors)
for (uint32_t i = 0; i < num_valid_sectors; i++) {
if (i << Vcb->sector_shift > sizeof(uint32_t) * num_sectors)
crc32 = ~calc_crc32c(0xffffffff, &data[i << Vcb->sector_shift], Vcb->superblock.sector_size);
else if ((i + 1) << Vcb->sector_shift < sizeof(uint32_t) * num_sectors)
crc32 = 0; // FIXME - test this
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]) {
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);
bmpnum = 0;
for (i = 0; i < num_entries; i++) {
if ((off + sizeof(FREE_SPACE_ENTRY)) / Vcb->superblock.sector_size != off / Vcb->superblock.sector_size)
for (uint32_t i = 0; i < num_entries; i++) {
if ((off + sizeof(FREE_SPACE_ENTRY)) >> Vcb->sector_shift != off >> Vcb->sector_shift)
off = sector_align(off, Vcb->superblock.sector_size);
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) {
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);
for (i = 0; i < num_entries; i++) {
if ((off + sizeof(FREE_SPACE_ENTRY)) / Vcb->superblock.sector_size != off / Vcb->superblock.sector_size)
for (uint32_t i = 0; i < num_entries; i++) {
if ((off + sizeof(FREE_SPACE_ENTRY)) >> Vcb->sector_shift != off >> Vcb->sector_shift)
off = sector_align(off, Vcb->superblock.sector_size);
fse = (FREE_SPACE_ENTRY*)&data[off];
if (fse->type == FREE_SPACE_BITMAP) {
// 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++;
}
@ -778,7 +778,7 @@ static NTSTATUS load_stored_free_space_tree(device_extension* Vcb, chunk* c, PIR
uint64_t lastoff;
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) {
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
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);
@ -824,8 +824,8 @@ static NTSTATUS load_stored_free_space_tree(device_extension* Vcb, chunk* c, PIR
break;
}
runstart = tp.item->key.obj_id + (index * Vcb->superblock.sector_size);
runend = runstart + (runlength * Vcb->superblock.sector_size);
runstart = tp.item->key.obj_id + (index << Vcb->sector_shift);
runend = runstart + (runlength << Vcb->sector_shift);
if (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));
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);
// adjust for padding
// FIXME - there must be a more efficient way of doing this
new_cache_size = sizeof(uint64_t) + (sizeof(uint32_t) * num_sectors);
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 += 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);
@ -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);
}
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;
if (!IsListEmpty(deleting)) {
le = deleting->Flink;
while (le != deleting) {
space* s = CONTAINING_RECORD(le, space, list_entry);
le = old_list->Flink;
while (le != old_list) {
space* s = CONTAINING_RECORD(le, space, list_entry);
space* s2;
space_list_add2(spacelist, spacelist_size, s->address, s->size, NULL, NULL);
le = le->Flink;
s2 = ExAllocatePoolWithTag(PagedPool, sizeof(space), ALLOC_TAG);
if (!s2) {
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) {
@ -1673,10 +1695,8 @@ static NTSTATUS update_chunk_cache(device_extension* Vcb, chunk* c, BTRFS_TIME*
FREE_SPACE_ITEM* fsi;
void* data;
uint64_t num_entries, *cachegen, off;
uint32_t *checksums, num_sectors, i;
LIST_ENTRY* le;
space_list_merge(&c->space, &c->space_size, &c->deleting);
uint32_t *checksums, num_sectors;
LIST_ENTRY space_list, deleting;
data = ExAllocatePoolWithTag(NonPagedPool, (ULONG)c->cache->inode_item.st_size, ALLOC_TAG);
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);
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_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);
le = c->space.Flink;
while (le != &c->space) {
while (!IsListEmpty(&space_list)) {
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);
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++;
off += sizeof(FREE_SPACE_ENTRY);
le = le->Flink;
}
// 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
for (i = 0; i < num_sectors; i++) {
if (i * Vcb->superblock.sector_size > sizeof(uint32_t) * num_sectors)
checksums[i] = ~calc_crc32c(0xffffffff, (uint8_t*)data + (i * Vcb->superblock.sector_size), Vcb->superblock.sector_size);
else if ((i + 1) * Vcb->superblock.sector_size < sizeof(uint32_t) * num_sectors)
for (uint32_t i = 0; i < num_sectors; i++) {
if (i << Vcb->sector_shift > sizeof(uint32_t) * num_sectors)
checksums[i] = ~calc_crc32c(0xffffffff, (uint8_t*)data + (i << Vcb->sector_shift), Vcb->superblock.sector_size);
else if ((i + 1) << Vcb->sector_shift < sizeof(uint32_t) * num_sectors)
checksums[i] = 0; // FIXME - test this
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
@ -1792,10 +1831,192 @@ end:
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;
LIST_ENTRY* le;
LIST_ENTRY space_list;
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);
if (!fsi) {
@ -1803,41 +2024,13 @@ static NTSTATUS update_chunk_cache_tree(device_extension* Vcb, chunk* c, LIST_EN
return STATUS_INSUFFICIENT_RESOURCES;
}
space_list_merge(&c->space, &c->space_size, &c->deleting);
fsi->count = 0;
fsi->count = fsi_count;
fsi->flags = 0;
le = c->space.Flink;
while (le != &c->space) {
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);
Status = insert_tree_item(Vcb, Vcb->space_root, c->offset, TYPE_FREE_SPACE_INFO, c->chunk_item->size, fsi, sizeof(fsi),
NULL, Irp);
if (!NT_SUCCESS(Status)) {
ERR("insert_tree_item_batch 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);
ERR("insert_tree_item returned %08lx\n", 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) {
LIST_ENTRY *le, batchlist;
LIST_ENTRY *le;
NTSTATUS Status;
chunk* c;
Vcb->superblock.compat_ro_flags |= BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID;
InitializeListHead(&batchlist);
ExAcquireResourceSharedLite(&Vcb->chunk_lock, true);
le = Vcb->chunks.Flink;
@ -1931,13 +2122,12 @@ NTSTATUS update_chunk_caches_tree(device_extension* Vcb, PIRP Irp) {
if (c->space_changed) {
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);
if (!NT_SUCCESS(Status)) {
ERR("update_chunk_cache_tree(%I64x) returned %08lx\n", c->offset, Status);
ExReleaseResourceLite(&Vcb->chunk_lock);
clear_batch_list(Vcb, &batchlist);
return Status;
}
}
@ -1947,12 +2137,6 @@ NTSTATUS update_chunk_caches_tree(device_extension* Vcb, PIRP Irp) {
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;
}
@ -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) {
LIST_ENTRY* list;
list = deleting ? &c->deleting : &c->space;
void space_list_subtract(chunk* c, uint64_t address, uint64_t length, LIST_ENTRY* rollback) {
c->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)
end = sector_align(fcb->inode_item.st_size, Vcb->superblock.sector_size);
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) {
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;
datalen2 = (ULONG)ded->ByteCount.QuadPart;
} 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);
}
@ -3469,7 +3469,7 @@ static NTSTATUS duplicate_extents(device_extension* Vcb, PFILE_OBJECT FileObject
fcb->inode_item.st_blocks += datalen2;
} 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);
if (!NT_SUCCESS(Status)) {
@ -3543,7 +3543,7 @@ static NTSTATUS duplicate_extents(device_extension* Vcb, PFILE_OBJECT FileObject
if (ext->csum) {
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) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
@ -3551,10 +3551,10 @@ static NTSTATUS duplicate_extents(device_extension* Vcb, PFILE_OBJECT FileObject
goto end;
}
RtlCopyMemory(ext2->csum, (uint8_t*)ext->csum + ((ed2d->offset - ed2s->offset) * Vcb->csum_size / Vcb->superblock.sector_size),
(ULONG)(ed2d->num_bytes * 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->sector_shift));
} 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) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
@ -3562,7 +3562,7 @@ static NTSTATUS duplicate_extents(device_extension* Vcb, PFILE_OBJECT FileObject
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
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);
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;
if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE), Irp->RequestorMode))

View file

@ -17,171 +17,15 @@
#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 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) {
device_extension* Vcb = DeviceObject->DeviceExtension;
NTSTATUS Status;
// We might be going away imminently - do a flush so we're not caught out
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))) {
@ -189,15 +33,6 @@ NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
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) {
Status = do_write(Vcb, Irp);
@ -212,25 +47,13 @@ NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
ExReleaseResourceLite(&Vcb->tree_lock);
if (Vcb->open_files == 0)
uninit(Vcb);
return STATUS_SUCCESS;
return STATUS_UNSUCCESSFUL;
}
static NTSTATUS pnp_remove_device(PDEVICE_OBJECT DeviceObject) {
device_extension* Vcb = DeviceObject->DeviceExtension;
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) {
Status = FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_DISMOUNT);
if (!NT_SUCCESS(Status)) {
@ -649,7 +472,7 @@ NTSTATUS __stdcall drv_pnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
switch (IrpSp->MinorFunction) {
case IRP_MN_CANCEL_REMOVE_DEVICE:
Status = pnp_cancel_remove_device(DeviceObject);
Status = STATUS_SUCCESS;
break;
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,
device** devices, uint64_t generation) {
ULONG i;
bool checksum_error = false;
uint16_t j, stripe = 0;
NTSTATUS Status;
@ -334,7 +333,7 @@ static NTSTATUS read_data_dup(device_extension* Vcb, uint8_t* buf, uint64_t addr
ExFreePool(t2);
} 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;
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;
}
for (i = 0; i < sectors; i++) {
if (!check_sector_csum(Vcb, buf + (i * Vcb->superblock.sector_size), ptr)) {
for (ULONG i = 0; i < sectors; i++) {
if (!check_sector_csum(Vcb, buf + (i << Vcb->sector_shift), ptr)) {
bool recovered = false;
for (j = 0; j < ci->num_stripes; j++) {
if (j != stripe && devices[j] && devices[j]->devobj) {
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);
if (!NT_SUCCESS(Status)) {
WARN("sync_read_phys returned %08lx\n", Status);
log_device_error(Vcb, devices[j], BTRFS_DEV_STAT_READ_ERRORS);
} else {
if (check_sector_csum(Vcb, sector, ptr)) {
RtlCopyMemory(buf + (i * Vcb->superblock.sector_size), 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);
RtlCopyMemory(buf + (i << Vcb->sector_shift), sector, Vcb->superblock.sector_size);
ERR("recovering from checksum error at %I64x, device %I64x\n", addr + ((uint64_t)i << Vcb->sector_shift), devices[stripe]->devitem.dev_id);
recovered = true;
if (!Vcb->readonly && !devices[stripe]->readonly) { // write good data over bad
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);
if (!NT_SUCCESS(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) {
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);
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,
CHUNK_ITEM* ci, device** devices, uint64_t generation, uint64_t offset) {
uint64_t i;
for (i = 0; i < ci->num_stripes; i++) {
for (uint16_t i = 0; i < ci->num_stripes; i++) {
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);
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) {
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) {
void* ptr = context->csum;
for (i = 0; i < length / Vcb->superblock.sector_size; i++) {
if (!check_sector_csum(Vcb, buf + (i * Vcb->superblock.sector_size), ptr)) {
for (uint32_t i = 0; i < length >> Vcb->sector_shift; i++) {
if (!check_sector_csum(Vcb, buf + (i << Vcb->sector_shift), ptr)) {
uint64_t off;
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);
@ -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,
CHUNK_ITEM* ci, device** devices, uint64_t generation, uint64_t offset) {
uint64_t i;
uint16_t j, stripe;
uint16_t stripe;
NTSTATUS Status;
bool checksum_error = false;
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) {
WARN("stripe %u returned error %08lx\n", j, context->stripes[j].iosb.Status);
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);
}
} 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)
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;
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) {
badsubstripe = j;
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) {
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);
@ -577,7 +573,7 @@ static NTSTATUS read_data_raid10(device_extension* Vcb, uint8_t* buf, uint64_t a
ExFreePool(t2);
} else {
ULONG sectors = length / Vcb->superblock.sector_size;
ULONG sectors = length >> Vcb->sector_shift;
uint8_t* sector;
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;
}
for (i = 0; i < sectors; i++) {
if (!check_sector_csum(Vcb, buf + (i * Vcb->superblock.sector_size), ptr)) {
for (ULONG i = 0; i < sectors; i++) {
if (!check_sector_csum(Vcb, buf + (i << Vcb->sector_shift), ptr)) {
uint64_t off;
uint16_t stripe2, badsubstripe = 0;
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);
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) {
badsubstripe = j;
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);
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) {
Status = sync_read_phys(devices[stripe2 + j]->devobj, devices[stripe2 + j]->fileobj, cis[stripe2 + j].offset + off,
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);
} else {
if (check_sector_csum(Vcb, sector, ptr)) {
RtlCopyMemory(buf + (i * Vcb->superblock.sector_size), 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);
RtlCopyMemory(buf + (i << Vcb->sector_shift), sector, Vcb->superblock.sector_size);
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;
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) {
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);
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,
device** devices, uint64_t offset, uint64_t generation, chunk* c, bool degraded) {
ULONG i;
NTSTATUS Status;
bool checksum_error = false;
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)
break;
}
#ifndef __REACTOS__
uint64_t runstart = ps->address + (index * Vcb->superblock.sector_size);
uint64_t runend = runstart + (runlength * Vcb->superblock.sector_size);
uint64_t runstart = ps->address + (index << Vcb->sector_shift);
uint64_t runend = runstart + (runlength << Vcb->sector_shift);
uint64_t start = max(runstart, addr);
uint64_t end = min(runend, addr + length);
#else
runstart = ps->address + (index * Vcb->superblock.sector_size);
runend = runstart + (runlength * Vcb->superblock.sector_size);
runstart = ps->address + (index * Vcb->sector_shift);
runend = runstart + (runlength * Vcb->sector_shift);
start = max(runstart, addr);
end = min(runend, addr + length);
#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);
}
} 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 (!degraded)
@ -834,7 +828,7 @@ static NTSTATUS read_data_raid5(device_extension* Vcb, uint8_t* buf, uint64_t ad
ExFreePool(t2);
} else {
ULONG sectors = length / Vcb->superblock.sector_size;
ULONG sectors = length >> Vcb->sector_shift;
uint8_t* sector;
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;
}
for (i = 0; i < sectors; i++) {
for (ULONG i = 0; i < sectors; i++) {
uint16_t parity;
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);
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;
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;
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 (!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)
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;
@ -914,7 +908,7 @@ static NTSTATUS read_data_raid5(device_extension* Vcb, uint8_t* buf, uint64_t ad
}
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);
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,
device** devices, uint64_t offset, uint64_t generation, chunk* c, bool degraded) {
NTSTATUS Status;
ULONG i;
bool checksum_error = false;
CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1];
uint16_t stripe, j;
@ -1068,13 +1061,13 @@ static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uint64_t ad
}
#ifndef __REACTOS__
uint64_t runstart = ps->address + (index * Vcb->superblock.sector_size);
uint64_t runend = runstart + (runlength * Vcb->superblock.sector_size);
uint64_t runstart = ps->address + (index << Vcb->sector_shift);
uint64_t runend = runstart + (runlength << Vcb->sector_shift);
uint64_t start = max(runstart, addr);
uint64_t end = min(runend, addr + length);
#else
runstart = ps->address + (index * Vcb->superblock.sector_size);
runend = runstart + (runlength * Vcb->superblock.sector_size);
runstart = ps->address + (index * Vcb->sector_shift);
runend = runstart + (runlength * Vcb->sector_shift);
start = max(runstart, addr);
end = min(runend, addr + length);
#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);
}
} 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 (!degraded)
@ -1305,30 +1298,30 @@ static NTSTATUS read_data_raid6(device_extension* Vcb, uint8_t* buf, uint64_t ad
ExFreePool(sector);
} else {
ULONG sectors = length / Vcb->superblock.sector_size;
ULONG sectors = length >> Vcb->sector_shift;
uint8_t* sector;
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) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
for (i = 0; i < sectors; i++) {
for (ULONG i = 0; i < sectors; i++) {
uint64_t off;
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);
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;
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))) {
uint16_t k, error_stripe;
if (!devices[physstripe] || !devices[physstripe]->devobj || (context->csum && !check_sector_csum(Vcb, buf + (i << Vcb->sector_shift), ptr))) {
uint16_t error_stripe;
bool recovered = false, failed = false;
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;
for (k = 0; k < ci->num_stripes - 1; k++) {
for (uint16_t k = 0; k < ci->num_stripes - 1; k++) {
if (j != physstripe) {
if (devices[j] && devices[j]->devobj) {
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)) {
ERR("sync_read_phys returned %08lx\n", Status);
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 (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++) {
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)) {
RtlCopyMemory(buf + (i * Vcb->superblock.sector_size), sector + (stripe * Vcb->superblock.sector_size), Vcb->superblock.sector_size);
if (!ptr || check_sector_csum(Vcb, sector + ((unsigned int)stripe << Vcb->sector_shift), ptr)) {
RtlCopyMemory(buf + (i << Vcb->sector_shift), sector + ((unsigned int)stripe << Vcb->sector_shift), Vcb->superblock.sector_size);
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);
recovered = true;
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,
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)) {
WARN("write_data_phys returned %08lx\n", Status);
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) {
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)) {
ERR("sync_read_phys returned %08lx\n", Status);
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 (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)
recovered = true;
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 {
for (j = 0; j < ci->num_stripes - 1; j++) {
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;
error_stripe = j;
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)
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
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)) {
WARN("write_data_phys returned %08lx\n", Status);
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 (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);
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++) {
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);
} 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);
}
}
} else {
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);
log_device_error(Vcb, devices[error_stripe_phys], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
RtlCopyMemory(sector + (error_stripe * Vcb->superblock.sector_size),
sector + ((ci->num_stripes + 1) * Vcb->superblock.sector_size), Vcb->superblock.sector_size);
RtlCopyMemory(sector + ((unsigned int)error_stripe << Vcb->sector_shift),
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
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)) {
WARN("write_data_phys returned %08lx\n", Status);
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) {
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);
return STATUS_CRC_ERROR;
}
@ -1796,9 +1789,9 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ uint64_t addr, _In_ uint32_t
} else
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.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;
endoffstripe *= ci->sub_stripes;
@ -2761,6 +2754,7 @@ exit:
return Status;
}
__attribute__((nonnull(1, 2)))
NTSTATUS read_stream(fcb* fcb, uint8_t* data, uint64_t start, ULONG length, ULONG* pbr) {
ULONG readlen;
@ -2825,6 +2819,7 @@ typedef struct {
size_t length;
} 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 Status;
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;
while (le != &fcb->extents) {
uint64_t len;
extent* ext = CONTAINING_RECORD(le, extent, list_entry);
if (!ext->ignore) {
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) {
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:
{
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;
read_part* rp;
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->to_read = (uint32_t)sector_align(rp->read, fcb->Vcb->superblock.sector_size);
if (rp->addr % fcb->Vcb->superblock.sector_size > 0) {
rp->bumpoff = rp->addr % fcb->Vcb->superblock.sector_size;
if (rp->addr & (fcb->Vcb->superblock.sector_size - 1)) {
rp->bumpoff = rp->addr & (fcb->Vcb->superblock.sector_size - 1);
rp->addr -= rp->bumpoff;
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);
}
if (ed->compression == BTRFS_COMPRESSION_NONE && start % fcb->Vcb->superblock.sector_size == 0 &&
length % 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 - 1)) == 0) {
rp->buf = data + bytes_read;
rp->buf_free = false;
} else {
@ -3036,12 +3034,13 @@ NTSTATUS read_file(fcb* fcb, uint8_t* data, uint64_t start, uint64_t length, ULO
ExFreePool(rp);
Status = STATUS_INTERNAL_ERROR;
goto exit;
}
if (ext->csum) {
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
rp->csum = ext->csum;
} else
@ -3114,7 +3113,7 @@ nextitem:
rp2->csum_free = false;
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);
if (!rp2->csum) {
@ -3124,9 +3123,9 @@ nextitem:
goto exit;
}
RtlCopyMemory(rp2->csum, last_rp->csum, last_rp->to_read * fcb->Vcb->csum_size / fcb->Vcb->superblock.sector_size);
RtlCopyMemory((uint8_t*)rp2->csum + (last_rp->to_read * fcb->Vcb->csum_size / fcb->Vcb->superblock.sector_size), rp->csum,
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->sector_shift), rp->csum,
(rp->to_read * fcb->Vcb->csum_size) >> fcb->Vcb->sector_shift);
rp2->csum_free = true;
} else
@ -3189,7 +3188,7 @@ nextitem:
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,
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)) {
ERR("read_data returned %08lx\n", Status);
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);
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);
if (!(Irp->Flags & IRP_NOCACHE) && IrpSp->MinorFunction & IRP_MN_MDL) {
NTSTATUS Status = STATUS_SUCCESS;
if (Irp->MdlAddress && !data) {
ERR("MmGetSystemAddressForMdlSafe returned NULL\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
_SEH2_TRY {
if (!FileObject->PrivateCacheMap) {
CC_FILE_SIZES ccfs;
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;
}
ccfs.AllocationSize = fcb->Header.AllocationSize;
ccfs.FileSize = fcb->Header.FileSize;
ccfs.ValidDataLength = fcb->Header.ValidDataLength;
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);
}
init_file_cache(FileObject, &ccfs);
}
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)) {
@ -3431,31 +3457,27 @@ NTSTATUS do_read(PIRP Irp, bool wait, ULONG* bytes_read) {
init_file_cache(FileObject, &ccfs);
}
if (IrpSp->MinorFunction & IRP_MN_MDL) {
CcMdlRead(FileObject,&IrpSp->Parameters.Read.ByteOffset, length, &Irp->MdlAddress, &Irp->IoStatus);
} else {
if (fCcCopyReadEx) {
TRACE("CcCopyReadEx(%p, %I64x, %lx, %u, %p, %p, %p)\n", FileObject, IrpSp->Parameters.Read.ByteOffset.QuadPart,
length, wait, data, &Irp->IoStatus, Irp->Tail.Overlay.Thread);
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");
if (fCcCopyReadEx) {
TRACE("CcCopyReadEx(%p, %I64x, %lx, %u, %p, %p, %p)\n", FileObject, IrpSp->Parameters.Read.ByteOffset.QuadPart,
length, wait, data, &Irp->IoStatus, Irp->Tail.Overlay.Thread);
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);
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");
IoMarkIrpPending(Irp);
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");
}
} _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
Status = _SEH2_GetExceptionCode();

View file

@ -19,6 +19,11 @@
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) {
USHORT subnamelen, printnamelen, i;
ULONG stringlen;
@ -171,17 +176,18 @@ end:
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;
ULONG minlen;
ULONG tlength;
UNICODE_STRING subname;
ANSI_STRING target;
bool target_alloc = false;
LARGE_INTEGER offset, time;
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);
if (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;
TRACE("substitute name = %.*S\n", (int)(subname.Length / sizeof(WCHAR)), subname.Buffer);
}
fcb->type = BTRFS_TYPE_SYMLINK;
fcb->inode_item.st_mode |= __S_IFLNK;
fcb->inode_item.generation = fcb->Vcb->superblock.generation; // so we don't confuse btrfs send on Linux
if (fileref && 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);
Status = utf16_to_utf8(NULL, 0, &len, subname.Buffer, subname.Length);
if (!NT_SUCCESS(Status)) {
ERR("utf16_to_utf8 1 failed with error %08lx\n", Status);
return Status;
}
target.MaximumLength = target.Length;
target.MaximumLength = target.Length = (USHORT)len;
target.Buffer = ExAllocatePoolWithTag(PagedPool, target.MaximumLength, ALLOC_TAG);
if (!target.Buffer) {
ERR("out of memory\n");
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)) {
ERR("utf16_to_utf8 2 failed with error %08lx\n", Status);
ExFreePool(target.Buffer);
return Status;
}
for (i = 0; i < target.MaximumLength; i++) {
for (USHORT i = 0; i < target.Length; i++) {
if (target.Buffer[i] == '\\')
target.Buffer[i] = '/';
}
} else if (rdb->ReparseTag == IO_REPARSE_TAG_LX_SYMLINK) {
REPARSE_DATA_BUFFER_LX_SYMLINK* buf;
offset.QuadPart = 0;
tlength = target.Length;
Status = write_file2(fcb->Vcb, Irp, offset, target.Buffer, &tlength, false, true,
true, false, false, rollback);
if (buflen < offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + rdb->ReparseDataLength) {
WARN("buffer was less than expected length (%lu < %u)\n", buflen,
offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + rdb->ReparseDataLength);
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);
} else
Status = STATUS_SUCCESS;
KeQuerySystemTime(&time);
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 &&
((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;
} else {
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);
}
} 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) {
context->stripes[i].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++) {
if (context->stripes[i].csum_error) {
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) {
ERR("out of memory\n");
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 {
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) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
@ -784,9 +784,9 @@ static NTSTATUS scrub_extent_dup(device_extension* Vcb, chunk* c, uint64_t offse
ULONG j;
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) {
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_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
for (i = 0; i < c->chunk_item->num_stripes; i++) {
ULONG j;
if (c->devices[i]->devobj) {
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) {
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;
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_device_error(Vcb, c->devices[i], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
RtlCopyMemory(context->stripes[i].buf + (j * Vcb->superblock.sector_size),
context->stripes[k].buf + (j * Vcb->superblock.sector_size), Vcb->superblock.sector_size);
RtlCopyMemory(context->stripes[i].buf + (j << Vcb->sector_shift),
context->stripes[k].buf + (j << Vcb->sector_shift), Vcb->superblock.sector_size);
recovered = true;
break;
@ -859,7 +857,7 @@ static NTSTATUS scrub_extent_dup(device_extension* Vcb, chunk* c, uint64_t offse
}
}
} 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];
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;
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) {
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);
}
@ -962,7 +960,7 @@ static NTSTATUS scrub_extent_raid0(device_extension* Vcb, chunk* c, uint64_t off
if (csum) {
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;
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 {
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,
(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;
context->stripes[(stripe * sub_stripes) + k].csum_error = true;
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) {
for (k = 0; k < sub_stripes; k++) {
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);
if (!context->stripes[j + k].bad_csums) {
ERR("out of memory\n");
@ -1212,7 +1210,7 @@ static NTSTATUS scrub_extent_raid10(device_extension* Vcb, chunk* c, uint64_t of
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 {
@ -1259,8 +1257,8 @@ static NTSTATUS scrub_extent_raid10(device_extension* Vcb, chunk* c, uint64_t of
goodstripe = 0xffffffff;
for (k = 0; k < sub_stripes; k++) {
if (c->devices[j + k]->devobj) {
if (RtlCompareMemory((uint8_t*)context->stripes[j + k].bad_csums + (so * Vcb->csum_size / Vcb->superblock.sector_size),
(uint8_t*)csum + (pos * 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->sector_shift),
Vcb->csum_size) != Vcb->csum_size) {
has_error = true;
} else
@ -1272,8 +1270,8 @@ static NTSTATUS scrub_extent_raid10(device_extension* Vcb, chunk* c, uint64_t of
if (goodstripe != 0xffffffff) {
for (k = 0; k < sub_stripes; k++) {
if (c->devices[j + k]->devobj &&
RtlCompareMemory((uint8_t*)context->stripes[j + k].bad_csums + (so * Vcb->csum_size / Vcb->superblock.sector_size),
(uint8_t*)csum + (pos * 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->sector_shift),
Vcb->csum_size) != Vcb->csum_size) {
uint64_t addr = offset + pos;
@ -1644,13 +1642,13 @@ static NTSTATUS scrub_data_extent(device_extension* Vcb, chunk* c, uint64_t offs
do {
ULONG rl;
if (runlength * Vcb->superblock.sector_size > SCRUB_UNIT)
rl = SCRUB_UNIT / Vcb->superblock.sector_size;
if (runlength << Vcb->sector_shift > SCRUB_UNIT)
rl = SCRUB_UNIT >> Vcb->sector_shift;
else
rl = runlength;
Status = scrub_extent(Vcb, c, type, offset + UInt32x32To64(index, Vcb->superblock.sector_size),
rl * Vcb->superblock.sector_size, (uint8_t*)csum + (index * Vcb->csum_size));
Status = scrub_extent(Vcb, c, type, offset + ((uint64_t)index << Vcb->sector_shift),
rl << Vcb->sector_shift, (uint8_t*)csum + (index * Vcb->csum_size));
if (!NT_SUCCESS(Status)) {
ERR("scrub_data_extent_dup returned %08lx\n", 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,
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;
uint64_t stripeoff;
@ -1721,32 +1719,32 @@ static void scrub_raid5_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
while (stripe != parity) {
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 (RtlCheckBit(&context->is_tree, off)) {
tree_header* th = (tree_header*)&context->stripes[stripe].buf[stripeoff * Vcb->superblock.sector_size];
uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 1) * c->chunk_item->stripe_length) + (off * 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->sector_shift);
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);
if (missing_devices > 0)
log_error(Vcb, addr, c->devices[stripe]->devitem.dev_id, true, false, false);
}
off += Vcb->superblock.node_size / Vcb->superblock.sector_size;
stripeoff += Vcb->superblock.node_size / Vcb->superblock.sector_size;
i += (Vcb->superblock.node_size / Vcb->superblock.sector_size) - 1;
off += Vcb->superblock.node_size >> Vcb->sector_shift;
stripeoff += Vcb->superblock.node_size >> Vcb->sector_shift;
i += (Vcb->superblock.node_size >> Vcb->sector_shift) - 1;
continue;
} 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);
log_device_error(Vcb, c->devices[stripe], BTRFS_DEV_STAT_CORRUPTION_ERRORS);
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);
}
@ -1770,10 +1768,10 @@ static void scrub_raid5_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
if (missing_devices == 0) {
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;
o = i * Vcb->superblock.sector_size;
o = i << Vcb->sector_shift;
for (j = 0; j < Vcb->superblock.sector_size; j++) { // FIXME - use SSE
if (context->parity_scratch[o] != 0) {
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)
return;
for (i = 0; i < sectors_per_stripe; i++) {
for (ULONG i = 0; i < sectors_per_stripe; i++) {
ULONG num_errors = 0, bad_off;
uint64_t bad_stripe;
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
uint64_t addr;
do_xor(&context->stripes[parity].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
&context->parity_scratch[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->sector_shift],
Vcb->superblock.sector_size);
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;
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);
} 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)) {
tree_header* th;
do_xor(&context->parity_scratch[i * Vcb->superblock.sector_size],
&context->stripes[bad_stripe].buf[(num * c->chunk_item->stripe_length) + (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->sector_shift)],
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) {
RtlCopyMemory(&context->stripes[bad_stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
&context->parity_scratch[i * Vcb->superblock.sector_size], Vcb->superblock.node_size);
RtlCopyMemory(&context->stripes[bad_stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch[i << Vcb->sector_shift], Vcb->superblock.node_size);
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);
} else
@ -1858,15 +1856,15 @@ static void scrub_raid5_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
} else {
uint8_t hash[MAX_HASH_SIZE];
do_xor(&context->parity_scratch[i * Vcb->superblock.sector_size],
&context->stripes[bad_stripe].buf[(num * c->chunk_item->stripe_length) + (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->sector_shift)],
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) {
RtlCopyMemory(&context->stripes[bad_stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
&context->parity_scratch[i * Vcb->superblock.sector_size], 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->sector_shift], Vcb->superblock.sector_size);
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) {
if (RtlCheckBit(&context->alloc, off)) {
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);
}
@ -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,
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 parity2 = (parity1 + 1) % c->chunk_item->num_stripes;
uint64_t stripeoff;
@ -1914,32 +1912,32 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
while (stripe != parity1) {
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 (RtlCheckBit(&context->is_tree, off)) {
tree_header* th = (tree_header*)&context->stripes[stripe].buf[stripeoff * Vcb->superblock.sector_size];
uint64_t addr = c->offset + (stripe_start * (c->chunk_item->num_stripes - 2) * c->chunk_item->stripe_length) + (off * 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->sector_shift);
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);
if (missing_devices == 2)
log_error(Vcb, addr, c->devices[stripe]->devitem.dev_id, true, false, false);
}
off += Vcb->superblock.node_size / Vcb->superblock.sector_size;
stripeoff += Vcb->superblock.node_size / Vcb->superblock.sector_size;
i += (Vcb->superblock.node_size / Vcb->superblock.sector_size) - 1;
off += Vcb->superblock.node_size >> Vcb->sector_shift;
stripeoff += Vcb->superblock.node_size >> Vcb->sector_shift;
i += (Vcb->superblock.node_size >> Vcb->sector_shift) - 1;
continue;
} else if (RtlCheckBit(&context->has_csum, off)) {
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) {
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);
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)) {
// check parity 1
for (i = 0; i < sectors_per_stripe; i++) {
for (ULONG i = 0; i < sectors_per_stripe; i++) {
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
if (context->parity_scratch[o] != 0) {
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);
}
for (i = 0; i < sectors_per_stripe; i++) {
if (RtlCompareMemory(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
&context->parity_scratch2[i * Vcb->superblock.sector_size], Vcb->superblock.sector_size) != Vcb->superblock.sector_size)
for (ULONG i = 0; i < sectors_per_stripe; i++) {
if (RtlCompareMemory(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch2[i << Vcb->sector_shift], Vcb->superblock.sector_size) != Vcb->superblock.sector_size)
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
for (i = 0; i < sectors_per_stripe; i++) {
for (ULONG i = 0; i < sectors_per_stripe; i++) {
ULONG num_errors = 0;
uint64_t bad_stripe1, bad_stripe2;
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;
if (RtlCheckBit(&context->stripes[parity1].error, i)) {
do_xor(&context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
&context->parity_scratch[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->sector_shift],
Vcb->superblock.sector_size);
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;
@ -2059,12 +2057,12 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
}
if (RtlCheckBit(&context->stripes[parity2].error, i)) {
RtlCopyMemory(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
&context->parity_scratch2[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->sector_shift],
Vcb->superblock.sector_size);
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;
@ -2074,10 +2072,10 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
} else if (num_errors == 1) {
uint32_t len;
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;
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);
if (!scratch) {
@ -2087,8 +2085,8 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
RtlZeroMemory(scratch, len);
do_xor(&context->parity_scratch[i * Vcb->superblock.sector_size],
&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], len);
do_xor(&context->parity_scratch[i << Vcb->sector_shift],
&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);
@ -2098,7 +2096,7 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
galois_double(scratch, len);
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
bad_stripe_num = stripe_num;
@ -2106,7 +2104,7 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
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)
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;
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);
}
@ -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) ||
(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) {
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);
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;
RtlCopyMemory(&context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
&context->stripes[stripe].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->sector_shift)],
Vcb->superblock.node_size);
stripe = (stripe + 1) % c->chunk_item->num_stripes;
while (stripe != parity1) {
do_xor(&context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
&context->stripes[stripe].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->sector_shift)],
Vcb->superblock.node_size);
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);
}
} else {
RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
&context->parity_scratch[i * Vcb->superblock.sector_size], Vcb->superblock.node_size);
RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&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) {
// fix parity 2
stripe = parity1 == 0 ? (c->chunk_item->num_stripes - 1) : (parity1 - 1);
if (c->devices[parity2]->devobj) {
RtlCopyMemory(&context->stripes[parity2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
Vcb->superblock.node_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->sector_shift)],
Vcb->superblock.node_size);
stripe = stripe == 0 ? (c->chunk_item->num_stripes - 1) : (stripe - 1);
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)],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
Vcb->superblock.node_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->sector_shift)],
Vcb->superblock.node_size);
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;
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);
} else
@ -2202,7 +2200,7 @@ static void scrub_raid6_stripe(device_extension* Vcb, chunk* c, scrub_context_ra
uint8_t hash2[MAX_HASH_SIZE];
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)
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) ||
(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);
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;
RtlCopyMemory(&context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
&context->stripes[stripe].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->sector_shift)],
Vcb->superblock.sector_size);
stripe = (stripe + 1) % c->chunk_item->num_stripes;
while (stripe != parity1) {
do_xor(&context->stripes[parity1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
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->sector_shift)],
Vcb->superblock.sector_size);
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);
}
} else {
RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
&context->parity_scratch[i * Vcb->superblock.sector_size], 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->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) {
// fix parity 2
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)],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
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->sector_shift)],
Vcb->superblock.sector_size);
stripe = stripe == 0 ? (c->chunk_item->num_stripes - 1) : (stripe - 1);
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)],
&context->stripes[stripe].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->sector_shift)],
Vcb->superblock.sector_size);
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;
if (stripe == bad_stripe1 || stripe == bad_stripe2) {
RtlZeroMemory(&context->parity_scratch[i * Vcb->superblock.sector_size], len);
RtlZeroMemory(&context->parity_scratch2[i * Vcb->superblock.sector_size], len);
RtlZeroMemory(&context->parity_scratch[i << Vcb->sector_shift], len);
RtlZeroMemory(&context->parity_scratch2[i << Vcb->sector_shift], len);
if (stripe == bad_stripe1)
x = k;
else
y = k;
} else {
RtlCopyMemory(&context->parity_scratch[i * Vcb->superblock.sector_size],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], len);
RtlCopyMemory(&context->parity_scratch2[i * Vcb->superblock.sector_size],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], len);
RtlCopyMemory(&context->parity_scratch[i << Vcb->sector_shift],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)], len);
RtlCopyMemory(&context->parity_scratch2[i << Vcb->sector_shift],
&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);
k--;
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) {
do_xor(&context->parity_scratch[i * Vcb->superblock.sector_size],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], len);
do_xor(&context->parity_scratch2[i * Vcb->superblock.sector_size],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)], len);
do_xor(&context->parity_scratch[i << Vcb->sector_shift],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)], len);
do_xor(&context->parity_scratch2[i << Vcb->sector_shift],
&context->stripes[stripe].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)], len);
} else if (stripe == bad_stripe1)
x = k;
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);
b = gmul(gx, denom);
p = &context->stripes[parity1].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->superblock.sector_size)];
pxy = &context->parity_scratch2[i * Vcb->superblock.sector_size];
qxy = &context->parity_scratch[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->sector_shift)];
pxy = &context->parity_scratch2[i << Vcb->sector_shift];
qxy = &context->parity_scratch[i << Vcb->sector_shift];
for (j = 0; j < len; j++) {
*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++;
}
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->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->parity_scratch[i << Vcb->sector_shift], 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)) {
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) {
RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
&context->parity_scratch[i * Vcb->superblock.sector_size], Vcb->superblock.node_size);
RtlCopyMemory(&context->stripes[bad_stripe1].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch[i << Vcb->sector_shift], Vcb->superblock.node_size);
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);
} else
log_error(Vcb, addr, c->devices[bad_stripe1]->devitem.dev_id, true, false, false);
} else {
if (check_sector_csum(Vcb, &context->parity_scratch[i * Vcb->superblock.sector_size], (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)],
&context->parity_scratch[i * Vcb->superblock.sector_size], Vcb->superblock.sector_size);
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->sector_shift)],
&context->parity_scratch[i << Vcb->sector_shift], Vcb->superblock.sector_size);
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);
}
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)) {
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) {
RtlCopyMemory(&context->stripes[bad_stripe2].buf[(num * c->chunk_item->stripe_length) + (i * Vcb->superblock.sector_size)],
&context->parity_scratch2[i * Vcb->superblock.sector_size], Vcb->superblock.node_size);
RtlCopyMemory(&context->stripes[bad_stripe2].buf[(num * c->chunk_item->stripe_length) + (i << Vcb->sector_shift)],
&context->parity_scratch2[i << Vcb->sector_shift], Vcb->superblock.node_size);
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);
} else
log_error(Vcb, addr, c->devices[bad_stripe2]->devitem.dev_id, true, false, false);
} else {
if (check_sector_csum(Vcb, &context->parity_scratch2[i * Vcb->superblock.sector_size], (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)],
&context->parity_scratch2[i * Vcb->superblock.sector_size], Vcb->superblock.sector_size);
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->sector_shift)],
&context->parity_scratch2[i << Vcb->sector_shift], Vcb->superblock.sector_size);
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) {
if (c->devices[stripe]->devobj && RtlCheckBit(&context->alloc, off)) {
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);
}
@ -2451,7 +2449,7 @@ static NTSTATUS scrub_chunk_raid56_stripe_run(device_extension* Vcb, chunk* c, u
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));
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);
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)
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)
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) {
traverse_ptr tp2;
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) {
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),
tp2.item->data + ((csum_start - tp2.item->key.offset) * Vcb->csum_size / Vcb->superblock.sector_size),
(ULONG)((csum_end - csum_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->sector_shift),
(ULONG)(((csum_end - csum_start) * Vcb->csum_size) >> Vcb->sector_shift));
}
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;
}
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) {
uint64_t j;
@ -2643,7 +2641,7 @@ static NTSTATUS scrub_chunk_raid56_stripe_run(device_extension* Vcb, chunk* c, u
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].rewrite = false;
@ -3006,14 +3004,14 @@ static NTSTATUS scrub_chunk(device_extension* Vcb, chunk* c, uint64_t* offset, b
if (!is_tree) {
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) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
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);
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.offset >= tp.item->key.obj_id + size)
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 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),
tp2.item->data + ((cs - tp2.item->key.offset) * Vcb->csum_size / Vcb->superblock.sector_size),
(ULONG)((ce - cs) * 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->sector_shift),
(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)
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_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;
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;
if (context->lastinode.flags & BTRFS_INODE_NODATASUM)
@ -2331,7 +2331,7 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr* tp1, traverse
else {
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);
if (!csum) {
@ -2410,7 +2410,7 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr* tp1, traverse
else {
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);
if (!csum) {

View file

@ -18,6 +18,7 @@
#include "btrfs_drv.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) {
tree_header* th;
tree* t;
@ -191,6 +192,7 @@ NTSTATUS load_tree(device_extension* Vcb, uint64_t addr, uint8_t* buf, root* r,
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) {
if (!th->tree) {
NTSTATUS Status;
@ -216,6 +218,7 @@ static NTSTATUS do_load_tree2(device_extension* Vcb, tree_holder* th, uint8_t* b
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 Status;
uint8_t* buf;
@ -258,6 +261,7 @@ NTSTATUS do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t,
return Status;
}
__attribute__((nonnull(1)))
void free_tree(tree* t) {
tree* par;
root* r = t->root;
@ -314,6 +318,7 @@ void free_tree(tree* t) {
ExFreePool(t);
}
__attribute__((nonnull(1)))
static __inline tree_data* first_item(tree* t) {
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);
}
__attribute__((nonnull(1,2)))
static __inline tree_data* prev_item(tree* t, tree_data* td) {
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);
}
__attribute__((nonnull(1,2)))
static __inline tree_data* next_item(tree* t, tree_data* td) {
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);
}
__attribute__((nonnull(1,2,3,4)))
static NTSTATUS next_item2(device_extension* Vcb, tree* t, tree_data* td, traverse_ptr* tp) {
tree_data* td2 = next_item(t, td);
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);
}
__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 Status;
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) {
int cmp;
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,
_In_ const KEY* searchkey, _In_ bool ignore, _In_opt_ PIRP Irp) {
NTSTATUS Status;
@ -566,6 +577,7 @@ NTSTATUS find_item(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension
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 Status;
@ -590,6 +602,7 @@ NTSTATUS find_item_to_level(device_extension* Vcb, root* r, traverse_ptr* tp, co
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) {
tree* t;
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);
if (!fi)
return false;
if (!fi->treeholder.tree) {
Status = do_load_tree(Vcb, &fi->treeholder, t->parent->root, t, fi, Irp);
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->item = first_item(t);
if (!next_tp->item)
return false;
if (!ignore && next_tp->item->ignore) {
traverse_ptr ntp2;
bool b;
@ -687,6 +706,7 @@ bool find_next_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vc
return true;
}
__attribute__((nonnull(1)))
static __inline tree_data* last_item(tree* t) {
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);
}
__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) {
tree* t;
tree_data* td;
@ -754,6 +775,7 @@ bool find_prev_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vc
return true;
}
__attribute__((nonnull(1,2)))
void free_trees_root(device_extension* Vcb, root* r) {
LIST_ENTRY* le;
ULONG level;
@ -791,6 +813,7 @@ void free_trees_root(device_extension* Vcb, root* r) {
}
}
__attribute__((nonnull(1)))
void free_trees(device_extension* Vcb) {
LIST_ENTRY* le;
ULONG level;
@ -834,6 +857,7 @@ void free_trees(device_extension* Vcb) {
#pragma warning(push)
#pragma warning(suppress: 28194)
#endif
__attribute__((nonnull(1,3)))
void add_rollback(_In_ LIST_ENTRY* rollback, _In_ enum rollback_type type, _In_ __drv_aliasesMem void* ptr) {
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(suppress: 28194)
#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,
_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) {
@ -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);
if (Status == STATUS_NOT_FOUND) {
if (r) {
if (!r->treeholder.tree) {
Status = do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, Irp);
if (!NT_SUCCESS(Status)) {
ERR("do_load_tree returned %08lx\n", Status);
return Status;
}
if (!r->treeholder.tree) {
Status = do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, Irp);
if (!NT_SUCCESS(Status)) {
ERR("do_load_tree returned %08lx\n", Status);
return Status;
}
}
if (r->treeholder.tree && r->treeholder.tree->header.num_items == 0) {
tp.tree = r->treeholder.tree;
tp.item = NULL;
} else {
ERR("error: unable to load tree for root %I64x\n", r->id);
return STATUS_INTERNAL_ERROR;
}
if (r->treeholder.tree && r->treeholder.tree->header.num_items == 0) {
tp.tree = r->treeholder.tree;
tp.item = NULL;
} else {
ERR("error: find_item returned %08lx\n", Status);
return Status;
ERR("error: unable to load tree for root %I64x\n", r->id);
return STATUS_INTERNAL_ERROR;
}
} else if (!NT_SUCCESS(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)
#endif
__attribute__((nonnull(1,2)))
NTSTATUS delete_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _Inout_ traverse_ptr* tp) {
tree* t;
uint64_t gen;
@ -1026,6 +1047,7 @@ NTSTATUS delete_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock)
return STATUS_SUCCESS;
}
__attribute__((nonnull(1)))
void clear_rollback(LIST_ENTRY* rollback) {
while (!IsListEmpty(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) {
NTSTATUS Status;
rollback_item* ri;
@ -1062,23 +1085,32 @@ void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) {
re->ext->ignore = true;
if (re->ext->extent_data.type == EXTENT_TYPE_REGULAR || re->ext->extent_data.type == EXTENT_TYPE_PREALLOC) {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)re->ext->extent_data.data;
switch (re->ext->extent_data.type) {
case EXTENT_TYPE_REGULAR:
case EXTENT_TYPE_PREALLOC: {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)re->ext->extent_data.data;
if (ed2->size != 0) {
chunk* c = get_chunk_from_address(Vcb, ed2->address);
if (ed2->size != 0) {
chunk* c = get_chunk_from_address(Vcb, ed2->address);
if (c) {
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_item.flags & BTRFS_INODE_NODATASUM, false, NULL);
if (c) {
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_item.flags & BTRFS_INODE_NODATASUM, false, NULL);
if (!NT_SUCCESS(Status))
ERR("update_changed_extent_ref returned %08lx\n", Status);
if (!NT_SUCCESS(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);
@ -1091,23 +1123,32 @@ void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) {
re->ext->ignore = false;
if (re->ext->extent_data.type == EXTENT_TYPE_REGULAR || re->ext->extent_data.type == EXTENT_TYPE_PREALLOC) {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)re->ext->extent_data.data;
switch (re->ext->extent_data.type) {
case EXTENT_TYPE_REGULAR:
case EXTENT_TYPE_PREALLOC: {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)re->ext->extent_data.data;
if (ed2->size != 0) {
chunk* c = get_chunk_from_address(Vcb, ed2->address);
if (ed2->size != 0) {
chunk* c = get_chunk_from_address(Vcb, ed2->address);
if (c) {
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_item.flags & BTRFS_INODE_NODATASUM, false, NULL);
if (c) {
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_item.flags & BTRFS_INODE_NODATASUM, false, NULL);
if (!NT_SUCCESS(Status))
ERR("update_changed_extent_ref returned %08lx\n", Status);
if (!NT_SUCCESS(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);
@ -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;
p = t;
@ -1183,8 +1225,11 @@ static void find_tree_end(tree* t, KEY* tree_end, bool* no_end) {
tree_data* pi;
if (!p->parent) {
tree_end->obj_id = 0xffffffffffffffff;
tree_end->obj_type = 0xff;
tree_end->offset = 0xffffffffffffffff;
*no_end = true;
return;
return STATUS_SUCCESS;
}
pi = p->paritem;
@ -1194,13 +1239,16 @@ static void find_tree_end(tree* t, KEY* tree_end, bool* no_end) {
*tree_end = td->key;
*no_end = false;
return;
return STATUS_SUCCESS;
}
p = p->parent;
} while (p);
return STATUS_INTERNAL_ERROR;
}
__attribute__((nonnull(1,2)))
void clear_batch_list(device_extension* Vcb, LIST_ENTRY* batchlist) {
while (!IsListEmpty(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) {
batch_item* bi2;
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);
}
__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) {
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 ||
@ -1849,6 +1899,7 @@ static NTSTATUS handle_batch_collision(device_extension* Vcb, batch_item* bi, tr
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) {
LIST_ENTRY* le;
NTSTATUS Status;
@ -1875,7 +1926,11 @@ static NTSTATUS commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tr
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 (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 (tp2.item->key.obj_id == bi->key.obj_id && tp2.item->key.obj_type == bi->key.obj_type) {
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;
}
__attribute__((nonnull(1,2)))
NTSTATUS commit_batch_list(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, LIST_ENTRY* batchlist, PIRP Irp) {
NTSTATUS Status;

View file

@ -953,7 +953,7 @@ NTSTATUS __stdcall pnp_removal(PVOID NotificationStructure, PVOID Context) {
TRACE("GUID_TARGET_DEVICE_QUERY_REMOVE\n");
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;

View file

@ -28,13 +28,14 @@ typedef struct {
_Function_class_(IO_COMPLETION_ROUTINE)
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 tCcCopyWriteEx fCcCopyWriteEx;
extern tFsRtlUpdateDiskCounters fFsRtlUpdateDiskCounters;
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) {
LIST_ENTRY* le;
space* s;
@ -86,6 +87,7 @@ bool find_data_address_in_chunk(device_extension* Vcb, chunk* c, uint64_t length
return false;
}
__attribute__((nonnull(1)))
chunk* get_chunk_from_address(device_extension* Vcb, uint64_t address) {
LIST_ENTRY* le2;
@ -113,6 +115,7 @@ typedef struct {
device* device;
} stripe;
__attribute__((nonnull(1)))
static uint64_t find_new_chunk_address(device_extension* Vcb, uint64_t size) {
uint64_t lastaddr;
LIST_ENTRY* le;
@ -134,6 +137,7 @@ static uint64_t find_new_chunk_address(device_extension* Vcb, uint64_t size) {
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) {
uint64_t devusage = 0xffffffffffffffff;
space *devdh1 = NULL, *devdh2 = NULL;
@ -245,6 +249,7 @@ static bool find_new_dup_stripes(device_extension* Vcb, stripe* stripes, uint64_
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) {
uint64_t k, devusage = 0xffffffffffffffff;
space* devdh = NULL;
@ -358,6 +363,7 @@ static bool find_new_stripe(device_extension* Vcb, stripe* stripes, uint16_t i,
return true;
}
__attribute__((nonnull(1,3)))
NTSTATUS alloc_chunk(device_extension* Vcb, uint64_t flags, chunk** pc, bool full_size) {
NTSTATUS Status;
uint64_t max_stripe_size, max_chunk_size, stripe_size, stripe_length, factor;
@ -703,6 +709,7 @@ end:
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,
_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;
@ -832,6 +839,7 @@ static NTSTATUS prepare_raid0_write(_Pre_satisfies_(_Curr_->chunk_item->num_stri
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,
_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) {
@ -971,7 +979,8 @@ static NTSTATUS prepare_raid10_write(_Pre_satisfies_(_Curr_->chunk_item->sub_str
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;
LIST_ENTRY* le;
partial_stripe* ps;
@ -991,10 +1000,10 @@ static NTSTATUS add_partial_stripe(device_extension* Vcb, chunk *c, uint64_t add
// update existing entry
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 (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);
if (!NT_SUCCESS(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;
}
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->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);
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);
@ -1058,6 +1067,7 @@ typedef struct {
PFN_NUMBER* pfns;
} 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,
uint64_t irp_offset, ULONG priority, write_data_context* wtc) {
uint64_t startoff, endoff, parity_start, parity_end;
@ -1456,6 +1466,7 @@ exit:
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,
uint64_t irp_offset, ULONG priority, write_data_context* wtc) {
uint64_t startoff, endoff, parity_start, parity_end;
@ -1894,6 +1905,7 @@ exit:
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,
_In_opt_ PIRP Irp, _In_opt_ chunk* c, _In_ bool file_write, _In_ uint64_t irp_offset, _In_ ULONG priority) {
NTSTATUS Status;
@ -2163,6 +2175,7 @@ prepare_failed:
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) {
uint64_t startoff, endoff;
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;
}
__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) {
write_data_context wtc;
NTSTATUS Status;
@ -2261,6 +2275,7 @@ NTSTATUS write_data_complete(device_extension* Vcb, uint64_t address, void* data
return Status;
}
__attribute__((nonnull(2,3)))
_Function_class_(IO_COMPLETION_ROUTINE)
static NTSTATUS __stdcall write_data_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
write_data_stripe* stripe = conptr;
@ -2304,6 +2319,7 @@ end:
return STATUS_MORE_PROCESSING_REQUIRED;
}
__attribute__((nonnull(1)))
void free_write_data_stripes(write_data_context* wtc) {
LIST_ENTRY* le;
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) {
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);
}
__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 Status;
LIST_ENTRY* le;
@ -2390,15 +2408,15 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
while (le != &fcb->extents) {
LIST_ENTRY* le2 = le->Flink;
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 (ed->type != EXTENT_TYPE_INLINE)
ed2 = (EXTENT_DATA2*)ed->data;
EXTENT_DATA* ed = &ext->extent_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 (ed->type == EXTENT_TYPE_INLINE) {
@ -2414,7 +2432,9 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
#endif
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 (ed2->size != 0) {
chunk* c;
@ -2474,7 +2494,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
if (ext->csum) {
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) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2482,10 +2502,10 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
goto end;
}
RtlCopyMemory(newext->csum, (uint8_t*)ext->csum + ((end_data - ext->offset) * Vcb->csum_size / Vcb->superblock.sector_size),
(ULONG)(ned2->num_bytes * 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->sector_shift));
} 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) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2493,7 +2513,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
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
newext->csum = NULL;
@ -2538,7 +2558,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
if (ext->csum) {
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) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2546,9 +2566,9 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
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 {
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) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2556,7 +2576,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
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
newext->csum = NULL;
@ -2643,7 +2663,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
if (ext->csum) {
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) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2652,7 +2672,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
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) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2662,11 +2682,11 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
goto end;
}
RtlCopyMemory(newext1->csum, ext->csum, (ULONG)(neda2->num_bytes * Vcb->csum_size / Vcb->superblock.sector_size));
RtlCopyMemory(newext2->csum, (uint8_t*)ext->csum + ((end_data - ext->offset) * Vcb->csum_size / Vcb->superblock.sector_size),
(ULONG)(nedb2->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->sector_shift),
(ULONG)((nedb2->num_bytes * Vcb->csum_size) >> Vcb->sector_shift));
} 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) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2675,7 +2695,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
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) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
@ -2685,8 +2705,8 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, uint64_t start_data, ui
goto end;
}
RtlCopyMemory(newext1->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->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->sector_shift));
}
} else {
newext1->csum = NULL;
@ -2714,7 +2734,8 @@ end:
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;
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(suppress: 28194)
#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,
_In_ bool unique, _In_opt_ _When_(return >= 0, __drv_aliasesMem) void* csum, _In_ LIST_ENTRY* rollback) {
extent* ext;
@ -2776,6 +2798,7 @@ end:
#pragma warning(pop)
#endif
__attribute__((nonnull(1, 2, 3)))
static void remove_fcb_extent(fcb* fcb, extent* ext, LIST_ENTRY* rollback) {
if (!ext->ignore) {
rollback_extent* re;
@ -2797,6 +2820,7 @@ static void remove_fcb_extent(fcb* fcb, extent* ext, LIST_ENTRY* rollback) {
_Requires_lock_held_(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,
_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;
@ -2832,7 +2856,7 @@ bool insert_extent_chunk(_In_ device_extension* Vcb, _In_ fcb* fcb, _In_ chunk*
ed2->num_bytes = decoded_size;
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);
if (!csum) {
@ -2855,7 +2879,7 @@ bool insert_extent_chunk(_In_ device_extension* Vcb, _In_ fcb* fcb, _In_ chunk*
ExFreePool(ed);
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;
@ -2881,6 +2905,7 @@ bool insert_extent_chunk(_In_ device_extension* Vcb, _In_ fcb* fcb, _In_ chunk*
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,
PIRP Irp, uint64_t* written, bool file_write, uint64_t irp_offset, LIST_ENTRY* rollback) {
bool success = false;
@ -2973,6 +2998,7 @@ static bool try_extend_data(device_extension* Vcb, fcb* fcb, uint64_t start_data
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) {
LIST_ENTRY* le;
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;
}
__attribute__((nonnull(1,4)))
static NTSTATUS insert_prealloc_extent(fcb* fcb, uint64_t start, uint64_t length, LIST_ENTRY* rollback) {
LIST_ENTRY* le;
chunk* c;
@ -3102,6 +3129,7 @@ end:
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,
PIRP Irp, bool file_write, uint64_t irp_offset, LIST_ENTRY* rollback) {
NTSTATUS Status;
@ -3213,6 +3241,7 @@ static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, uint64_t start_da
return STATUS_DISK_FULL;
}
__attribute__((nonnull(1,4)))
NTSTATUS truncate_file(fcb* fcb, uint64_t end, PIRP Irp, LIST_ENTRY* rollback) {
NTSTATUS Status;
@ -3296,6 +3325,7 @@ NTSTATUS truncate_file(fcb* fcb, uint64_t end, PIRP Irp, LIST_ENTRY* rollback) {
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) {
uint64_t oldalloc, newalloc;
bool cur_inline;
@ -3529,6 +3559,7 @@ NTSTATUS extend_file(fcb* fcb, file_ref* fileref, uint64_t end, bool prealloc, P
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,
PIRP Irp, bool file_write, uint64_t irp_offset, ULONG priority, LIST_ENTRY* rollback) {
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)) {
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);
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)) {
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);
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)) {
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);
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)) {
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);
if (!csum) {
@ -3888,6 +3919,7 @@ static NTSTATUS do_write_file_prealloc(fcb* fcb, extent* ext, uint64_t start_dat
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 Status;
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) {
EXTENT_DATA* ed = &ext->extent_data;
EXTENT_DATA2* ed2 = ed->type == EXTENT_TYPE_INLINE ? NULL : (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 + len <= start)
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) {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;
uint64_t writeaddr = ed2->address + ed2->offset + start + written - ext->offset;
uint64_t write_len = min(len, length);
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.
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),
(uint8_t*)ext->csum + ((start + written - ext->offset) * fcb->Vcb->csum_size / 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->sector_shift));
ext->inserted = true;
extents_changed = true;
@ -4052,6 +4087,7 @@ nextitem:
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,
bool wait, bool deferred_write, bool write_irp, LIST_ENTRY* rollback) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
@ -4542,6 +4578,7 @@ end:
return Status;
}
__attribute__((nonnull(1,2)))
NTSTATUS write_file(device_extension* Vcb, PIRP Irp, bool wait, bool deferred_write) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
void* buf;
@ -4616,6 +4653,7 @@ exit:
_Dispatch_type_(IRP_MJ_WRITE)
_Function_class_(DRIVER_DISPATCH)
__attribute__((nonnull(1,2)))
NTSTATUS __stdcall drv_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
NTSTATUS Status;
bool top_level;