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) {
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;
}
le = le->Flink;
}
- return deleted;
-}
-
+ if (deleted) {
+ rc = InterlockedIncrement(&deleted->refcount);
#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;
+ WARN("fcb %p: refcount now %i (%.*S)\n", deleted, rc, deleted->full_filename.Length / sizeof(WCHAR), deleted->full_filename.Buffer);
+#endif
}
+
+ return deleted;
}
-#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;
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;
}
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;
}
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);
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))
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;
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);
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);
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;
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;
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
ULONG access;
PACCESS_STATE access_state = Stack->Parameters.Create.SecurityContext->AccessState;
+ LONG oc;
Irp->IoStatus.Information = 0;
if (NT_SUCCESS(Status) && fcb->deleted) {
free_fcb(fcb);
Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ goto exit;
}
if (NT_SUCCESS(Status)) {
}
}
- 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;
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");
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 {
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;
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;
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;
-}
\ No newline at end of file
+}
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;
}
free_traverse_ptr(&insert_tp);
t->new_address = address;
+ t->has_new_address = TRUE;
return TRUE;
}
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;
free_traverse_ptr(&insert_tp);
t->new_address = address;
+ t->has_new_address = TRUE;
return TRUE;
}
// }
// }
- 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))
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)) {
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;
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);
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)) {
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;
}
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;
}
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) {
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);
// // 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);
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;
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;
nt->parent = pt;
end:
+ t->root->root_item.bytes_used += Vcb->superblock.node_size;
// #ifdef DEBUG_PARANOID
// lastkey2.obj_id = 0xffffffffffffffff;
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;
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)) {
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)) {
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
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;
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;
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 (tc2->tree->parent) {
+ LIST_ENTRY* le2;
+ KEY firstitem = {0xcccccccccccccccc,0xcc,0xcccccccccccccccc};
- if (!NT_SUCCESS(Status)) {
- ERR("reduce_tree_extent returned %08x\n", Status);
- return Status;
+ 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;
}
- } else if (tc2->tree->header.address != 0) {
- Status = reduce_tree_extent(Vcb,tc2->tree->header.address, tc2->tree, rollback);
+ 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);
- if (!NT_SUCCESS(Status)) {
- ERR("reduce_tree_extent returned %08x\n", Status);
- return Status;
+ 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->parent) {
+
if (!tc2->tree->paritem->ignore) {
tc2->tree->paritem->ignore = TRUE;
tc2->tree->parent->header.num_items--;
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->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);
+ } 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;
- }
+ if (!NT_SUCCESS(Status)) {
+ ERR("split_tree returned %08x\n", Status);
+ return Status;
}
}
}
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)) {
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);
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;
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));
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;
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) {
}
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;
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;
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) {
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);
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;
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);
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;
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);
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;
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;
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");
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;
}
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;
}
traverse_ptr tp;
NTSTATUS Status;
EXTENT_DATA* ed;
+ UINT64 len;
searchkey.obj_id = fcb->inode;
searchkey.obj_type = TYPE_EXTENT_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);
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;
TRACE("giving inline file proper extents\n");
- origlength = ((EXTENT_DATA*)tp.item->data)->decoded_size;
+ origlength = ed->decoded_size;
cur_inline = FALSE;
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;
}
if (cur_inline) {
- EXTENT_DATA* ed;
ULONG edsize;
if (end > oldalloc) {
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);
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);