Upgrade the WinBtrfs to release 0.3.

Mostly bugfixes

CORE-11024 #resolve #comment Committed in r71052

svn path=/trunk/; revision=71052
This commit is contained in:
Pierre Schweitzer 2016-03-26 11:53:07 +00:00
parent 7fb342fec3
commit 0df3e104b4
11 changed files with 491 additions and 203 deletions

View file

@ -1550,8 +1550,8 @@ NTSTATUS delete_fcb(fcb* fcb, PFILE_OBJECT FileObject, LIST_ENTRY* rollback) {
// FIXME - delete all children if deleting directory
if (fcb->deleted) {
ERR("trying to delete already-deleted file\n");
return STATUS_INTERNAL_ERROR;
WARN("trying to delete already-deleted file\n");
return STATUS_SUCCESS;
}
if (!fcb->par) {
@ -1772,7 +1772,7 @@ NTSTATUS delete_fcb(fcb* fcb, PFILE_OBJECT FileObject, LIST_ENTRY* rollback) {
InitializeListHead(&changed_sector_list);
if (fcb->type != BTRFS_TYPE_DIRECTORY) {
if (fcb->type != BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size > 0) {
Status = excise_extents(fcb->Vcb, fcb, 0, sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size), &changed_sector_list, rollback);
if (!NT_SUCCESS(Status)) {
ERR("excise_extents returned %08x\n", Status);
@ -1879,9 +1879,9 @@ void _free_fcb(fcb* fcb, const char* func, const char* file, unsigned int line)
#ifdef DEBUG_FCB_REFCOUNTS
// WARN("fcb %p: refcount now %i (%.*S)\n", fcb, rc, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
#ifdef DEBUG_LONG_MESSAGES
_debug_message(func, file, line, "fcb %p: refcount now %i (%.*S)\n", fcb, rc, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
_debug_message(func, 1, file, line, "fcb %p: refcount now %i (%.*S)\n", fcb, rc, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
#else
_debug_message(func, "fcb %p: refcount now %i (%.*S)\n", fcb, rc, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
_debug_message(func, 1, "fcb %p: refcount now %i (%.*S)\n", fcb, rc, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
#endif
#endif
@ -1930,9 +1930,9 @@ void _free_fcb(fcb* fcb, const char* func, const char* file, unsigned int line)
ExFreePool(fcb);
#ifdef DEBUG_FCB_REFCOUNTS
#ifdef DEBUG_LONG_MESSAGES
_debug_message(func, file, line, "freeing fcb %p\n", fcb);
_debug_message(func, 1, file, line, "freeing fcb %p\n", fcb);
#else
_debug_message(func, "freeing fcb %p\n", fcb);
_debug_message(func, 1, "freeing fcb %p\n", fcb);
#endif
#endif
}
@ -1964,13 +1964,10 @@ static NTSTATUS STDCALL close_file(device_extension* Vcb, PFILE_OBJECT FileObjec
ExFreePool(ccb);
}
if (fcb->refcount == 1)
CcUninitializeCacheMap(FileObject, NULL, NULL);
CcUninitializeCacheMap(FileObject, NULL, NULL);
free_fcb(fcb);
FileObject->FsContext = NULL;
return STATUS_SUCCESS;
}
@ -2072,6 +2069,9 @@ static NTSTATUS STDCALL drv_cleanup(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
IoRemoveShareAccess(FileObject, &fcb->share_access);
oc = InterlockedDecrement(&fcb->open_count);
#ifdef DEBUG_FCB_REFCOUNTS
ERR("fcb %p: open_count now %i\n", fcb, oc);
#endif
if (oc == 0) {
if (fcb->delete_on_close && fcb != fcb->Vcb->root_fcb && fcb != fcb->Vcb->volume_fcb) {
@ -2115,11 +2115,11 @@ static NTSTATUS STDCALL drv_cleanup(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
TRACE("flushed cache on close (FileObject = %p, fcb = %p, AllocationSize = %llx, FileSize = %llx, ValidDataLength = %llx)\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);
FileObject->Flags |= FO_CLEANUP_COMPLETE;
}
@ -3029,12 +3029,23 @@ void protect_superblocks(device_extension* Vcb, chunk* c) {
for (j = 0; j < ci->num_stripes; j++) {
if (cis[j].offset + ci->size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) {
UINT32 size;
TRACE("cut out superblock in chunk %llx\n", c->offset);
addr = (superblock_addrs[i] - cis[j].offset) + c->offset;
TRACE("addr %llx\n", addr);
add_to_space_list(c, addr, sizeof(superblock), SPACE_TYPE_USED);
// This prevents trees from spanning a stripe boundary, which btrfs check complains
// about. It also prevents the chunk tree being placed at 0x11000, which for some
// reason makes the FS unmountable on Linux (it tries to read 0x10000, i.e. the
// superblock, instead).
if (ci->type & BLOCK_FLAG_SYSTEM || ci->type & BLOCK_FLAG_METADATA)
size = max(sizeof(superblock), Vcb->superblock.node_size);
else
size = sizeof(superblock);
add_to_space_list(c, addr, size, SPACE_TYPE_USED);
}
}

View file

@ -204,6 +204,7 @@ typedef struct _tree {
// UINT8 level;
tree_header header;
LONG refcount;
BOOL has_address;
UINT32 size;
struct _device_extension* Vcb;
struct _tree* parent;
@ -213,6 +214,7 @@ typedef struct _tree {
LIST_ENTRY itemlist;
LIST_ENTRY list_entry;
UINT64 new_address;
BOOL has_new_address;
UINT64 flags;
} tree;

View file

@ -0,0 +1,12 @@
#ifndef BTRFSIOCTL_H_DEFINED
#define BTRFSIOCTL_H_DEFINED
#define FSCTL_BTRFS_GET_FILE_IDS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x829, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
typedef struct {
UINT64 subvol;
UINT64 inode;
BOOL top;
} btrfs_get_file_ids;
#endif

View file

@ -26,7 +26,10 @@ static BOOLEAN STDCALL acquire_for_lazy_write(PVOID Context, BOOLEAN Wait) {
TRACE("(%p, %u)\n", Context, Wait);
if (!fcb || FileObject->Flags & FO_CLEANUP_COMPLETE)
// if (!fcb || FileObject->Flags & FO_CLEANUP_COMPLETE)
// return FALSE;
if (!ExAcquireResourceSharedLite(fcb->Header.PagingIoResource, Wait))
return FALSE;
fcb->lazy_writer_thread = KeGetCurrentThread();
@ -40,10 +43,12 @@ static void STDCALL release_from_lazy_write(PVOID Context) {
TRACE("(%p)\n", Context);
if (!fcb || FileObject->Flags & FO_CLEANUP_COMPLETE)
return;
// if (!fcb || FileObject->Flags & FO_CLEANUP_COMPLETE)
// return;
fcb->lazy_writer_thread = NULL;
ExReleaseResourceLite(fcb->Header.PagingIoResource);
}
static BOOLEAN STDCALL acquire_for_read_ahead(PVOID Context, BOOLEAN Wait) {

View file

@ -648,6 +648,7 @@ static NTSTATUS split_path(PUNICODE_STRING path, UNICODE_STRING** parts, ULONG*
static fcb* search_fcb_children(fcb* dir, PUNICODE_STRING name) {
LIST_ENTRY* le;
fcb *c, *deleted = NULL;
ULONG rc;
le = dir->children.Flink;
while (le != &dir->children) {
@ -657,9 +658,9 @@ static fcb* search_fcb_children(fcb* dir, PUNICODE_STRING name) {
if (c->deleted) {
deleted = c;
} else {
c->refcount++;
rc = InterlockedIncrement(&c->refcount);
#ifdef DEBUG_FCB_REFCOUNTS
WARN("fcb %p: refcount now %i (%.*S)\n", c, c->refcount, c->full_filename.Length / sizeof(WCHAR), c->full_filename.Buffer);
WARN("fcb %p: refcount now %i (%.*S)\n", c, rc, c->full_filename.Length / sizeof(WCHAR), c->full_filename.Buffer);
#endif
return c;
}
@ -668,20 +669,27 @@ static fcb* search_fcb_children(fcb* dir, PUNICODE_STRING name) {
le = le->Flink;
}
if (deleted) {
rc = InterlockedIncrement(&deleted->refcount);
#ifdef DEBUG_FCB_REFCOUNTS
WARN("fcb %p: refcount now %i (%.*S)\n", deleted, rc, deleted->full_filename.Length / sizeof(WCHAR), deleted->full_filename.Buffer);
#endif
}
return deleted;
}
#ifdef DEBUG_FCB_REFCOUNTS
static void print_fcbs(device_extension* Vcb) {
fcb* fcb = Vcb->fcbs;
while (fcb) {
ERR("fcb %p (%.*S): refcount %u\n", fcb, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer, fcb->refcount);
fcb = fcb->next;
}
}
#endif
// #ifdef DEBUG_FCB_REFCOUNTS
// static void print_fcbs(device_extension* Vcb) {
// fcb* fcb = Vcb->fcbs;
//
// while (fcb) {
// ERR("fcb %p (%.*S): refcount %u\n", fcb, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer, fcb->refcount);
//
// fcb = fcb->next;
// }
// }
// #endif
NTSTATUS get_fcb(device_extension* Vcb, fcb** pfcb, PUNICODE_STRING fnus, fcb* relatedfcb, BOOL parent) {
fcb *dir, *sf, *sf2;
@ -693,9 +701,9 @@ NTSTATUS get_fcb(device_extension* Vcb, fcb** pfcb, PUNICODE_STRING fnus, fcb* r
TRACE("(%p, %p, %.*S, %p, %s)\n", Vcb, pfcb, fnus->Length / sizeof(WCHAR), fnus->Buffer, relatedfcb, parent ? "TRUE" : "FALSE");
#ifdef DEBUG_FCB_REFCOUNTS
print_fcbs(Vcb);
#endif
// #ifdef DEBUG_FCB_REFCOUNTS
// print_fcbs(Vcb);
// #endif
fnus2 = *fnus;
@ -713,10 +721,12 @@ NTSTATUS get_fcb(device_extension* Vcb, fcb** pfcb, PUNICODE_STRING fnus, fcb* r
}
if (fnus2.Length == sizeof(WCHAR)) {
LONG rc;
*pfcb = Vcb->root_fcb;
Vcb->root_fcb->refcount++;
rc = InterlockedIncrement(&Vcb->root_fcb->refcount);
#ifdef DEBUG_FCB_REFCOUNTS
WARN("fcb %p: refcount now %i (root)\n", Vcb->root_fcb, Vcb->root_fcb->refcount);
WARN("fcb %p: refcount now %i (root)\n", Vcb->root_fcb, rc);
#endif
return STATUS_SUCCESS;
}
@ -1028,9 +1038,9 @@ end2:
if (parts)
ExFreePool(parts);
#ifdef DEBUG_FCB_REFCOUNTS
print_fcbs(Vcb);
#endif
// #ifdef DEBUG_FCB_REFCOUNTS
// print_fcbs(Vcb);
// #endif
TRACE("returning %08x\n", Status);
@ -1064,6 +1074,7 @@ static NTSTATUS STDCALL file_create2(PIRP Irp, device_extension* Vcb, PUNICODE_S
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
ANSI_STRING utf8as;
ULONG defda;
LONG rc;
Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, fpus->Buffer, fpus->Length);
if (!NT_SUCCESS(Status))
@ -1281,9 +1292,9 @@ static NTSTATUS STDCALL file_create2(PIRP Irp, device_extension* Vcb, PUNICODE_S
fcb->delete_on_close = TRUE;
fcb->par = parfcb;
parfcb->refcount++;
rc = InterlockedIncrement(&parfcb->refcount);
#ifdef DEBUG_FCB_REFCOUNTS
WARN("fcb %p: refcount now %i (%.*S)\n", parfcb, parfcb->refcount, parfcb->full_filename.Length / sizeof(WCHAR), parfcb->full_filename.Buffer);
WARN("fcb %p: refcount now %i (%.*S)\n", parfcb, rc, parfcb->full_filename.Length / sizeof(WCHAR), parfcb->full_filename.Buffer);
#endif
fcb->subvol = parfcb->subvol;
fcb->inode = inode;
@ -1355,6 +1366,7 @@ static NTSTATUS STDCALL file_create(PIRP Irp, device_extension* Vcb, PFILE_OBJEC
ccb* ccb;
static WCHAR datasuf[] = {':','$','D','A','T','A',0};
UNICODE_STRING dsus, fpus, stream;
LONG oc;
TRACE("(%p, %p, %p, %.*S, %x, %x)\n", Irp, Vcb, FileObject, fnus->Length / sizeof(WCHAR), fnus->Buffer, disposition, options);
@ -1444,6 +1456,7 @@ static NTSTATUS STDCALL file_create(PIRP Irp, device_extension* Vcb, PFILE_OBJEC
KEY searchkey;
traverse_ptr tp;
INODE_ITEM* ii;
LONG rc;
TRACE("fpus = %.*S\n", fpus.Length / sizeof(WCHAR), fpus.Buffer);
TRACE("stream = %.*S\n", stream.Length / sizeof(WCHAR), stream.Buffer);
@ -1497,9 +1510,9 @@ static NTSTATUS STDCALL file_create(PIRP Irp, device_extension* Vcb, PFILE_OBJEC
fcb->delete_on_close = TRUE;
fcb->par = parfcb;
parfcb->refcount++;
rc = InterlockedIncrement(&parfcb->refcount);
#ifdef DEBUG_FCB_REFCOUNTS
WARN("fcb %p: refcount now %i (%.*S)\n", parfcb, parfcb->refcount, parfcb->full_filename.Length / sizeof(WCHAR), parfcb->full_filename.Buffer);
WARN("fcb %p: refcount now %i (%.*S)\n", parfcb, rc, parfcb->full_filename.Length / sizeof(WCHAR), parfcb->full_filename.Buffer);
#endif
fcb->subvol = parfcb->subvol;
fcb->inode = parfcb->inode;
@ -1658,7 +1671,10 @@ static NTSTATUS STDCALL file_create(PIRP Irp, device_extension* Vcb, PFILE_OBJEC
ccb->has_wildcard = FALSE;
ccb->specific_file = FALSE;
InterlockedIncrement(&fcb->open_count);
oc = InterlockedIncrement(&fcb->open_count);
#ifdef DEBUG_FCB_REFCOUNTS
ERR("fcb %p: open_count now %i\n", fcb, oc);
#endif
FileObject->FsContext2 = ccb;
@ -1884,6 +1900,7 @@ static NTSTATUS STDCALL create_file(PDEVICE_OBJECT DeviceObject, PIRP Irp, LIST_
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
ULONG access;
PACCESS_STATE access_state = Stack->Parameters.Create.SecurityContext->AccessState;
LONG oc;
Irp->IoStatus.Information = 0;
@ -1948,6 +1965,7 @@ static NTSTATUS STDCALL create_file(PDEVICE_OBJECT DeviceObject, PIRP Irp, LIST_
if (NT_SUCCESS(Status) && fcb->deleted) {
free_fcb(fcb);
Status = STATUS_OBJECT_NAME_NOT_FOUND;
goto exit;
}
if (NT_SUCCESS(Status)) {
@ -2217,7 +2235,10 @@ static NTSTATUS STDCALL create_file(PDEVICE_OBJECT DeviceObject, PIRP Irp, LIST_
}
}
InterlockedIncrement(&fcb->open_count);
oc = InterlockedIncrement(&fcb->open_count);
#ifdef DEBUG_FCB_REFCOUNTS
ERR("fcb %p: open_count now %i\n", fcb, oc);
#endif
} else {
Status = file_create(Irp, DeviceObject->DeviceExtension, FileObject, &FileObject->FileName, RequestedDisposition, options, rollback);
Irp->IoStatus.Information = NT_SUCCESS(Status) ? FILE_CREATED : 0;
@ -2316,6 +2337,7 @@ NTSTATUS STDCALL drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
if (IrpSp->FileObject->FileName.Length == 0 && !IrpSp->FileObject->RelatedFileObject) {
ULONG RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 0xff);
ULONG RequestedOptions = IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
LONG rc, oc;
TRACE("open operation for volume\n");
@ -2332,14 +2354,18 @@ NTSTATUS STDCALL drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
goto exit;
}
Vcb->volume_fcb->refcount++;
rc = InterlockedIncrement(&Vcb->volume_fcb->refcount);
oc = InterlockedIncrement(&Vcb->volume_fcb->open_count);
#ifdef DEBUG_FCB_REFCOUNTS
WARN("fcb %p: refcount now %i (volume)\n", Vcb->volume_fcb, Vcb->volume_fcb->refcount);
WARN("fcb %p: refcount now %i (volume)\n", Vcb->volume_fcb, rc);
WARN("fcb %p: open_count now %i (volume)\n", Vcb->volume_fcb, oc);
#endif
attach_fcb_to_fileobject(Vcb, Vcb->volume_fcb, IrpSp->FileObject);
// // NtfsAttachFCBToFileObject(DeviceExt, DeviceExt->VolumeFcb, FileObject);
// // DeviceExt->VolumeFcb->RefCount++;
//
IrpSp->FileObject->SectionObjectPointer = &Vcb->volume_fcb->nonpaged->segment_object;
Irp->IoStatus.Information = FILE_OPENED;
Status = STATUS_SUCCESS;
} else {

View file

@ -137,22 +137,58 @@ static NTSTATUS STDCALL fast_io_release_for_mod_write(PFILE_OBJECT FileObject, s
static NTSTATUS STDCALL fast_io_acquire_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject){
TRACE("STUB: fast_io_acquire_for_ccflush\n");
return STATUS_NOT_IMPLEMENTED;
return STATUS_SUCCESS;
}
static NTSTATUS STDCALL fast_io_release_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject){
TRACE("STUB: fast_io_release_for_ccflush\n");
return STATUS_NOT_IMPLEMENTED;
return STATUS_SUCCESS;
}
#ifdef DEBUG
static BOOLEAN STDCALL fast_io_read(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
TRACE("(%p, %p, %x, %x, %x, %p, %p, %p)\n", FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
return FsRtlCopyRead(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
}
static BOOLEAN STDCALL fast_io_write(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
TRACE("(%p, %p, %x, %x, %x, %p, %p, %p)\n", FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
return FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
}
static BOOLEAN STDCALL fast_io_mdl_read(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, ULONG LockKey, PMDL* MdlChain, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
TRACE("(%p, %p, %x, %x, %p, %p, %p)\n", FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject);
return FsRtlMdlReadDev(FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject);
}
static BOOLEAN STDCALL fast_io_mdl_read_complete(PFILE_OBJECT FileObject, PMDL* MdlChain, PDEVICE_OBJECT DeviceObject) {
TRACE("(%p, %p, %p)\n", FileObject, MdlChain, DeviceObject);
return FsRtlMdlReadCompleteDev(FileObject, MdlChain, DeviceObject);
}
static BOOLEAN STDCALL fast_io_prepare_mdl_write(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, ULONG LockKey, PMDL* MdlChain, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
TRACE("(%p, %p, %x, %x, %p, %p, %p)\n", FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject);
return FsRtlPrepareMdlWriteDev(FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject);
}
static BOOLEAN STDCALL fast_io_mdl_write_complete(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PMDL* MdlChain, PDEVICE_OBJECT DeviceObject) {
TRACE("(%p, %p, %p, %p)\n", FileObject, FileOffset, MdlChain, DeviceObject);
return FsRtlMdlWriteCompleteDev(FileObject, FileOffset, MdlChain, DeviceObject);
}
#endif
void __stdcall init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) {
RtlZeroMemory(&FastIoDispatch, sizeof(FastIoDispatch));
FastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
FastIoDispatch.FastIoCheckIfPossible = fast_io_check_if_possible;
FastIoDispatch.FastIoRead = FsRtlCopyRead;
FastIoDispatch.FastIoWrite = FsRtlCopyWrite;
FastIoDispatch.FastIoQueryBasicInfo = fast_query_basic_info;
FastIoDispatch.FastIoQueryStandardInfo = fast_query_standard_info;
FastIoDispatch.FastIoLock = fast_io_lock;
@ -165,10 +201,6 @@ void __stdcall init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) {
FastIoDispatch.FastIoDetachDevice = fast_io_detach_device;
FastIoDispatch.FastIoQueryNetworkOpenInfo = fast_io_query_network_open_info;
FastIoDispatch.AcquireForModWrite = fast_io_acquire_for_mod_write;
FastIoDispatch.MdlRead = FsRtlMdlReadDev;
FastIoDispatch.MdlReadComplete = FsRtlMdlReadCompleteDev;
FastIoDispatch.PrepareMdlWrite = FsRtlPrepareMdlWriteDev;
FastIoDispatch.MdlWriteComplete = FsRtlMdlWriteCompleteDev;
FastIoDispatch.FastIoReadCompressed = fast_io_read_compressed;
FastIoDispatch.FastIoWriteCompressed = fast_io_write_compressed;
FastIoDispatch.MdlReadCompleteCompressed = fast_io_mdl_read_complete_compressed;
@ -178,5 +210,21 @@ void __stdcall init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) {
FastIoDispatch.AcquireForCcFlush = fast_io_acquire_for_ccflush;
FastIoDispatch.ReleaseForCcFlush = fast_io_release_for_ccflush;
#ifdef DEBUG
FastIoDispatch.FastIoRead = fast_io_read;
FastIoDispatch.FastIoWrite = fast_io_write;
FastIoDispatch.MdlRead = fast_io_mdl_read;
FastIoDispatch.MdlReadComplete = fast_io_mdl_read_complete;
FastIoDispatch.PrepareMdlWrite = fast_io_prepare_mdl_write;
FastIoDispatch.MdlWriteComplete = fast_io_mdl_write_complete;
#else
FastIoDispatch.FastIoRead = FsRtlCopyRead;
FastIoDispatch.FastIoWrite = FsRtlCopyWrite;
FastIoDispatch.MdlRead = FsRtlMdlReadDev;
FastIoDispatch.MdlReadComplete = FsRtlMdlReadCompleteDev;
FastIoDispatch.PrepareMdlWrite = FsRtlPrepareMdlWriteDev;
FastIoDispatch.MdlWriteComplete = FsRtlMdlWriteCompleteDev;
#endif
*fiod = &FastIoDispatch;
}
}

View file

@ -2194,7 +2194,7 @@ NTSTATUS STDCALL drv_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp
break;
case FileRemoteProtocolInformation:
FIXME("STUB: FileRemoteProtocolInformation\n");
TRACE("FileRemoteProtocolInformation\n");
break;
#endif
@ -2884,7 +2884,7 @@ static NTSTATUS STDCALL query_info(device_extension* Vcb, PFILE_OBJECT FileObjec
}
case FileRemoteProtocolInformation:
FIXME("STUB: FileRemoteProtocolInformation\n");
TRACE("FileRemoteProtocolInformation\n");
Status = STATUS_INVALID_PARAMETER;
goto exit;
#endif

View file

@ -16,11 +16,36 @@
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
#include "btrfs_drv.h"
#include "btrfsioctl.h"
#ifndef FSCTL_CSV_CONTROL
#define FSCTL_CSV_CONTROL CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 181, METHOD_BUFFERED, FILE_ANY_ACCESS)
#endif
static NTSTATUS get_file_ids(PFILE_OBJECT FileObject, void* data, ULONG length) {
btrfs_get_file_ids* bgfi;
fcb* fcb;
if (length < sizeof(btrfs_get_file_ids))
return STATUS_BUFFER_OVERFLOW;
if (!FileObject)
return STATUS_INVALID_PARAMETER;
fcb = FileObject->FsContext;
if (!fcb)
return STATUS_INVALID_PARAMETER;
bgfi = data;
bgfi->subvol = fcb->subvol->id;
bgfi->inode = fcb->inode;
bgfi->top = fcb->Vcb->root_fcb == fcb ? TRUE : FALSE;
return STATUS_SUCCESS;
}
NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP Irp, UINT32 type, BOOL user) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS Status;
@ -496,6 +521,9 @@ NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP Irp, UINT32 type, BOOL
Status = STATUS_NOT_IMPLEMENTED;
break;
#endif
case FSCTL_BTRFS_GET_FILE_IDS:
Status = get_file_ids(IrpSp->FileObject, map_user_buffer(Irp), IrpSp->Parameters.DeviceIoControl.OutputBufferLength);
break;
default:
WARN("unknown control code %x (DeviceType = %x, Access = %x, Function = %x, Method = %x)\n",

View file

@ -368,6 +368,9 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI
// }
do {
UINT64 len;
EXTENT_DATA2* ed2;
ed = (EXTENT_DATA*)tp.item->data;
if (tp.item->size < sizeof(EXTENT_DATA)) {
@ -384,7 +387,11 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI
goto exit;
}
if (tp.item->key.offset + ed->decoded_size < start) {
ed2 = (EXTENT_DATA2*)ed->data;
len = ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes;
if (tp.item->key.offset + len < start) {
ERR("Tried to read beyond end of file\n");
free_traverse_ptr(&tp);
Status = STATUS_END_OF_FILE;
@ -416,9 +423,8 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI
case EXTENT_TYPE_INLINE:
{
UINT64 off = start + bytes_read - tp.item->key.offset;
UINT64 read;
UINT64 read = len - off;
read = ed->decoded_size - off;
if (read > length) read = length;
RtlCopyMemory(data + bytes_read, &ed->data[off], read);
@ -430,12 +436,11 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI
case EXTENT_TYPE_REGULAR:
{
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;
UINT64 off = start + bytes_read - tp.item->key.offset;
UINT32 to_read, read;
UINT8* buf;
read = ed->decoded_size - off;
read = len - off;
if (read > length) read = length;
if (ed2->address == 0) {
@ -476,9 +481,8 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI
case EXTENT_TYPE_PREALLOC:
{
UINT64 off = start + bytes_read - tp.item->key.offset;
UINT32 read;
UINT32 read = len - off;
read = ed->decoded_size - off;
if (read > length) read = length;
RtlZeroMemory(data + bytes_read, read);
@ -503,7 +507,7 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI
break;
else if (next_tp.item->key.obj_id != inode ||
next_tp.item->key.obj_type != TYPE_EXTENT_DATA ||
next_tp.item->key.offset != tp.item->key.offset + ed->decoded_size
next_tp.item->key.offset != tp.item->key.offset + len
) {
free_traverse_ptr(&next_tp);
break;

View file

@ -386,6 +386,7 @@ NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
// t->address = addr;
// t->level = th->level;
t->refcount = 1;
t->has_address = TRUE;
t->Vcb = Vcb;
t->parent = NULL;
t->root = r;
@ -393,6 +394,7 @@ NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
t->paritem = NULL;
t->size = 0;
t->new_address = 0;
t->has_new_address = FALSE;
#ifdef DEBUG_TREE_REFCOUNTS
#ifdef DEBUG_LONG_MESSAGES
_debug_message(func, file, line, "loaded tree %p (%llx)\n", t, addr);
@ -698,11 +700,20 @@ static NTSTATUS STDCALL find_item_in_tree(device_extension* Vcb, tree* t, traver
}
if (t->header.level == 0 && cmp == 0 && !ignore && td && td->ignore) {
tree_data* origtd = td;
while (td && td->ignore)
td = next_item(t, td);
if (td)
if (td) {
cmp = keycmp(searchkey, &td->key);
if (cmp != 0) {
td = origtd;
cmp = 0;
}
} else
td = origtd;
}
} while (td && cmp == 1);

View file

@ -1093,13 +1093,13 @@ static BOOL trees_consistent(device_extension* Vcb) {
tree_cache* tc2 = CONTAINING_RECORD(le, tree_cache, list_entry);
if (tc2->write) {
if (tc2->tree->header.num_items == 0)
if (tc2->tree->header.num_items == 0 && tc2->tree->parent)
return FALSE;
if (tc2->tree->size > maxsize)
return FALSE;
if (tc2->tree->new_address == 0)
if (!tc2->tree->has_new_address)
return FALSE;
}
@ -1263,6 +1263,7 @@ static BOOL insert_tree_extent_skinny(device_extension* Vcb, tree* t, chunk* c,
free_traverse_ptr(&insert_tp);
t->new_address = address;
t->has_new_address = TRUE;
return TRUE;
}
@ -1272,7 +1273,7 @@ static BOOL insert_tree_extent(device_extension* Vcb, tree* t, chunk* c, LIST_EN
EXTENT_ITEM_TREE2* eit2;
traverse_ptr insert_tp;
TRACE("(%p, %p, %p, %p)\n", Vcb, t, c);
TRACE("(%p, %p, %p, %p)\n", Vcb, t, c, rollback);
if (!find_address_in_chunk(Vcb, c, Vcb->superblock.node_size, &address))
return FALSE;
@ -1316,6 +1317,7 @@ static BOOL insert_tree_extent(device_extension* Vcb, tree* t, chunk* c, LIST_EN
free_traverse_ptr(&insert_tp);
t->new_address = address;
t->has_new_address = TRUE;
return TRUE;
}
@ -1341,7 +1343,7 @@ static NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, LIST_ENTRY*
// }
// }
if (t->header.address != 0) {
if (t->has_address) {
origchunk = get_chunk_from_address(Vcb, t->header.address);
if (insert_tree_extent(Vcb, t, origchunk, rollback))
@ -1384,7 +1386,7 @@ static BOOL reduce_tree_extent_skinny(device_extension* Vcb, UINT64 address, tre
searchkey.obj_id = address;
searchkey.obj_type = TYPE_METADATA_ITEM;
searchkey.offset = t->header.level;
searchkey.offset = 0xffffffffffffffff;
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
if (!NT_SUCCESS(Status)) {
@ -1392,7 +1394,7 @@ static BOOL reduce_tree_extent_skinny(device_extension* Vcb, UINT64 address, tre
return FALSE;
}
if (keycmp(&tp.item->key, &searchkey)) {
if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
TRACE("could not find %llx,%x,%llx in extent_root\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset);
free_traverse_ptr(&tp);
return FALSE;
@ -1765,7 +1767,7 @@ static NTSTATUS allocate_tree_extents(device_extension* Vcb, LIST_ENTRY* rollbac
while (le != &Vcb->tree_cache) {
tree_cache* tc2 = CONTAINING_RECORD(le, tree_cache, list_entry);
if (tc2->write && tc2->tree->new_address == 0) {
if (tc2->write && !tc2->tree->has_new_address) {
chunk* c;
Status = get_tree_new_address(Vcb, tc2->tree, rollback);
@ -1776,7 +1778,7 @@ static NTSTATUS allocate_tree_extents(device_extension* Vcb, LIST_ENTRY* rollbac
TRACE("allocated extent %llx\n", tc2->tree->new_address);
if (tc2->tree->header.address != 0) {
if (tc2->tree->has_address) {
Status = reduce_tree_extent(Vcb, tc2->tree->header.address, tc2->tree, rollback);
if (!NT_SUCCESS(Status)) {
@ -2088,7 +2090,7 @@ static NTSTATUS write_trees(device_extension* Vcb) {
traverse_ptr tp;
EXTENT_ITEM_TREE* eit;
if (tc2->tree->new_address == 0) {
if (!tc2->tree->has_new_address) {
ERR("error - tried to write tree with no new address\n");
int3;
}
@ -2226,13 +2228,8 @@ static NTSTATUS write_trees(device_extension* Vcb) {
crash = TRUE;
}
if (tc2->tree->new_address == 0) {
ERR("tree %llx, level %x: tried to write tree to address 0\n", tc2->tree->root->id, tc2->tree->header.level);
crash = TRUE;
}
if (tc2->tree->header.num_items == 0) {
ERR("tree %llx, level %x: tried to write empty tree\n", tc2->tree->root->id, tc2->tree->header.level);
if (tc2->tree->header.num_items == 0 && tc2->tree->parent) {
ERR("tree %llx, level %x: tried to write empty tree with parent\n", tc2->tree->root->id, tc2->tree->header.level);
crash = TRUE;
}
@ -2257,6 +2254,7 @@ static NTSTATUS write_trees(device_extension* Vcb) {
tc2->tree->header.address = tc2->tree->new_address;
tc2->tree->header.generation = Vcb->superblock.generation;
tc2->tree->header.flags |= HEADER_FLAG_MIXED_BACKREF;
tc2->tree->has_address = TRUE;
data = ExAllocatePoolWithTag(NonPagedPool, Vcb->superblock.node_size, ALLOC_TAG);
if (!data) {
@ -2564,11 +2562,13 @@ static NTSTATUS STDCALL split_tree_at(device_extension* Vcb, tree* t, tree_data*
nt->header.flags = HEADER_FLAG_MIXED_BACKREF;
nt->refcount = 0;
nt->has_address = FALSE;
nt->Vcb = Vcb;
nt->parent = t->parent;
nt->root = t->root;
// nt->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(tree_nonpaged), ALLOC_TAG);
nt->new_address = 0;
nt->has_new_address = FALSE;
nt->flags = t->flags;
InitializeListHead(&nt->itemlist);
@ -2637,6 +2637,22 @@ static NTSTATUS STDCALL split_tree_at(device_extension* Vcb, tree* t, tree_data*
// // TRACE("last item is now (%x,%x,%x)\n", (UINT32)oldlastitem->key.obj_id, oldlastitem->key.obj_type, (UINT32)oldlastitem->key.offset);
if (nt->header.level > 0) {
LIST_ENTRY* le = nt->itemlist.Flink;
while (le != &nt->itemlist) {
tree_data* td2 = CONTAINING_RECORD(le, tree_data, list_entry);
if (td2->treeholder.tree) {
td2->treeholder.tree->parent = nt;
increase_tree_rc(nt);
free_tree(t);
}
le = le->Flink;
}
}
if (nt->parent) {
increase_tree_rc(nt->parent);
@ -2648,7 +2664,7 @@ static NTSTATUS STDCALL split_tree_at(device_extension* Vcb, tree* t, tree_data*
td->key = newfirstitem->key;
InsertAfter(&t->itemlist, &td->list_entry, &t->paritem->list_entry);
InsertHeadList(&t->paritem->list_entry, &td->list_entry);
td->ignore = FALSE;
td->inserted = TRUE;
@ -2683,11 +2699,13 @@ static NTSTATUS STDCALL split_tree_at(device_extension* Vcb, tree* t, tree_data*
pt->header.flags = HEADER_FLAG_MIXED_BACKREF;
pt->refcount = 2;
pt->has_address = FALSE;
pt->Vcb = Vcb;
pt->parent = NULL;
pt->paritem = NULL;
pt->root = t->root;
pt->new_address = 0;
pt->has_new_address = FALSE;
// pt->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(tree_nonpaged), ALLOC_TAG);
pt->size = pt->header.num_items * sizeof(internal_node);
pt->flags = t->flags;
@ -2743,6 +2761,7 @@ static NTSTATUS STDCALL split_tree_at(device_extension* Vcb, tree* t, tree_data*
nt->parent = pt;
end:
t->root->root_item.bytes_used += Vcb->superblock.node_size;
// #ifdef DEBUG_PARANOID
// lastkey2.obj_id = 0xffffffffffffffff;
@ -2857,6 +2876,22 @@ static NTSTATUS try_tree_amalgamate(device_extension* Vcb, tree* t, LIST_ENTRY*
t->header.num_items += next_tree->header.num_items;
t->size += next_tree->size;
if (next_tree->header.level > 0) {
le = next_tree->itemlist.Flink;
while (le != &next_tree->itemlist) {
tree_data* td2 = CONTAINING_RECORD(le, tree_data, list_entry);
if (td2->treeholder.tree) {
td2->treeholder.tree->parent = t;
increase_tree_rc(t);
free_tree(next_tree);
}
le = le->Flink;
}
}
t->itemlist.Blink->Flink = next_tree->itemlist.Flink;
t->itemlist.Blink->Flink->Blink = t->itemlist.Blink;
t->itemlist.Blink = next_tree->itemlist.Blink;
@ -2877,7 +2912,7 @@ static NTSTATUS try_tree_amalgamate(device_extension* Vcb, tree* t, LIST_ENTRY*
next_tree->header.num_items = 0;
next_tree->size = 0;
if (next_tree->new_address != 0) { // delete associated EXTENT_ITEM
if (next_tree->has_new_address) { // delete associated EXTENT_ITEM
Status = reduce_tree_extent(Vcb, next_tree->new_address, next_tree, rollback);
if (!NT_SUCCESS(Status)) {
@ -2885,7 +2920,7 @@ static NTSTATUS try_tree_amalgamate(device_extension* Vcb, tree* t, LIST_ENTRY*
free_tree(next_tree);
return Status;
}
} else if (next_tree->header.address != 0) {
} else if (next_tree->has_address) {
Status = reduce_tree_extent(Vcb, next_tree->header.address, next_tree, rollback);
if (!NT_SUCCESS(Status)) {
@ -2911,6 +2946,8 @@ static NTSTATUS try_tree_amalgamate(device_extension* Vcb, tree* t, LIST_ENTRY*
ExFreePool(next_tree->paritem);
next_tree->paritem = NULL;
next_tree->root->root_item.bytes_used -= Vcb->superblock.node_size;
free_tree(next_tree);
// remove next_tree from tree cache
@ -2951,6 +2988,12 @@ static NTSTATUS try_tree_amalgamate(device_extension* Vcb, tree* t, LIST_ENTRY*
RemoveEntryList(&td->list_entry);
InsertTailList(&t->itemlist, &td->list_entry);
if (next_tree->header.level > 0 && td->treeholder.tree) {
td->treeholder.tree->parent = t;
increase_tree_rc(t);
free_tree(next_tree);
}
if (!td->ignore) {
next_tree->size -= size;
t->size += size;
@ -2993,6 +3036,106 @@ static NTSTATUS try_tree_amalgamate(device_extension* Vcb, tree* t, LIST_ENTRY*
return STATUS_SUCCESS;
}
static NTSTATUS update_extent_level(device_extension* Vcb, UINT64 address, tree* t, UINT8 level, LIST_ENTRY* rollback) {
KEY searchkey;
traverse_ptr tp;
NTSTATUS Status;
if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA) {
searchkey.obj_id = address;
searchkey.obj_type = TYPE_METADATA_ITEM;
searchkey.offset = t->header.level;
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
}
if (!keycmp(&tp.item->key, &searchkey)) {
EXTENT_ITEM_SKINNY_METADATA* eism;
if (tp.item->size > 0) {
eism = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG);
if (!eism) {
ERR("out of memory\n");
free_traverse_ptr(&tp);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(eism, tp.item->data, tp.item->size);
} else
eism = NULL;
delete_tree_item(Vcb, &tp, rollback);
if (!insert_tree_item(Vcb, Vcb->extent_root, address, TYPE_METADATA_ITEM, level, eism, tp.item->size, NULL, rollback)) {
ERR("insert_tree_item failed\n");
ExFreePool(eism);
free_traverse_ptr(&tp);
return STATUS_INTERNAL_ERROR;
}
free_traverse_ptr(&tp);
return STATUS_SUCCESS;
}
free_traverse_ptr(&tp);
}
searchkey.obj_id = address;
searchkey.obj_type = TYPE_EXTENT_ITEM;
searchkey.offset = 0xffffffffffffffff;
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
}
if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
EXTENT_ITEM_TREE* eit;
if (tp.item->size < sizeof(EXTENT_ITEM_TREE)) {
ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_ITEM_TREE));
free_traverse_ptr(&tp);
return STATUS_INTERNAL_ERROR;
}
eit = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG);
if (!eit) {
ERR("out of memory\n");
free_traverse_ptr(&tp);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(eit, tp.item->data, tp.item->size);
delete_tree_item(Vcb, &tp, rollback);
eit->level = level;
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, eit, tp.item->size, NULL, rollback)) {
ERR("insert_tree_item failed\n");
ExFreePool(eit);
free_traverse_ptr(&tp);
return STATUS_INTERNAL_ERROR;
}
free_traverse_ptr(&tp);
return STATUS_SUCCESS;
}
ERR("could not find EXTENT_ITEM for address %llx\n", address);
free_traverse_ptr(&tp);
return STATUS_INTERNAL_ERROR;
}
static NTSTATUS STDCALL do_splits(device_extension* Vcb, LIST_ENTRY* rollback) {
// LIST_ENTRY *le, *le2;
// write_tree* wt;
@ -3025,38 +3168,39 @@ static NTSTATUS STDCALL do_splits(device_extension* Vcb, LIST_ENTRY* rollback) {
empty = FALSE;
if (tc2->tree->header.num_items == 0) {
LIST_ENTRY* le2;
KEY firstitem = {0xcccccccccccccccc,0xcc,0xcccccccccccccccc};
done_deletions = TRUE;
le2 = tc2->tree->itemlist.Flink;
while (le2 != &tc2->tree->itemlist) {
tree_data* td = CONTAINING_RECORD(le2, tree_data, list_entry);
firstitem = td->key;
break;
}
ERR("deleting tree in root %llx (first item was %llx,%x,%llx)\n",
tc2->tree->root->id, firstitem.obj_id, firstitem.obj_type, firstitem.offset);
if (tc2->tree->new_address != 0) { // delete associated EXTENT_ITEM
Status = reduce_tree_extent(Vcb, tc2->tree->new_address, tc2->tree, rollback);
if (!NT_SUCCESS(Status)) {
ERR("reduce_tree_extent returned %08x\n", Status);
return Status;
}
} else if (tc2->tree->header.address != 0) {
Status = reduce_tree_extent(Vcb,tc2->tree->header.address, tc2->tree, rollback);
if (!NT_SUCCESS(Status)) {
ERR("reduce_tree_extent returned %08x\n", Status);
return Status;
}
}
if (tc2->tree->parent) {
LIST_ENTRY* le2;
KEY firstitem = {0xcccccccccccccccc,0xcc,0xcccccccccccccccc};
done_deletions = TRUE;
le2 = tc2->tree->itemlist.Flink;
while (le2 != &tc2->tree->itemlist) {
tree_data* td = CONTAINING_RECORD(le2, tree_data, list_entry);
firstitem = td->key;
break;
}
TRACE("deleting tree in root %llx (first item was %llx,%x,%llx)\n",
tc2->tree->root->id, firstitem.obj_id, firstitem.obj_type, firstitem.offset);
tc2->tree->root->root_item.bytes_used -= Vcb->superblock.node_size;
if (tc2->tree->has_new_address) { // delete associated EXTENT_ITEM
Status = reduce_tree_extent(Vcb, tc2->tree->new_address, tc2->tree, rollback);
if (!NT_SUCCESS(Status)) {
ERR("reduce_tree_extent returned %08x\n", Status);
return Status;
}
} else if (tc2->tree->has_address) {
Status = reduce_tree_extent(Vcb,tc2->tree->header.address, tc2->tree, rollback);
if (!NT_SUCCESS(Status)) {
ERR("reduce_tree_extent returned %08x\n", Status);
return Status;
}
}
if (!tc2->tree->paritem->ignore) {
tc2->tree->paritem->ignore = TRUE;
tc2->tree->parent->header.num_items--;
@ -3071,19 +3215,25 @@ static NTSTATUS STDCALL do_splits(device_extension* Vcb, LIST_ENTRY* rollback) {
RemoveEntryList(le);
ExFreePool(tc2);
} else {
FIXME("trying to delete top root, not sure what to do here\n"); // FIXME
return STATUS_INTERNAL_ERROR;
}
} else {
if (tc2->tree->size > Vcb->superblock.node_size - sizeof(tree_header)) {
TRACE("splitting overlarge tree (%x > %x)\n", tc2->tree->size, Vcb->superblock.node_size - sizeof(tree_header));
Status = split_tree(Vcb, tc2->tree);
if (!NT_SUCCESS(Status)) {
ERR("split_tree returned %08x\n", Status);
return Status;
} else if (tc2->tree->header.level != 0) {
if (tc2->tree->has_new_address) {
Status = update_extent_level(Vcb, tc2->tree->new_address, tc2->tree, 0, rollback);
if (!NT_SUCCESS(Status)) {
ERR("update_extent_level returned %08x\n", Status);
return Status;
}
}
tc2->tree->header.level = 0;
}
} else if (tc2->tree->size > Vcb->superblock.node_size - sizeof(tree_header)) {
TRACE("splitting overlarge tree (%x > %x)\n", tc2->tree->size, Vcb->superblock.node_size - sizeof(tree_header));
Status = split_tree(Vcb, tc2->tree);
if (!NT_SUCCESS(Status)) {
ERR("split_tree returned %08x\n", Status);
return Status;
}
}
}
@ -3145,16 +3295,16 @@ static NTSTATUS STDCALL do_splits(device_extension* Vcb, LIST_ENTRY* rollback) {
le2 = le2->Flink;
}
ERR("deleting top-level tree in root %llx with one item\n", tc2->tree->root->id);
TRACE("deleting top-level tree in root %llx with one item\n", tc2->tree->root->id);
if (tc2->tree->new_address != 0) { // delete associated EXTENT_ITEM
if (tc2->tree->has_new_address) { // delete associated EXTENT_ITEM
Status = reduce_tree_extent(Vcb, tc2->tree->new_address, tc2->tree, rollback);
if (!NT_SUCCESS(Status)) {
ERR("reduce_tree_extent returned %08x\n", Status);
return Status;
}
} else if (tc2->tree->header.address != 0) {
} else if (tc2->tree->has_address) {
Status = reduce_tree_extent(Vcb,tc2->tree->header.address, tc2->tree, rollback);
if (!NT_SUCCESS(Status)) {
@ -3180,8 +3330,11 @@ static NTSTATUS STDCALL do_splits(device_extension* Vcb, LIST_ENTRY* rollback) {
if (child_tree) {
child_tree->parent = NULL;
child_tree->paritem = NULL;
free_tree(tc2->tree);
}
tc2->tree->root->root_item.bytes_used -= Vcb->superblock.node_size;
free_tree(tc2->tree);
@ -3208,7 +3361,7 @@ NTSTATUS STDCALL do_write(device_extension* Vcb, LIST_ENTRY* rollback) {
TRACE("(%p)\n", Vcb);
// If only changing superblock, e.g. changing label, we still need to rewrite
// the root tree so the generations mach. Otherwise you won't be able to mount on Linux.
// the root tree so the generations match, otherwise you won't be able to mount on Linux.
if (Vcb->write_trees > 0) {
KEY searchkey;
traverse_ptr tp;
@ -4236,6 +4389,8 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT
do {
EXTENT_DATA* ed = (EXTENT_DATA*)tp.item->data;
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;
UINT64 len;
if (tp.item->size < sizeof(EXTENT_DATA)) {
ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA));
@ -4251,7 +4406,9 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT
b = find_next_item(Vcb, &tp, &next_tp, FALSE);
if (tp.item->key.offset < end_data && tp.item->key.offset + ed->decoded_size >= start_data) {
len = ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes;
if (tp.item->key.offset < end_data && tp.item->key.offset + len >= start_data) {
if (ed->compression != BTRFS_COMPRESSION_NONE) {
FIXME("FIXME - compression not supported at present\n");
Status = STATUS_NOT_SUPPORTED;
@ -4270,20 +4427,18 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT
goto end;
}
// FIXME - is ed->decoded_size the size of the whole extent, or just this bit of it?
if (ed->type == EXTENT_TYPE_INLINE) {
if (start_data <= tp.item->key.offset && end_data >= tp.item->key.offset + ed->decoded_size) { // remove all
if (start_data <= tp.item->key.offset && end_data >= tp.item->key.offset + len) { // remove all
delete_tree_item(Vcb, &tp, rollback);
fcb->inode_item.st_blocks -= ed->decoded_size;
} else if (start_data <= tp.item->key.offset && end_data < tp.item->key.offset + ed->decoded_size) { // remove beginning
fcb->inode_item.st_blocks -= len;
} else if (start_data <= tp.item->key.offset && end_data < tp.item->key.offset + len) { // remove beginning
EXTENT_DATA* ned;
UINT64 size;
delete_tree_item(Vcb, &tp, rollback);
size = ed->decoded_size - (end_data - tp.item->key.offset);
size = len - (end_data - tp.item->key.offset);
ned = ExAllocatePoolWithTag(PagedPool, sizeof(EXTENT_DATA) - 1 + size, ALLOC_TAG);
if (!ned) {
@ -4309,7 +4464,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT
}
fcb->inode_item.st_blocks -= end_data - tp.item->key.offset;
} else if (start_data > tp.item->key.offset && end_data >= tp.item->key.offset + ed->decoded_size) { // remove end
} else if (start_data > tp.item->key.offset && end_data >= tp.item->key.offset + len) { // remove end
EXTENT_DATA* ned;
UINT64 size;
@ -4340,8 +4495,8 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT
goto end;
}
fcb->inode_item.st_blocks -= tp.item->key.offset + ed->decoded_size - start_data;
} else if (start_data > tp.item->key.offset && end_data < tp.item->key.offset + ed->decoded_size) { // remove middle
fcb->inode_item.st_blocks -= tp.item->key.offset + len - start_data;
} else if (start_data > tp.item->key.offset && end_data < tp.item->key.offset + len) { // remove middle
EXTENT_DATA* ned;
UINT64 size;
@ -4372,7 +4527,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT
goto end;
}
size = tp.item->key.offset + ed->decoded_size - end_data;
size = tp.item->key.offset + len - end_data;
ned = ExAllocatePoolWithTag(PagedPool, sizeof(EXTENT_DATA) - 1 + size, ALLOC_TAG);
if (!ned) {
@ -4400,39 +4555,24 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT
fcb->inode_item.st_blocks -= end_data - start_data;
}
} else if (ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ed->data[0];
if (start_data <= tp.item->key.offset && end_data >= tp.item->key.offset + ed->decoded_size) { // remove all
if (start_data <= tp.item->key.offset && end_data >= tp.item->key.offset + len) { // remove all
if (ed2->address != 0) {
Status = remove_extent_ref(Vcb, ed2->address, ed2->size, fcb->subvol, fcb->inode, tp.item->key.offset, changed_sector_list, rollback);
Status = remove_extent_ref(Vcb, ed2->address, ed2->size, fcb->subvol, fcb->inode, tp.item->key.offset - ed2->offset, changed_sector_list, rollback);
if (!NT_SUCCESS(Status)) {
ERR("remove_extent_ref returned %08x\n", Status);
goto end;
}
fcb->inode_item.st_blocks -= ed->decoded_size;
fcb->inode_item.st_blocks -= len;
}
delete_tree_item(Vcb, &tp, rollback);
} else if (start_data <= tp.item->key.offset && end_data < tp.item->key.offset + ed->decoded_size) { // remove beginning
} else if (start_data <= tp.item->key.offset && end_data < tp.item->key.offset + len) { // remove beginning
EXTENT_DATA* ned;
EXTENT_DATA2* ned2;
if (ed2->address != 0) {
Status = add_extent_ref(Vcb, ed2->address, ed2->size, fcb->subvol, fcb->inode, end_data, rollback);
if (!NT_SUCCESS(Status)) {
ERR("add_extent_ref returned %08x\n", Status);
goto end;
}
Status = remove_extent_ref(Vcb, ed2->address, ed2->size, fcb->subvol, fcb->inode, tp.item->key.offset, changed_sector_list, rollback);
if (!NT_SUCCESS(Status)) {
ERR("remove_extent_ref returned %08x\n", Status);
goto end;
}
if (ed2->address != 0)
fcb->inode_item.st_blocks -= end_data - tp.item->key.offset;
}
delete_tree_item(Vcb, &tp, rollback);
@ -4446,7 +4586,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT
ned2 = (EXTENT_DATA2*)&ned->data[0];
ned->generation = Vcb->superblock.generation;
ned->decoded_size = ed->decoded_size - (end_data - tp.item->key.offset);
ned->decoded_size = ed->decoded_size;
ned->compression = ed->compression;
ned->encryption = ed->encryption;
ned->encoding = ed->encoding;
@ -4462,12 +4602,12 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT
Status = STATUS_INTERNAL_ERROR;
goto end;
}
} else if (start_data > tp.item->key.offset && end_data >= tp.item->key.offset + ed->decoded_size) { // remove end
} else if (start_data > tp.item->key.offset && end_data >= tp.item->key.offset + len) { // remove end
EXTENT_DATA* ned;
EXTENT_DATA2* ned2;
if (ed2->address != 0)
fcb->inode_item.st_blocks -= tp.item->key.offset + ed->decoded_size - start_data;
fcb->inode_item.st_blocks -= tp.item->key.offset + len - start_data;
delete_tree_item(Vcb, &tp, rollback);
@ -4481,7 +4621,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT
ned2 = (EXTENT_DATA2*)&ned->data[0];
ned->generation = Vcb->superblock.generation;
ned->decoded_size = start_data - tp.item->key.offset;
ned->decoded_size = ed->decoded_size;
ned->compression = ed->compression;
ned->encryption = ed->encryption;
ned->encoding = ed->encoding;
@ -4497,19 +4637,12 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT
Status = STATUS_INTERNAL_ERROR;
goto end;
}
} else if (start_data > tp.item->key.offset && end_data < tp.item->key.offset + ed->decoded_size) { // remove middle
} else if (start_data > tp.item->key.offset && end_data < tp.item->key.offset + len) { // remove middle
EXTENT_DATA* ned;
EXTENT_DATA2* ned2;
if (ed2->address != 0) {
Status = add_extent_ref(Vcb, ed2->address, ed2->size, fcb->subvol, fcb->inode, end_data, rollback);
if (!NT_SUCCESS(Status)) {
ERR("add_extent_ref returned %08x\n", Status);
goto end;
}
if (ed2->address != 0)
fcb->inode_item.st_blocks -= end_data - start_data;
}
delete_tree_item(Vcb, &tp, rollback);
@ -4523,7 +4656,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT
ned2 = (EXTENT_DATA2*)&ned->data[0];
ned->generation = Vcb->superblock.generation;
ned->decoded_size = start_data - tp.item->key.offset;
ned->decoded_size = ed->decoded_size;
ned->compression = ed->compression;
ned->encryption = ed->encryption;
ned->encoding = ed->encoding;
@ -4550,7 +4683,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT
ned2 = (EXTENT_DATA2*)&ned->data[0];
ned->generation = Vcb->superblock.generation;
ned->decoded_size = tp.item->key.offset + ed->decoded_size - end_data;
ned->decoded_size = ed->decoded_size;
ned->compression = ed->compression;
ned->encryption = ed->encryption;
ned->encoding = ed->encoding;
@ -4558,7 +4691,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT
ned2->address = ed2->address;
ned2->size = ed2->size;
ned2->offset = ed2->address == 0 ? 0 : (ed2->offset + (end_data - tp.item->key.offset));
ned2->num_bytes = tp.item->key.offset + ed->decoded_size - end_data;
ned2->num_bytes = tp.item->key.offset + len - end_data;
if (!insert_tree_item(Vcb, fcb->subvol, fcb->inode, TYPE_EXTENT_DATA, end_data, ned, sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2), NULL, rollback)) {
ERR("insert_tree_item failed\n");
@ -4830,9 +4963,16 @@ static BOOL try_extend_data(device_extension* Vcb, fcb* fcb, UINT64 start_data,
TRACE("not extending extent which is not EXTENT_TYPE_REGULAR\n");
goto end;
}
ed2 = (EXTENT_DATA2*)ed->data;
if (tp.item->size < sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) {
ERR("(%llx,%x,%llx) was %u bytes, expected %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2));
goto end;
}
if (tp.item->key.offset + ed->decoded_size != start_data) {
TRACE("last EXTENT_DATA does not run up to start_data (%llx + %llx != %llx)\n", tp.item->key.offset, ed->decoded_size, start_data);
if (tp.item->key.offset + ed2->num_bytes != start_data) {
TRACE("last EXTENT_DATA does not run up to start_data (%llx + %llx != %llx)\n", tp.item->key.offset, ed2->num_bytes, start_data);
goto end;
}
@ -4851,14 +4991,7 @@ static BOOL try_extend_data(device_extension* Vcb, fcb* fcb, UINT64 start_data,
goto end;
}
ed2 = (EXTENT_DATA2*)ed->data;
if (tp.item->size < sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) {
ERR("(%llx,%x,%llx) was %u bytes, expected %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2));
goto end;
}
if (ed2->size - ed2->offset != ed->decoded_size) {
if (ed2->size - ed2->offset != ed2->num_bytes) {
TRACE("last EXTENT_DATA does not run all the way to the end of the extent\n");
goto end;
}
@ -5033,6 +5166,7 @@ static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, UINT64 start_data
traverse_ptr tp;
NTSTATUS Status;
EXTENT_DATA* ed;
UINT64 len;
searchkey.obj_id = fcb->inode;
searchkey.obj_type = TYPE_EXTENT_DATA;
@ -5065,19 +5199,24 @@ static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, UINT64 start_data
// return STATUS_INTERNAL_ERROR;
// }
if (tp.item->key.obj_type == TYPE_EXTENT_DATA && tp.item->size >= sizeof(EXTENT_DATA))
if (tp.item->key.obj_type == TYPE_EXTENT_DATA && tp.item->size >= sizeof(EXTENT_DATA)) {
EXTENT_DATA2* ed2;
ed = (EXTENT_DATA*)tp.item->data;
else
ed2 = (EXTENT_DATA2*)ed->data;
len = ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes;
} else
ed = NULL;
if (tp.item->key.obj_id != fcb->inode || tp.item->key.obj_type != TYPE_EXTENT_DATA || !ed || tp.item->key.offset + ed->decoded_size < start_data) {
if (tp.item->key.obj_id != fcb->inode || tp.item->key.obj_type != TYPE_EXTENT_DATA || !ed || tp.item->key.offset + len < start_data) {
if (tp.item->key.obj_id != fcb->inode || tp.item->key.obj_type != TYPE_EXTENT_DATA)
Status = insert_sparse_extent(Vcb, fcb->subvol, fcb->inode, 0, start_data, rollback);
else if (!ed)
ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA));
else {
Status = insert_sparse_extent(Vcb, fcb->subvol, fcb->inode, tp.item->key.offset + ed->decoded_size,
start_data - tp.item->key.offset - ed->decoded_size, rollback);
Status = insert_sparse_extent(Vcb, fcb->subvol, fcb->inode, tp.item->key.offset + len,
start_data - tp.item->key.offset - len, rollback);
}
if (!NT_SUCCESS(Status)) {
ERR("insert_sparse_extent returned %08x\n", Status);
@ -5388,14 +5527,17 @@ NTSTATUS extend_file(fcb* fcb, UINT64 end, LIST_ENTRY* rollback) {
oldalloc = 0;
if (tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type == TYPE_EXTENT_DATA) {
EXTENT_DATA* ed = (EXTENT_DATA*)tp.item->data;
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;
if (tp.item->size < sizeof(EXTENT_DATA)) {
ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA));
free_traverse_ptr(&tp);
return STATUS_INTERNAL_ERROR;
}
oldalloc = tp.item->key.offset + ((EXTENT_DATA*)tp.item->data)->decoded_size;
cur_inline = ((EXTENT_DATA*)tp.item->data)->type == EXTENT_TYPE_INLINE;
oldalloc = tp.item->key.offset + (ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes);
cur_inline = ed->type == EXTENT_TYPE_INLINE;
if (cur_inline && end > fcb->Vcb->max_inline) {
LIST_ENTRY changed_sector_list;
@ -5405,7 +5547,7 @@ NTSTATUS extend_file(fcb* fcb, UINT64 end, LIST_ENTRY* rollback) {
TRACE("giving inline file proper extents\n");
origlength = ((EXTENT_DATA*)tp.item->data)->decoded_size;
origlength = ed->decoded_size;
cur_inline = FALSE;
@ -5426,7 +5568,7 @@ NTSTATUS extend_file(fcb* fcb, UINT64 end, LIST_ENTRY* rollback) {
if (length > origlength)
RtlZeroMemory(data + origlength, length - origlength);
RtlCopyMemory(data, ((EXTENT_DATA*)tp.item->data)->data, origlength);
RtlCopyMemory(data, ed->data, origlength);
fcb->inode_item.st_blocks -= origlength;
@ -5447,7 +5589,6 @@ NTSTATUS extend_file(fcb* fcb, UINT64 end, LIST_ENTRY* rollback) {
}
if (cur_inline) {
EXTENT_DATA* ed;
ULONG edsize;
if (end > oldalloc) {
@ -5868,7 +6009,7 @@ static void check_extents_consistent(device_extension* Vcb, fcb* fcb) {
ed = (EXTENT_DATA*)tp.item->data;
ed2 = (EXTENT_DATA2*)&ed->data[0];
length = oldlength = ed->decoded_size;
length = oldlength = ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes;
lastoff = tp.item->key.offset;
TRACE("(%llx,%x,%llx) length = %llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, length);
@ -5895,7 +6036,7 @@ static void check_extents_consistent(device_extension* Vcb, fcb* fcb) {
ed = (EXTENT_DATA*)tp.item->data;
ed2 = (EXTENT_DATA2*)&ed->data[0];
length = ed->decoded_size;
length = ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes;
TRACE("(%llx,%x,%llx) length = %llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, length);