mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 17:05:46 +00:00
[BTRFS]
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:
parent
7fb342fec3
commit
0df3e104b4
11 changed files with 491 additions and 203 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
12
reactos/drivers/filesystems/btrfs/btrfsioctl.h
Normal file
12
reactos/drivers/filesystems/btrfs/btrfsioctl.h
Normal 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
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue