[BTRFS] Upgrade to 1.2.1

CORE-16004
This commit is contained in:
Pierre Schweitzer 2019-05-11 11:20:02 +02:00
parent 927e1d0968
commit 883b1f31ac
No known key found for this signature in database
GPG key ID: 7545556C3D585B0B
16 changed files with 1788 additions and 1441 deletions

View file

@ -2108,8 +2108,6 @@ end:
// update open FCBs // update open FCBs
// FIXME - speed this up(?) // FIXME - speed this up(?)
acquire_fcb_lock_shared(Vcb);
le = Vcb->all_fcbs.Flink; le = Vcb->all_fcbs.Flink;
while (le != &Vcb->all_fcbs) { while (le != &Vcb->all_fcbs) {
struct _fcb* fcb = CONTAINING_RECORD(le, struct _fcb, list_entry_all); struct _fcb* fcb = CONTAINING_RECORD(le, struct _fcb, list_entry_all);
@ -2148,8 +2146,6 @@ end:
le = le->Flink; le = le->Flink;
} }
release_fcb_lock(Vcb);
} else } else
do_rollback(Vcb, &rollback); do_rollback(Vcb, &rollback);

View file

@ -1036,6 +1036,8 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
t->nonpaged = NULL;
t->is_unique = TRUE; t->is_unique = TRUE;
t->uniqueness_determined = TRUE; t->uniqueness_determined = TRUE;
t->buf = NULL; t->buf = NULL;
@ -1065,7 +1067,9 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi
r->send_ops = 0; r->send_ops = 0;
RtlZeroMemory(&r->root_item, sizeof(ROOT_ITEM)); RtlZeroMemory(&r->root_item, sizeof(ROOT_ITEM));
r->root_item.num_references = 1; r->root_item.num_references = 1;
r->fcbs_version = 0;
InitializeListHead(&r->fcbs); InitializeListHead(&r->fcbs);
RtlZeroMemory(r->fcbs_ptrs, sizeof(LIST_ENTRY*) * 256);
RtlCopyMemory(ri, &r->root_item, sizeof(ROOT_ITEM)); RtlCopyMemory(ri, &r->root_item, sizeof(ROOT_ITEM));
@ -1391,7 +1395,7 @@ void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_
return; return;
} }
acquire_fcb_lock_exclusive(fcb->Vcb); ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, TRUE);
le = fcb->hardlinks.Flink; le = fcb->hardlinks.Flink;
while (le != &fcb->hardlinks) { while (le != &fcb->hardlinks) {
@ -1410,7 +1414,7 @@ void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_
Status = fileref_get_filename(parfr, &fn, NULL, &pathlen); Status = fileref_get_filename(parfr, &fn, NULL, &pathlen);
if (Status != STATUS_BUFFER_OVERFLOW) { if (Status != STATUS_BUFFER_OVERFLOW) {
ERR("fileref_get_filename returned %08x\n", Status); ERR("fileref_get_filename returned %08x\n", Status);
free_fileref(fcb->Vcb, parfr); free_fileref(parfr);
break; break;
} }
@ -1419,7 +1423,7 @@ void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_
if (pathlen + hl->name.Length > 0xffff) { if (pathlen + hl->name.Length > 0xffff) {
WARN("pathlen + hl->name.Length was too long for FsRtlNotifyFilterReportChange\n"); WARN("pathlen + hl->name.Length was too long for FsRtlNotifyFilterReportChange\n");
free_fileref(fcb->Vcb, parfr); free_fileref(parfr);
break; break;
} }
@ -1427,14 +1431,14 @@ void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_
fn.Buffer = ExAllocatePoolWithTag(PagedPool, fn.MaximumLength, ALLOC_TAG); fn.Buffer = ExAllocatePoolWithTag(PagedPool, fn.MaximumLength, ALLOC_TAG);
if (!fn.Buffer) { if (!fn.Buffer) {
ERR("out of memory\n"); ERR("out of memory\n");
free_fileref(fcb->Vcb, parfr); free_fileref(parfr);
break; break;
} }
Status = fileref_get_filename(parfr, &fn, NULL, NULL); Status = fileref_get_filename(parfr, &fn, NULL, NULL);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("fileref_get_filename returned %08x\n", Status); ERR("fileref_get_filename returned %08x\n", Status);
free_fileref(fcb->Vcb, parfr); free_fileref(parfr);
ExFreePool(fn.Buffer); ExFreePool(fn.Buffer);
break; break;
} }
@ -1452,13 +1456,13 @@ void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_
ExFreePool(fn.Buffer); ExFreePool(fn.Buffer);
free_fileref(fcb->Vcb, parfr); free_fileref(parfr);
} }
le = le->Flink; le = le->Flink;
} }
release_fcb_lock(fcb->Vcb); ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
} }
void mark_fcb_dirty(_In_ fcb* fcb) { void mark_fcb_dirty(_In_ fcb* fcb) {
@ -1497,24 +1501,31 @@ void mark_fileref_dirty(_In_ file_ref* fileref) {
} }
#ifdef DEBUG_FCB_REFCOUNTS #ifdef DEBUG_FCB_REFCOUNTS
void _free_fcb(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ fcb* fcb, _In_ const char* func) { void _free_fcb(_Inout_ fcb* fcb, _In_ const char* func) {
LONG rc = InterlockedDecrement(&fcb->refcount);
#else #else
void free_fcb(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ fcb* fcb) { void free_fcb(_Inout_ fcb* fcb) {
InterlockedDecrement(&fcb->refcount);
#endif #endif
LONG rc;
rc = InterlockedDecrement(&fcb->refcount);
#ifdef DEBUG_FCB_REFCOUNTS #ifdef DEBUG_FCB_REFCOUNTS
#ifdef DEBUG_LONG_MESSAGES #ifdef DEBUG_LONG_MESSAGES
ERR("fcb %p: refcount now %i (subvol %llx, inode %llx)\n", fcb, rc, fcb->subvol ? fcb->subvol->id : 0, fcb->inode); ERR("fcb %p (%s): refcount now %i (subvol %llx, inode %llx)\n", fcb, func, rc, fcb->subvol ? fcb->subvol->id : 0, fcb->inode);
#else #else
ERR("fcb %p: refcount now %i (subvol %llx, inode %llx)\n", fcb, rc, fcb->subvol ? fcb->subvol->id : 0, fcb->inode); ERR("fcb %p (%s): refcount now %i (subvol %llx, inode %llx)\n", fcb, func, rc, fcb->subvol ? fcb->subvol->id : 0, fcb->inode);
#endif #endif
#endif #endif
}
if (rc > 0) void reap_fcb(fcb* fcb) {
return; UINT8 c = fcb->hash >> 24;
if (fcb->subvol && fcb->subvol->fcbs_ptrs[c] == &fcb->list_entry) {
if (fcb->list_entry.Flink != &fcb->subvol->fcbs && (CONTAINING_RECORD(fcb->list_entry.Flink, struct _fcb, list_entry)->hash >> 24) == c)
fcb->subvol->fcbs_ptrs[c] = fcb->list_entry.Flink;
else
fcb->subvol->fcbs_ptrs[c] = NULL;
}
if (fcb->list_entry.Flink) if (fcb->list_entry.Flink)
RemoveEntryList(&fcb->list_entry); RemoveEntryList(&fcb->list_entry);
@ -1526,7 +1537,7 @@ void free_fcb(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_exten
ExDeleteResourceLite(&fcb->nonpaged->paging_resource); ExDeleteResourceLite(&fcb->nonpaged->paging_resource);
ExDeleteResourceLite(&fcb->nonpaged->dir_children_lock); ExDeleteResourceLite(&fcb->nonpaged->dir_children_lock);
ExFreeToNPagedLookasideList(&Vcb->fcb_np_lookaside, fcb->nonpaged); ExFreeToNPagedLookasideList(&fcb->Vcb->fcb_np_lookaside, fcb->nonpaged);
if (fcb->sd) if (fcb->sd)
ExFreePool(fcb->sd); ExFreePool(fcb->sd);
@ -1596,21 +1607,31 @@ void free_fcb(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_exten
if (fcb->pool_type == NonPagedPool) if (fcb->pool_type == NonPagedPool)
ExFreePool(fcb); ExFreePool(fcb);
else else
ExFreeToPagedLookasideList(&Vcb->fcb_lookaside, fcb); ExFreeToPagedLookasideList(&fcb->Vcb->fcb_lookaside, fcb);
#ifdef DEBUG_FCB_REFCOUNTS
#ifdef DEBUG_LONG_MESSAGES
_debug_message(func, file, line, "freeing fcb %p\n", fcb);
#else
_debug_message(func, "freeing fcb %p\n", fcb);
#endif
#endif
} }
void free_fileref(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ file_ref* fr) { void reap_fcbs(device_extension* Vcb) {
LIST_ENTRY* le;
le = Vcb->all_fcbs.Flink;
while (le != &Vcb->all_fcbs) {
fcb* fcb = CONTAINING_RECORD(le, struct _fcb, list_entry_all);
LIST_ENTRY* le2 = le->Flink;
if (fcb->refcount == 0)
reap_fcb(fcb);
le = le2;
}
}
void free_fileref(_Inout_ file_ref* fr) {
LONG rc; LONG rc;
rc = InterlockedDecrement(&fr->refcount); rc = InterlockedDecrement(&fr->refcount);
#ifdef __REACTOS__
(void)rc;
#endif
#ifdef DEBUG_FCB_REFCOUNTS #ifdef DEBUG_FCB_REFCOUNTS
ERR("fileref %p: refcount now %i\n", fr, rc); ERR("fileref %p: refcount now %i\n", fr, rc);
@ -1622,13 +1643,9 @@ void free_fileref(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_e
int3; int3;
} }
#endif #endif
}
if (rc > 0) void reap_fileref(device_extension* Vcb, file_ref* fr) {
return;
if (fr->parent)
ExAcquireResourceExclusiveLite(&fr->parent->nonpaged->children_lock, TRUE);
// FIXME - do we need a file_ref lock? // FIXME - do we need a file_ref lock?
// FIXME - do delete if needed // FIXME - do delete if needed
@ -1636,7 +1653,6 @@ void free_fileref(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_e
if (fr->debug_desc) if (fr->debug_desc)
ExFreePool(fr->debug_desc); ExFreePool(fr->debug_desc);
ExDeleteResourceLite(&fr->nonpaged->children_lock);
ExDeleteResourceLite(&fr->nonpaged->fileref_lock); ExDeleteResourceLite(&fr->nonpaged->fileref_lock);
ExFreeToNPagedLookasideList(&Vcb->fileref_np_lookaside, fr->nonpaged); ExFreeToNPagedLookasideList(&Vcb->fileref_np_lookaside, fr->nonpaged);
@ -1656,22 +1672,38 @@ void free_fileref(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_e
if (fr->list_entry.Flink) if (fr->list_entry.Flink)
RemoveEntryList(&fr->list_entry); RemoveEntryList(&fr->list_entry);
if (fr->parent) { if (fr->parent)
ExReleaseResourceLite(&fr->parent->nonpaged->children_lock); free_fileref(fr->parent);
free_fileref(Vcb, fr->parent);
}
free_fcb(Vcb, fr->fcb); free_fcb(fr->fcb);
ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, fr); ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, fr);
} }
void reap_filerefs(device_extension* Vcb, file_ref* fr) {
LIST_ENTRY* le;
// FIXME - recursion is a bad idea in kernel mode
le = fr->children.Flink;
while (le != &fr->children) {
file_ref* c = CONTAINING_RECORD(le, file_ref, list_entry);
LIST_ENTRY* le2 = le->Flink;
reap_filerefs(Vcb, c);
le = le2;
}
if (fr->refcount == 0)
reap_fileref(Vcb, fr);
}
static NTSTATUS close_file(_In_ PFILE_OBJECT FileObject, _In_ PIRP Irp) { static NTSTATUS close_file(_In_ PFILE_OBJECT FileObject, _In_ PIRP Irp) {
fcb* fcb; fcb* fcb;
ccb* ccb; ccb* ccb;
file_ref* fileref = NULL; file_ref* fileref = NULL;
LONG open_files; LONG open_files;
device_extension* Vcb;
UNUSED(Irp); UNUSED(Irp);
@ -1735,16 +1767,10 @@ static NTSTATUS close_file(_In_ PFILE_OBJECT FileObject, _In_ PIRP Irp) {
if (!(fcb->Vcb->Vpb->Flags & VPB_MOUNTED)) if (!(fcb->Vcb->Vpb->Flags & VPB_MOUNTED))
return STATUS_SUCCESS; return STATUS_SUCCESS;
Vcb = fcb->Vcb;
acquire_fcb_lock_exclusive(Vcb);
if (fileref) if (fileref)
free_fileref(fcb->Vcb, fileref); free_fileref(fileref);
else else
free_fcb(Vcb, fcb); free_fcb(fcb);
release_fcb_lock(Vcb);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -1835,10 +1861,8 @@ void uninit(_In_ device_extension* Vcb) {
KeSetTimer(&Vcb->flush_thread_timer, time, NULL); // trigger the timer early KeSetTimer(&Vcb->flush_thread_timer, time, NULL); // trigger the timer early
KeWaitForSingleObject(&Vcb->flush_thread_finished, Executive, KernelMode, FALSE, NULL); KeWaitForSingleObject(&Vcb->flush_thread_finished, Executive, KernelMode, FALSE, NULL);
acquire_fcb_lock_exclusive(Vcb); reap_fcb(Vcb->volume_fcb);
free_fcb(Vcb, Vcb->volume_fcb); reap_fcb(Vcb->dummy_fcb);
free_fcb(Vcb, Vcb->dummy_fcb);
release_fcb_lock(Vcb);
if (Vcb->root_file) if (Vcb->root_file)
ObDereferenceObject(Vcb->root_file); ObDereferenceObject(Vcb->root_file);
@ -1848,9 +1872,7 @@ void uninit(_In_ device_extension* Vcb) {
chunk* c = CONTAINING_RECORD(le, chunk, list_entry); chunk* c = CONTAINING_RECORD(le, chunk, list_entry);
if (c->cache) { if (c->cache) {
acquire_fcb_lock_exclusive(Vcb); reap_fcb(c->cache);
free_fcb(Vcb, c->cache);
release_fcb_lock(Vcb);
c->cache = NULL; c->cache = NULL;
} }
@ -1885,11 +1907,8 @@ void uninit(_In_ device_extension* Vcb) {
if (c->devices) if (c->devices)
ExFreePool(c->devices); ExFreePool(c->devices);
if (c->cache) { if (c->cache)
acquire_fcb_lock_exclusive(Vcb); reap_fcb(c->cache);
free_fcb(Vcb, c->cache);
release_fcb_lock(Vcb);
}
ExDeleteResourceLite(&c->range_locks_lock); ExDeleteResourceLite(&c->range_locks_lock);
ExDeleteResourceLite(&c->partial_stripes_lock); ExDeleteResourceLite(&c->partial_stripes_lock);
@ -1924,6 +1943,7 @@ void uninit(_In_ device_extension* Vcb) {
ExReleaseResourceLite(&Vcb->scrub.stats_lock); ExReleaseResourceLite(&Vcb->scrub.stats_lock);
ExDeleteResourceLite(&Vcb->fcb_lock); ExDeleteResourceLite(&Vcb->fcb_lock);
ExDeleteResourceLite(&Vcb->fileref_lock);
ExDeleteResourceLite(&Vcb->load_lock); ExDeleteResourceLite(&Vcb->load_lock);
ExDeleteResourceLite(&Vcb->tree_lock); ExDeleteResourceLite(&Vcb->tree_lock);
ExDeleteResourceLite(&Vcb->chunk_lock); ExDeleteResourceLite(&Vcb->chunk_lock);
@ -2269,21 +2289,19 @@ static NTSTATUS drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
ExReleaseResourceLite(fcb->Header.Resource); ExReleaseResourceLite(fcb->Header.Resource);
locked = FALSE; locked = FALSE;
// fcb_lock needs to be acquired before fcb->Header.Resource // fileref_lock needs to be acquired before fcb->Header.Resource
acquire_fcb_lock_exclusive(fcb->Vcb); ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, TRUE);
Status = delete_fileref(fileref, FileObject, Irp, &rollback); Status = delete_fileref(fileref, FileObject, Irp, &rollback);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("delete_fileref returned %08x\n", Status); ERR("delete_fileref returned %08x\n", Status);
do_rollback(fcb->Vcb, &rollback); do_rollback(fcb->Vcb, &rollback);
release_fcb_lock(fcb->Vcb); ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
ExReleaseResourceLite(&fcb->Vcb->tree_lock); ExReleaseResourceLite(&fcb->Vcb->tree_lock);
goto exit; goto exit;
} }
release_fcb_lock(fcb->Vcb); ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
locked = FALSE;
clear_rollback(&rollback); clear_rollback(&rollback);
} else if (FileObject->Flags & FO_CACHE_SUPPORTED && fcb->nonpaged->segment_object.DataSectionObject) { } else if (FileObject->Flags & FO_CACHE_SUPPORTED && fcb->nonpaged->segment_object.DataSectionObject) {
@ -2658,7 +2676,9 @@ static NTSTATUS add_root(_Inout_ device_extension* Vcb, _In_ UINT64 id, _In_ UIN
r->treeholder.generation = generation; r->treeholder.generation = generation;
r->parent = 0; r->parent = 0;
r->send_ops = 0; r->send_ops = 0;
r->fcbs_version = 0;
InitializeListHead(&r->fcbs); InitializeListHead(&r->fcbs);
RtlZeroMemory(r->fcbs_ptrs, sizeof(LIST_ENTRY*) * 256);
r->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(root_nonpaged), ALLOC_TAG); r->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(root_nonpaged), ALLOC_TAG);
if (!r->nonpaged) { if (!r->nonpaged) {
@ -4132,6 +4152,7 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
Vcb->need_write = FALSE; Vcb->need_write = FALSE;
ExInitializeResourceLite(&Vcb->fcb_lock); ExInitializeResourceLite(&Vcb->fcb_lock);
ExInitializeResourceLite(&Vcb->fileref_lock);
ExInitializeResourceLite(&Vcb->chunk_lock); ExInitializeResourceLite(&Vcb->chunk_lock);
ExInitializeResourceLite(&Vcb->dirty_fcbs_lock); ExInitializeResourceLite(&Vcb->dirty_fcbs_lock);
ExInitializeResourceLite(&Vcb->dirty_filerefs_lock); ExInitializeResourceLite(&Vcb->dirty_filerefs_lock);
@ -4260,6 +4281,8 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
InitializeListHead(&Vcb->dirty_subvols); InitializeListHead(&Vcb->dirty_subvols);
InitializeListHead(&Vcb->send_ops); InitializeListHead(&Vcb->send_ops);
ExInitializeFastMutex(&Vcb->trees_list_mutex);
InitializeListHead(&Vcb->DirNotifyList); InitializeListHead(&Vcb->DirNotifyList);
InitializeListHead(&Vcb->scrub.errors); InitializeListHead(&Vcb->scrub.errors);
@ -4424,6 +4447,7 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
root_fcb->Vcb = Vcb; root_fcb->Vcb = Vcb;
root_fcb->inode = SUBVOL_ROOT_INODE; root_fcb->inode = SUBVOL_ROOT_INODE;
root_fcb->hash = calc_crc32c(0xffffffff, (UINT8*)&root_fcb->inode, sizeof(UINT64));
root_fcb->type = BTRFS_TYPE_DIRECTORY; root_fcb->type = BTRFS_TYPE_DIRECTORY;
#ifdef DEBUG_FCB_REFCOUNTS #ifdef DEBUG_FCB_REFCOUNTS
@ -4479,6 +4503,8 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
InsertTailList(&root_fcb->subvol->fcbs, &root_fcb->list_entry); InsertTailList(&root_fcb->subvol->fcbs, &root_fcb->list_entry);
InsertTailList(&Vcb->all_fcbs, &root_fcb->list_entry_all); InsertTailList(&Vcb->all_fcbs, &root_fcb->list_entry_all);
root_fcb->subvol->fcbs_ptrs[root_fcb->hash >> 24] = &root_fcb->list_entry;
root_fcb->fileref = Vcb->root_fileref; root_fcb->fileref = Vcb->root_fileref;
root_ccb = ExAllocatePoolWithTag(PagedPool, sizeof(ccb), ALLOC_TAG); root_ccb = ExAllocatePoolWithTag(PagedPool, sizeof(ccb), ALLOC_TAG);
@ -4596,25 +4622,21 @@ exit2:
if (Vcb->root_file) if (Vcb->root_file)
ObDereferenceObject(Vcb->root_file); ObDereferenceObject(Vcb->root_file);
else if (Vcb->root_fileref) { else if (Vcb->root_fileref)
acquire_fcb_lock_exclusive(Vcb); free_fileref(Vcb->root_fileref);
free_fileref(Vcb, Vcb->root_fileref); else if (root_fcb)
release_fcb_lock(Vcb); free_fcb(root_fcb);
} else if (root_fcb) {
acquire_fcb_lock_exclusive(Vcb);
free_fcb(Vcb, root_fcb);
release_fcb_lock(Vcb);
}
if (Vcb->volume_fcb) { if (root_fcb && root_fcb->refcount == 0)
acquire_fcb_lock_exclusive(Vcb); reap_fcb(root_fcb);
free_fcb(Vcb, Vcb->volume_fcb);
release_fcb_lock(Vcb); if (Vcb->volume_fcb)
} reap_fcb(Vcb->volume_fcb);
ExDeleteResourceLite(&Vcb->tree_lock); ExDeleteResourceLite(&Vcb->tree_lock);
ExDeleteResourceLite(&Vcb->load_lock); ExDeleteResourceLite(&Vcb->load_lock);
ExDeleteResourceLite(&Vcb->fcb_lock); ExDeleteResourceLite(&Vcb->fcb_lock);
ExDeleteResourceLite(&Vcb->fileref_lock);
ExDeleteResourceLite(&Vcb->chunk_lock); ExDeleteResourceLite(&Vcb->chunk_lock);
ExDeleteResourceLite(&Vcb->dirty_fcbs_lock); ExDeleteResourceLite(&Vcb->dirty_fcbs_lock);
ExDeleteResourceLite(&Vcb->dirty_filerefs_lock); ExDeleteResourceLite(&Vcb->dirty_filerefs_lock);

View file

@ -13,13 +13,11 @@
#undef APSTUDIO_READONLY_SYMBOLS #undef APSTUDIO_READONLY_SYMBOLS
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// English (U.K.) resources // English (United Kingdom) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma code_page(1252) #pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -27,18 +25,18 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
// TEXTINCLUDE // TEXTINCLUDE
// //
1 TEXTINCLUDE 1 TEXTINCLUDE
BEGIN BEGIN
"resource.h\0" "resource.h\0"
END END
2 TEXTINCLUDE 2 TEXTINCLUDE
BEGIN BEGIN
"#include ""winres.h""\r\n" "#include ""winres.h""\r\n"
"\0" "\0"
END END
3 TEXTINCLUDE 3 TEXTINCLUDE
BEGIN BEGIN
"\r\n" "\r\n"
"\0" "\0"
@ -53,8 +51,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,1,0,0 FILEVERSION 1,2,1,0
PRODUCTVERSION 1,1,0,0 PRODUCTVERSION 1,2,1,0
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -70,12 +68,12 @@ BEGIN
BLOCK "080904b0" BLOCK "080904b0"
BEGIN BEGIN
VALUE "FileDescription", "WinBtrfs" VALUE "FileDescription", "WinBtrfs"
VALUE "FileVersion", "1.1" VALUE "FileVersion", "1.2.1"
VALUE "InternalName", "btrfs" VALUE "InternalName", "btrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-18" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-19"
VALUE "OriginalFilename", "btrfs.sys" VALUE "OriginalFilename", "btrfs.sys"
VALUE "ProductName", "WinBtrfs" VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "1.1" VALUE "ProductVersion", "1.2.1"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
@ -84,7 +82,7 @@ BEGIN
END END
END END
#endif // English (U.K.) resources #endif // English (United Kingdom) resources
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////

View file

@ -260,6 +260,7 @@ typedef struct _fcb {
struct _device_extension* Vcb; struct _device_extension* Vcb;
struct _root* subvol; struct _root* subvol;
UINT64 inode; UINT64 inode;
UINT32 hash;
UINT8 type; UINT8 type;
INODE_ITEM inode_item; INODE_ITEM inode_item;
SECURITY_DESCRIPTOR* sd; SECURITY_DESCRIPTOR* sd;
@ -309,7 +310,6 @@ typedef struct _fcb {
typedef struct { typedef struct {
ERESOURCE fileref_lock; ERESOURCE fileref_lock;
ERESOURCE children_lock;
} file_ref_nonpaged; } file_ref_nonpaged;
typedef struct _file_ref { typedef struct _file_ref {
@ -392,7 +392,12 @@ typedef struct _tree_data {
}; };
} tree_data; } tree_data;
typedef struct {
FAST_MUTEX mutex;
} tree_nonpaged;
typedef struct _tree { typedef struct _tree {
tree_nonpaged* nonpaged;
tree_header header; tree_header header;
UINT32 hash; UINT32 hash;
BOOL has_address; BOOL has_address;
@ -428,7 +433,9 @@ typedef struct _root {
PEPROCESS reserved; PEPROCESS reserved;
UINT64 parent; UINT64 parent;
LONG send_ops; LONG send_ops;
UINT64 fcbs_version;
LIST_ENTRY fcbs; LIST_ENTRY fcbs;
LIST_ENTRY* fcbs_ptrs[256];
LIST_ENTRY list_entry; LIST_ENTRY list_entry;
LIST_ENTRY list_entry_dirty; LIST_ENTRY list_entry_dirty;
} root; } root;
@ -742,6 +749,7 @@ typedef struct _device_extension {
file_ref* root_fileref; file_ref* root_fileref;
LONG open_files; LONG open_files;
_Has_lock_level_(fcb_lock) ERESOURCE fcb_lock; _Has_lock_level_(fcb_lock) ERESOURCE fcb_lock;
ERESOURCE fileref_lock;
ERESOURCE load_lock; ERESOURCE load_lock;
_Has_lock_level_(tree_lock) ERESOURCE tree_lock; _Has_lock_level_(tree_lock) ERESOURCE tree_lock;
PNOTIFY_SYNC NotifySync; PNOTIFY_SYNC NotifySync;
@ -768,6 +776,7 @@ typedef struct _device_extension {
LIST_ENTRY trees; LIST_ENTRY trees;
LIST_ENTRY trees_hash; LIST_ENTRY trees_hash;
LIST_ENTRY* trees_ptrs[256]; LIST_ENTRY* trees_ptrs[256];
FAST_MUTEX trees_list_mutex;
LIST_ENTRY all_fcbs; LIST_ENTRY all_fcbs;
LIST_ENTRY dirty_fcbs; LIST_ENTRY dirty_fcbs;
ERESOURCE dirty_fcbs_lock; ERESOURCE dirty_fcbs_lock;
@ -1087,9 +1096,9 @@ BOOL get_xattr(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vc
_Out_ UINT8** data, _Out_ UINT16* datalen, _In_opt_ PIRP Irp); _Out_ UINT8** data, _Out_ UINT16* datalen, _In_opt_ PIRP Irp);
#ifndef DEBUG_FCB_REFCOUNTS #ifndef DEBUG_FCB_REFCOUNTS
void free_fcb(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ fcb* fcb); void free_fcb(_Inout_ fcb* fcb);
#endif #endif
void free_fileref(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ file_ref* fr); void free_fileref(_Inout_ file_ref* fr);
void protect_superblocks(_Inout_ chunk* c); void protect_superblocks(_Inout_ chunk* c);
BOOL is_top_level(_In_ PIRP Irp); BOOL is_top_level(_In_ PIRP Irp);
NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ UINT64 id, NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ UINT64 id,
@ -1129,6 +1138,10 @@ NTSTATUS NTAPI AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDev
#else #else
NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject); NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject);
#endif #endif
void reap_fcb(fcb* fcb);
void reap_fcbs(device_extension* Vcb);
void reap_fileref(device_extension* Vcb, file_ref* fr);
void reap_filerefs(device_extension* Vcb, file_ref* fr);
#ifdef _MSC_VER #ifdef _MSC_VER
#define funcname __FUNCTION__ #define funcname __FUNCTION__
@ -1192,8 +1205,8 @@ void _debug_message(_In_ const char* func, _In_ char* s, ...);
#endif #endif
#ifdef DEBUG_FCB_REFCOUNTS #ifdef DEBUG_FCB_REFCOUNTS
void _free_fcb(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ fcb* fcb, _In_ const char* func); void _free_fcb(_Inout_ fcb* fcb, _In_ const char* func);
#define free_fcb(Vcb, fcb) _free_fcb(Vcb, fcb, funcname) #define free_fcb(fcb) _free_fcb(fcb, funcname)
#endif #endif
// in fastio.c // in fastio.c
@ -1251,9 +1264,9 @@ NTSTATUS insert_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock)
_In_ UINT8 obj_type, _In_ UINT64 offset, _In_reads_bytes_opt_(size) _When_(return >= 0, __drv_aliasesMem) void* data, _In_ UINT8 obj_type, _In_ UINT64 offset, _In_reads_bytes_opt_(size) _When_(return >= 0, __drv_aliasesMem) void* data,
_In_ UINT16 size, _Out_opt_ traverse_ptr* ptp, _In_opt_ PIRP Irp); _In_ UINT16 size, _Out_opt_ traverse_ptr* ptp, _In_opt_ PIRP Irp);
NTSTATUS delete_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _Inout_ traverse_ptr* tp); NTSTATUS delete_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _Inout_ traverse_ptr* tp);
tree* free_tree(tree* t); void free_tree(tree* t);
NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT64 generation, PIRP Irp); NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, UINT8* buf, root* r, tree** pt);
NTSTATUS do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, BOOL* loaded, PIRP Irp); NTSTATUS do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, PIRP Irp);
void clear_rollback(LIST_ENTRY* rollback); void clear_rollback(LIST_ENTRY* rollback);
void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback); void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback);
void free_trees_root(device_extension* Vcb, root* r); void free_trees_root(device_extension* Vcb, root* r);
@ -1380,7 +1393,6 @@ NTSTATUS NTAPI drv_set_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
BOOL has_open_children(file_ref* fileref); BOOL has_open_children(file_ref* fileref);
NTSTATUS stream_set_end_of_file_information(device_extension* Vcb, UINT16 end, fcb* fcb, file_ref* fileref, BOOL advance_only); NTSTATUS stream_set_end_of_file_information(device_extension* Vcb, UINT16 end, fcb* fcb, file_ref* fileref, BOOL advance_only);
NTSTATUS fileref_get_filename(file_ref* fileref, PUNICODE_STRING fn, USHORT* name_offset, ULONG* preqlen); NTSTATUS fileref_get_filename(file_ref* fileref, PUNICODE_STRING fn, USHORT* name_offset, ULONG* preqlen);
NTSTATUS open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb, root* subvol, UINT64 inode, file_ref** pfr, PIRP Irp);
void insert_dir_child_into_hash_lists(fcb* fcb, dir_child* dc); void insert_dir_child_into_hash_lists(fcb* fcb, dir_child* dc);
void remove_dir_child_from_hash_lists(fcb* fcb, dir_child* dc); void remove_dir_child_from_hash_lists(fcb* fcb, dir_child* dc);
@ -1411,6 +1423,7 @@ fcb* create_fcb(device_extension* Vcb, POOL_TYPE pool_type);
NTSTATUS find_file_in_dir(PUNICODE_STRING filename, fcb* fcb, root** subvol, UINT64* inode, dir_child** pdc, BOOL case_sensitive); NTSTATUS find_file_in_dir(PUNICODE_STRING filename, fcb* fcb, root** subvol, UINT64* inode, dir_child** pdc, BOOL case_sensitive);
UINT32 inherit_mode(fcb* parfcb, BOOL is_dir); UINT32 inherit_mode(fcb* parfcb, BOOL is_dir);
file_ref* create_fileref(device_extension* Vcb); file_ref* create_fileref(device_extension* Vcb);
NTSTATUS open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb, root* subvol, UINT64 inode, file_ref** pfr, PIRP Irp);
// in fsctl.c // in fsctl.c
NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp, UINT32 type); NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp, UINT32 type);

File diff suppressed because it is too large Load diff

View file

@ -91,7 +91,7 @@ ULONG get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 t
ExReleaseResourceLite(fcb->Header.Resource); ExReleaseResourceLite(fcb->Header.Resource);
free_fcb(Vcb, fcb); free_fcb(fcb);
return tag; return tag;
} }
@ -602,7 +602,6 @@ static NTSTATUS query_directory(PIRP Irp) {
BOOL has_wildcard = FALSE, specific_file = FALSE, initial; BOOL has_wildcard = FALSE, specific_file = FALSE, initial;
dir_entry de; dir_entry de;
UINT64 newoffset; UINT64 newoffset;
ANSI_STRING utf8;
dir_child* dc = NULL; dir_child* dc = NULL;
TRACE("query directory\n"); TRACE("query directory\n");
@ -612,8 +611,6 @@ static NTSTATUS query_directory(PIRP Irp) {
ccb = IrpSp->FileObject->FsContext2; ccb = IrpSp->FileObject->FsContext2;
fileref = ccb ? ccb->fileref : NULL; fileref = ccb ? ccb->fileref : NULL;
utf8.Buffer = NULL;
if (!fileref) if (!fileref)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
@ -642,11 +639,6 @@ static NTSTATUS query_directory(PIRP Irp) {
if (fileref->fcb == Vcb->dummy_fcb) if (fileref->fcb == Vcb->dummy_fcb)
return STATUS_NO_MORE_FILES; return STATUS_NO_MORE_FILES;
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
acquire_fcb_lock_shared(Vcb);
TRACE("%S\n", file_desc(IrpSp->FileObject));
if (IrpSp->Flags == 0) { if (IrpSp->Flags == 0) {
TRACE("QD flags: (none)\n"); TRACE("QD flags: (none)\n");
} else { } else {
@ -708,8 +700,7 @@ static NTSTATUS query_directory(PIRP Irp) {
ccb->query_string.Buffer = ExAllocatePoolWithTag(PagedPool, IrpSp->Parameters.QueryDirectory.FileName->Length, ALLOC_TAG); ccb->query_string.Buffer = ExAllocatePoolWithTag(PagedPool, IrpSp->Parameters.QueryDirectory.FileName->Length, ALLOC_TAG);
if (!ccb->query_string.Buffer) { if (!ccb->query_string.Buffer) {
ERR("out of memory\n"); ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
goto end2;
} }
ccb->query_string.Length = ccb->query_string.MaximumLength = IrpSp->Parameters.QueryDirectory.FileName->Length; ccb->query_string.Length = ccb->query_string.MaximumLength = IrpSp->Parameters.QueryDirectory.FileName->Length;
@ -725,10 +716,8 @@ static NTSTATUS query_directory(PIRP Irp) {
if (!(IrpSp->Flags & SL_RESTART_SCAN)) { if (!(IrpSp->Flags & SL_RESTART_SCAN)) {
initial = FALSE; initial = FALSE;
if (specific_file) { if (specific_file)
Status = STATUS_NO_MORE_FILES; return STATUS_NO_MORE_FILES;
goto end2;
}
} }
} }
@ -738,6 +727,8 @@ static NTSTATUS query_directory(PIRP Irp) {
newoffset = ccb->query_dir_offset; newoffset = ccb->query_dir_offset;
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
ExAcquireResourceSharedLite(&fileref->fcb->nonpaged->dir_children_lock, TRUE); ExAcquireResourceSharedLite(&fileref->fcb->nonpaged->dir_children_lock, TRUE);
Status = next_dir_entry(fileref, &newoffset, &de, &dc); Status = next_dir_entry(fileref, &newoffset, &de, &dc);
@ -923,15 +914,10 @@ static NTSTATUS query_directory(PIRP Irp) {
end: end:
ExReleaseResourceLite(&fileref->fcb->nonpaged->dir_children_lock); ExReleaseResourceLite(&fileref->fcb->nonpaged->dir_children_lock);
end2:
release_fcb_lock(Vcb);
ExReleaseResourceLite(&Vcb->tree_lock); ExReleaseResourceLite(&Vcb->tree_lock);
TRACE("returning %08x\n", Status); TRACE("returning %08x\n", Status);
if (utf8.Buffer)
ExFreePool(utf8.Buffer);
return Status; return Status;
} }

View file

@ -19,7 +19,7 @@
#if (NTDDI_VERSION >= NTDDI_WIN10) #if (NTDDI_VERSION >= NTDDI_WIN10)
// not currently in mingw - introduced with Windows 10 // not currently in mingw - introduced with Windows 10
#ifndef FileIdInformation #ifndef _MSC_VER
#define FileIdInformation (enum _FILE_INFORMATION_CLASS)59 #define FileIdInformation (enum _FILE_INFORMATION_CLASS)59
#define FileStatLxInformation (enum _FILE_INFORMATION_CLASS)70 #define FileStatLxInformation (enum _FILE_INFORMATION_CLASS)70
@ -230,8 +230,6 @@ static NTSTATUS set_disposition_information(device_extension* Vcb, PIRP Irp, PFI
if (!fileref) if (!fileref)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
acquire_fcb_lock_exclusive(Vcb);
ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE); ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
TRACE("changing delete_on_close to %s for %S (fcb %p)\n", fdi->DeleteFile ? "TRUE" : "FALSE", file_desc(FileObject), fcb); TRACE("changing delete_on_close to %s for %S (fcb %p)\n", fdi->DeleteFile ? "TRUE" : "FALSE", file_desc(FileObject), fcb);
@ -277,8 +275,6 @@ static NTSTATUS set_disposition_information(device_extension* Vcb, PIRP Irp, PFI
end: end:
ExReleaseResourceLite(fcb->Header.Resource); ExReleaseResourceLite(fcb->Header.Resource);
release_fcb_lock(Vcb);
// send notification that directory is about to be deleted // send notification that directory is about to be deleted
if (NT_SUCCESS(Status) && fdi->DeleteFile && fcb->type == BTRFS_TYPE_DIRECTORY) { if (NT_SUCCESS(Status) && fdi->DeleteFile && fcb->type == BTRFS_TYPE_DIRECTORY) {
FsRtlNotifyFullChangeDirectory(Vcb->NotifySync, &Vcb->DirNotifyList, FileObject->FsContext, FsRtlNotifyFullChangeDirectory(Vcb->NotifySync, &Vcb->DirNotifyList, FileObject->FsContext,
@ -343,7 +339,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
if (!fcb->adsxattr.Buffer) { if (!fcb->adsxattr.Buffer) {
ERR("out of memory\n"); ERR("out of memory\n");
free_fcb(Vcb, fcb); free_fcb(fcb);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -357,7 +353,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
if (!fcb->adsdata.Buffer) { if (!fcb->adsdata.Buffer) {
ERR("out of memory\n"); ERR("out of memory\n");
free_fcb(Vcb, fcb); free_fcb(fcb);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -374,7 +370,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
fcb->sd = ExAllocatePoolWithTag(PagedPool, RtlLengthSecurityDescriptor(oldfcb->sd), ALLOC_TAG); fcb->sd = ExAllocatePoolWithTag(PagedPool, RtlLengthSecurityDescriptor(oldfcb->sd), ALLOC_TAG);
if (!fcb->sd) { if (!fcb->sd) {
ERR("out of memory\n"); ERR("out of memory\n");
free_fcb(Vcb, fcb); free_fcb(fcb);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -392,7 +388,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
if (!ext2) { if (!ext2) {
ERR("out of memory\n"); ERR("out of memory\n");
free_fcb(Vcb, fcb); free_fcb(fcb);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -420,7 +416,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
ext2->csum = ExAllocatePoolWithTag(PagedPool, len, ALLOC_TAG); ext2->csum = ExAllocatePoolWithTag(PagedPool, len, ALLOC_TAG);
if (!ext2->csum) { if (!ext2->csum) {
ERR("out of memory\n"); ERR("out of memory\n");
free_fcb(Vcb, fcb); free_fcb(fcb);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -442,7 +438,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
if (!hl2) { if (!hl2) {
ERR("out of memory\n"); ERR("out of memory\n");
free_fcb(Vcb, fcb); free_fcb(fcb);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -455,7 +451,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
if (!hl2->name.Buffer) { if (!hl2->name.Buffer) {
ERR("out of memory\n"); ERR("out of memory\n");
ExFreePool(hl2); ExFreePool(hl2);
free_fcb(Vcb, fcb); free_fcb(fcb);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -468,7 +464,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
ERR("out of memory\n"); ERR("out of memory\n");
ExFreePool(hl2->name.Buffer); ExFreePool(hl2->name.Buffer);
ExFreePool(hl2); ExFreePool(hl2);
free_fcb(Vcb, fcb); free_fcb(fcb);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -485,7 +481,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
fcb->reparse_xattr.Buffer = ExAllocatePoolWithTag(PagedPool, fcb->reparse_xattr.MaximumLength, ALLOC_TAG); fcb->reparse_xattr.Buffer = ExAllocatePoolWithTag(PagedPool, fcb->reparse_xattr.MaximumLength, ALLOC_TAG);
if (!fcb->reparse_xattr.Buffer) { if (!fcb->reparse_xattr.Buffer) {
ERR("out of memory\n"); ERR("out of memory\n");
free_fcb(Vcb, fcb); free_fcb(fcb);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -498,7 +494,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
fcb->ea_xattr.Buffer = ExAllocatePoolWithTag(PagedPool, fcb->ea_xattr.MaximumLength, ALLOC_TAG); fcb->ea_xattr.Buffer = ExAllocatePoolWithTag(PagedPool, fcb->ea_xattr.MaximumLength, ALLOC_TAG);
if (!fcb->ea_xattr.Buffer) { if (!fcb->ea_xattr.Buffer) {
ERR("out of memory\n"); ERR("out of memory\n");
free_fcb(Vcb, fcb); free_fcb(fcb);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -518,7 +514,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
if (!xa2) { if (!xa2) {
ERR("out of memory\n"); ERR("out of memory\n");
free_fcb(Vcb, fcb); free_fcb(fcb);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -666,11 +662,13 @@ static NTSTATUS create_directory_fcb(device_extension* Vcb, root* r, fcb* parfcb
Status = SeAssignSecurity(parfcb->sd, NULL, (void**)&fcb->sd, TRUE, &subjcont, IoGetFileObjectGenericMapping(), PagedPool); Status = SeAssignSecurity(parfcb->sd, NULL, (void**)&fcb->sd, TRUE, &subjcont, IoGetFileObjectGenericMapping(), PagedPool);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
reap_fcb(fcb);
ERR("SeAssignSecurity returned %08x\n", Status); ERR("SeAssignSecurity returned %08x\n", Status);
return Status; return Status;
} }
if (!fcb->sd) { if (!fcb->sd) {
reap_fcb(fcb);
ERR("SeAssignSecurity returned NULL security descriptor\n"); ERR("SeAssignSecurity returned NULL security descriptor\n");
return STATUS_INTERNAL_ERROR; return STATUS_INTERNAL_ERROR;
} }
@ -689,16 +687,12 @@ static NTSTATUS create_directory_fcb(device_extension* Vcb, root* r, fcb* parfcb
fcb->inode_item_changed = TRUE; fcb->inode_item_changed = TRUE;
InsertTailList(&r->fcbs, &fcb->list_entry);
InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
fcb->Header.IsFastIoPossible = fast_io_possible(fcb); fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
fcb->Header.AllocationSize.QuadPart = 0; fcb->Header.AllocationSize.QuadPart = 0;
fcb->Header.FileSize.QuadPart = 0; fcb->Header.FileSize.QuadPart = 0;
fcb->Header.ValidDataLength.QuadPart = 0; fcb->Header.ValidDataLength.QuadPart = 0;
fcb->created = TRUE; fcb->created = TRUE;
mark_fcb_dirty(fcb);
if (parfcb->inode_item.flags & BTRFS_INODE_COMPRESS) if (parfcb->inode_item.flags & BTRFS_INODE_COMPRESS)
fcb->inode_item.flags |= BTRFS_INODE_COMPRESS; fcb->inode_item.flags |= BTRFS_INODE_COMPRESS;
@ -722,6 +716,14 @@ static NTSTATUS create_directory_fcb(device_extension* Vcb, root* r, fcb* parfcb
RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256); RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
acquire_fcb_lock_exclusive(Vcb);
InsertTailList(&r->fcbs, &fcb->list_entry);
InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
r->fcbs_version++;
release_fcb_lock(Vcb);
mark_fcb_dirty(fcb);
*pfcb = fcb; *pfcb = fcb;
return STATUS_SUCCESS; return STATUS_SUCCESS;
@ -735,11 +737,15 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb, file_ref* destd
BTRFS_TIME now; BTRFS_TIME now;
file_ref* origparent; file_ref* origparent;
// FIXME - make sure me->dummyfileref and me->dummyfcb get freed properly
InitializeListHead(&move_list); InitializeListHead(&move_list);
KeQuerySystemTime(&time); KeQuerySystemTime(&time);
win_time_to_unix(time, &now); win_time_to_unix(time, &now);
acquire_fcb_lock_exclusive(fileref->fcb->Vcb);
me = ExAllocatePoolWithTag(PagedPool, sizeof(move_entry), ALLOC_TAG); me = ExAllocatePoolWithTag(PagedPool, sizeof(move_entry), ALLOC_TAG);
if (!me) { if (!me) {
@ -1020,9 +1026,9 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb, file_ref* destd
me->dummyfileref->parent = me->parent ? me->parent->dummyfileref : origparent; me->dummyfileref->parent = me->parent ? me->parent->dummyfileref : origparent;
increase_fileref_refcount(me->dummyfileref->parent); increase_fileref_refcount(me->dummyfileref->parent);
ExAcquireResourceExclusiveLite(&me->dummyfileref->parent->nonpaged->children_lock, TRUE); ExAcquireResourceExclusiveLite(&me->dummyfileref->parent->fcb->nonpaged->dir_children_lock, TRUE);
InsertTailList(&me->dummyfileref->parent->children, &me->dummyfileref->list_entry); InsertTailList(&me->dummyfileref->parent->children, &me->dummyfileref->list_entry);
ExReleaseResourceLite(&me->dummyfileref->parent->nonpaged->children_lock); ExReleaseResourceLite(&me->dummyfileref->parent->fcb->nonpaged->dir_children_lock);
me->dummyfileref->debug_desc = me->fileref->debug_desc; me->dummyfileref->debug_desc = me->fileref->debug_desc;
@ -1104,12 +1110,12 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb, file_ref* destd
ExReleaseResourceLite(&destdir->fcb->nonpaged->dir_children_lock); ExReleaseResourceLite(&destdir->fcb->nonpaged->dir_children_lock);
} }
free_fileref(fileref->fcb->Vcb, me->fileref->parent); free_fileref(me->fileref->parent);
me->fileref->parent = destdir; me->fileref->parent = destdir;
ExAcquireResourceExclusiveLite(&me->fileref->parent->nonpaged->children_lock, TRUE); ExAcquireResourceExclusiveLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock, TRUE);
InsertTailList(&me->fileref->parent->children, &me->fileref->list_entry); InsertTailList(&me->fileref->parent->children, &me->fileref->list_entry);
ExReleaseResourceLite(&me->fileref->parent->nonpaged->children_lock); ExReleaseResourceLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock);
TRACE("me->fileref->parent->fcb->inode_item.st_size (inode %llx) was %llx\n", me->fileref->parent->fcb->inode, me->fileref->parent->fcb->inode_item.st_size); TRACE("me->fileref->parent->fcb->inode_item.st_size (inode %llx) was %llx\n", me->fileref->parent->fcb->inode, me->fileref->parent->fcb->inode_item.st_size);
me->fileref->parent->fcb->inode_item.st_size += me->fileref->dc->utf8.Length * 2; me->fileref->parent->fcb->inode_item.st_size += me->fileref->dc->utf8.Length * 2;
@ -1237,16 +1243,21 @@ end:
me = CONTAINING_RECORD(le, move_entry, list_entry); me = CONTAINING_RECORD(le, move_entry, list_entry);
if (me->dummyfcb) if (me->dummyfcb)
free_fcb(fileref->fcb->Vcb, me->dummyfcb); free_fcb(me->dummyfcb);
if (me->dummyfileref) if (me->dummyfileref)
free_fileref(fileref->fcb->Vcb, me->dummyfileref); free_fileref(me->dummyfileref);
free_fileref(fileref->fcb->Vcb, me->fileref); free_fileref(me->fileref);
ExFreePool(me); ExFreePool(me);
} }
destdir->fcb->subvol->fcbs_version++;
fileref->fcb->subvol->fcbs_version++;
release_fcb_lock(fileref->fcb->Vcb);
return Status; return Status;
} }
@ -1390,7 +1401,7 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB
} }
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE); ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
acquire_fcb_lock_exclusive(Vcb); ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, TRUE);
ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE); ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
if (fcb->ads) { if (fcb->ads) {
@ -1457,7 +1468,7 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB
} }
if (fileref == oldfileref || oldfileref->deleted) { if (fileref == oldfileref || oldfileref->deleted) {
free_fileref(Vcb, oldfileref); free_fileref(oldfileref);
oldfileref = NULL; oldfileref = NULL;
} }
} }
@ -1726,10 +1737,10 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB
fileref->created = TRUE; fileref->created = TRUE;
fileref->parent = related; fileref->parent = related;
ExAcquireResourceExclusiveLite(&fileref->parent->nonpaged->children_lock, TRUE); ExAcquireResourceExclusiveLite(&fileref->parent->fcb->nonpaged->dir_children_lock, TRUE);
InsertHeadList(&fileref->list_entry, &fr2->list_entry); InsertHeadList(&fileref->list_entry, &fr2->list_entry);
RemoveEntryList(&fileref->list_entry); RemoveEntryList(&fileref->list_entry);
ExReleaseResourceLite(&fileref->parent->nonpaged->children_lock); ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
mark_fileref_dirty(fr2); mark_fileref_dirty(fr2);
mark_fileref_dirty(fileref); mark_fileref_dirty(fileref);
@ -1794,9 +1805,9 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB
ExReleaseResourceLite(&related->fcb->nonpaged->dir_children_lock); ExReleaseResourceLite(&related->fcb->nonpaged->dir_children_lock);
} }
ExAcquireResourceExclusiveLite(&related->nonpaged->children_lock, TRUE); ExAcquireResourceExclusiveLite(&related->fcb->nonpaged->dir_children_lock, TRUE);
InsertTailList(&related->children, &fileref->list_entry); InsertTailList(&related->children, &fileref->list_entry);
ExReleaseResourceLite(&related->nonpaged->children_lock); ExReleaseResourceLite(&related->fcb->nonpaged->dir_children_lock);
if (fcb->inode_item.st_nlink > 1) { if (fcb->inode_item.st_nlink > 1) {
// add new hardlink entry to fcb // add new hardlink entry to fcb
@ -1900,7 +1911,7 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB
fr2->parent->fcb->inode_item.st_ctime = now; fr2->parent->fcb->inode_item.st_ctime = now;
fr2->parent->fcb->inode_item.st_mtime = now; fr2->parent->fcb->inode_item.st_mtime = now;
free_fileref(Vcb, fr2); free_fileref(fr2);
fr2->parent->fcb->inode_item_changed = TRUE; fr2->parent->fcb->inode_item_changed = TRUE;
mark_fcb_dirty(fr2->parent->fcb); mark_fcb_dirty(fr2->parent->fcb);
@ -1913,13 +1924,13 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB
end: end:
if (oldfileref) if (oldfileref)
free_fileref(Vcb, oldfileref); free_fileref(oldfileref);
if (!NT_SUCCESS(Status) && related) if (!NT_SUCCESS(Status) && related)
free_fileref(Vcb, related); free_fileref(related);
if (!NT_SUCCESS(Status) && fr2) if (!NT_SUCCESS(Status) && fr2)
free_fileref(Vcb, fr2); free_fileref(fr2);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
clear_rollback(&rollback); clear_rollback(&rollback);
@ -1927,7 +1938,7 @@ end:
do_rollback(Vcb, &rollback); do_rollback(Vcb, &rollback);
ExReleaseResourceLite(fcb->Header.Resource); ExReleaseResourceLite(fcb->Header.Resource);
release_fcb_lock(Vcb); ExReleaseResourceLite(&Vcb->fileref_lock);
ExReleaseResourceLite(&Vcb->tree_lock); ExReleaseResourceLite(&Vcb->tree_lock);
return Status; return Status;
@ -2227,7 +2238,7 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJE
} }
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE); ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
acquire_fcb_lock_exclusive(Vcb); ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, TRUE);
ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE); ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
if (fcb->type == BTRFS_TYPE_DIRECTORY) { if (fcb->type == BTRFS_TYPE_DIRECTORY) {
@ -2299,7 +2310,7 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJE
goto end; goto end;
} }
} else { } else {
free_fileref(Vcb, oldfileref); free_fileref(oldfileref);
oldfileref = NULL; oldfileref = NULL;
} }
} }
@ -2364,9 +2375,9 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJE
fr2->dc = dc; fr2->dc = dc;
dc->fileref = fr2; dc->fileref = fr2;
ExAcquireResourceExclusiveLite(&related->nonpaged->children_lock, TRUE); ExAcquireResourceExclusiveLite(&related->fcb->nonpaged->dir_children_lock, TRUE);
InsertTailList(&related->children, &fr2->list_entry); InsertTailList(&related->children, &fr2->list_entry);
ExReleaseResourceLite(&related->nonpaged->children_lock); ExReleaseResourceLite(&related->fcb->nonpaged->dir_children_lock);
// add hardlink for existing fileref, if it's not there already // add hardlink for existing fileref, if it's not there already
if (IsListEmpty(&fcb->hardlinks)) { if (IsListEmpty(&fcb->hardlinks)) {
@ -2447,7 +2458,7 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJE
InsertTailList(&fcb->hardlinks, &hl->list_entry); InsertTailList(&fcb->hardlinks, &hl->list_entry);
mark_fileref_dirty(fr2); mark_fileref_dirty(fr2);
free_fileref(Vcb, fr2); free_fileref(fr2);
// update inode's INODE_ITEM // update inode's INODE_ITEM
@ -2482,13 +2493,13 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJE
end: end:
if (oldfileref) if (oldfileref)
free_fileref(Vcb, oldfileref); free_fileref(oldfileref);
if (!NT_SUCCESS(Status) && related) if (!NT_SUCCESS(Status) && related)
free_fileref(Vcb, related); free_fileref(related);
if (!NT_SUCCESS(Status) && fr2) if (!NT_SUCCESS(Status) && fr2)
free_fileref(Vcb, fr2); free_fileref(fr2);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
clear_rollback(&rollback); clear_rollback(&rollback);
@ -2496,7 +2507,7 @@ end:
do_rollback(Vcb, &rollback); do_rollback(Vcb, &rollback);
ExReleaseResourceLite(fcb->Header.Resource); ExReleaseResourceLite(fcb->Header.Resource);
release_fcb_lock(Vcb); ExReleaseResourceLite(&Vcb->fileref_lock);
ExReleaseResourceLite(&Vcb->tree_lock); ExReleaseResourceLite(&Vcb->tree_lock);
return Status; return Status;
@ -3186,282 +3197,7 @@ static NTSTATUS fill_in_file_standard_link_information(FILE_STANDARD_LINK_INFORM
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
#endif /* __REACTOS__ */
NTSTATUS open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb,
root* subvol, UINT64 inode, file_ref** pfr, PIRP Irp) {
NTSTATUS Status;
fcb* fcb;
UINT64 parent = 0;
UNICODE_STRING name;
BOOL hl_alloc = FALSE;
file_ref *parfr, *fr;
Status = open_fcb(Vcb, subvol, inode, 0, NULL, NULL, &fcb, PagedPool, Irp);
if (!NT_SUCCESS(Status)) {
ERR("open_fcb returned %08x\n", Status);
return Status;
}
if (fcb->fileref) {
*pfr = fcb->fileref;
increase_fileref_refcount(fcb->fileref);
return STATUS_SUCCESS;
}
// find hardlink if fcb doesn't have any loaded
if (IsListEmpty(&fcb->hardlinks)) {
KEY searchkey;
traverse_ptr tp;
searchkey.obj_id = fcb->inode;
searchkey.obj_type = TYPE_INODE_EXTREF;
searchkey.offset = 0xffffffffffffffff;
Status = find_item(Vcb, fcb->subvol, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("find_item returned %08x\n", Status);
free_fcb(Vcb, fcb);
return Status;
}
if (tp.item->key.obj_id == fcb->inode) {
if (tp.item->key.obj_type == TYPE_INODE_REF) {
INODE_REF* ir;
ULONG stringlen;
ir = (INODE_REF*)tp.item->data;
parent = tp.item->key.offset;
Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, ir->name, ir->n);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
free_fcb(Vcb, fcb);
return Status;
}
name.Length = name.MaximumLength = (UINT16)stringlen;
if (stringlen == 0)
name.Buffer = NULL;
else {
name.Buffer = ExAllocatePoolWithTag(PagedPool, name.MaximumLength, ALLOC_TAG);
if (!name.Buffer) {
ERR("out of memory\n");
free_fcb(Vcb, fcb);
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = RtlUTF8ToUnicodeN(name.Buffer, stringlen, &stringlen, ir->name, ir->n);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
ExFreePool(name.Buffer);
free_fcb(Vcb, fcb);
return Status;
}
hl_alloc = TRUE;
}
} else if (tp.item->key.obj_type == TYPE_INODE_EXTREF) {
INODE_EXTREF* ier;
ULONG stringlen;
ier = (INODE_EXTREF*)tp.item->data;
parent = ier->dir;
Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, ier->name, ier->n);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
free_fcb(Vcb, fcb);
return Status;
}
name.Length = name.MaximumLength = (UINT16)stringlen;
if (stringlen == 0)
name.Buffer = NULL;
else {
name.Buffer = ExAllocatePoolWithTag(PagedPool, name.MaximumLength, ALLOC_TAG);
if (!name.Buffer) {
ERR("out of memory\n");
free_fcb(Vcb, fcb);
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = RtlUTF8ToUnicodeN(name.Buffer, stringlen, &stringlen, ier->name, ier->n);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
ExFreePool(name.Buffer);
free_fcb(Vcb, fcb);
return Status;
}
hl_alloc = TRUE;
}
}
}
} else {
hardlink* hl = CONTAINING_RECORD(fcb->hardlinks.Flink, hardlink, list_entry);
name = hl->name;
parent = hl->parent;
}
if (parent == 0) {
ERR("subvol %llx, inode %llx has no hardlinks\n", subvol->id, inode);
free_fcb(Vcb, fcb);
if (hl_alloc) ExFreePool(name.Buffer);
return STATUS_INVALID_PARAMETER;
}
if (parent == inode) { // subvolume root
KEY searchkey;
traverse_ptr tp;
searchkey.obj_id = subvol->id;
searchkey.obj_type = TYPE_ROOT_BACKREF;
searchkey.offset = 0xffffffffffffffff;
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("find_item returned %08x\n", Status);
free_fcb(Vcb, fcb);
if (hl_alloc) ExFreePool(name.Buffer);
return Status;
}
if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
ROOT_REF* rr = (ROOT_REF*)tp.item->data;
LIST_ENTRY* le;
root* r = NULL;
ULONG stringlen;
if (tp.item->size < sizeof(ROOT_REF)) {
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(ROOT_REF));
free_fcb(Vcb, fcb);
if (hl_alloc) ExFreePool(name.Buffer);
return STATUS_INTERNAL_ERROR;
}
if (tp.item->size < offsetof(ROOT_REF, name[0]) + rr->n) {
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, offsetof(ROOT_REF, name[0]) + rr->n);
free_fcb(Vcb, fcb);
if (hl_alloc) ExFreePool(name.Buffer);
return STATUS_INTERNAL_ERROR;
}
le = Vcb->roots.Flink;
while (le != &Vcb->roots) {
root* r2 = CONTAINING_RECORD(le, root, list_entry);
if (r2->id == tp.item->key.offset) {
r = r2;
break;
}
le = le->Flink;
}
if (!r) {
ERR("couldn't find subvol %llx\n", tp.item->key.offset);
free_fcb(Vcb, fcb);
if (hl_alloc) ExFreePool(name.Buffer);
return STATUS_INTERNAL_ERROR;
}
Status = open_fileref_by_inode(Vcb, r, rr->dir, &parfr, Irp);
if (!NT_SUCCESS(Status)) {
ERR("open_fileref_by_inode returned %08x\n", Status);
free_fcb(Vcb, fcb);
if (hl_alloc) ExFreePool(name.Buffer);
return Status;
}
if (hl_alloc) {
ExFreePool(name.Buffer);
hl_alloc = FALSE;
}
Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, rr->name, rr->n);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
free_fcb(Vcb, fcb);
return Status;
}
name.Length = name.MaximumLength = (UINT16)stringlen;
if (stringlen == 0)
name.Buffer = NULL;
else {
name.Buffer = ExAllocatePoolWithTag(PagedPool, name.MaximumLength, ALLOC_TAG);
if (!name.Buffer) {
ERR("out of memory\n");
free_fcb(Vcb, fcb);
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = RtlUTF8ToUnicodeN(name.Buffer, stringlen, &stringlen, rr->name, rr->n);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
ExFreePool(name.Buffer);
free_fcb(Vcb, fcb);
return Status;
}
hl_alloc = TRUE;
}
} else {
ERR("couldn't find parent for subvol %llx\n", subvol->id);
free_fcb(Vcb, fcb);
if (hl_alloc) ExFreePool(name.Buffer);
return STATUS_INTERNAL_ERROR;
}
} else {
Status = open_fileref_by_inode(Vcb, subvol, parent, &parfr, Irp);
if (!NT_SUCCESS(Status)) {
ERR("open_fileref_by_inode returned %08x\n", Status);
free_fcb(Vcb, fcb);
if (hl_alloc)
ExFreePool(name.Buffer);
return Status;
}
}
Status = open_fileref_child(Vcb, parfr, &name, TRUE, TRUE, FALSE, PagedPool, &fr, Irp);
if (!NT_SUCCESS(Status)) {
ERR("open_fileref_child returned %08x\n", Status);
if (hl_alloc)
ExFreePool(name.Buffer);
free_fcb(Vcb, fcb);
free_fileref(Vcb, parfr);
return Status;
}
*pfr = fr;
if (hl_alloc)
ExFreePool(name.Buffer);
free_fcb(Vcb, fcb);
free_fileref(Vcb, parfr);
return STATUS_SUCCESS;
}
#ifndef __REACTOS__
static NTSTATUS fill_in_hard_link_information(FILE_LINKS_INFORMATION* fli, file_ref* fileref, PIRP Irp, LONG* length) { static NTSTATUS fill_in_hard_link_information(FILE_LINKS_INFORMATION* fli, file_ref* fileref, PIRP Irp, LONG* length) {
NTSTATUS Status; NTSTATUS Status;
LIST_ENTRY* le; LIST_ENTRY* le;
@ -3517,7 +3253,7 @@ static NTSTATUS fill_in_hard_link_information(FILE_LINKS_INFORMATION* fli, file_
len = bytes_needed; len = bytes_needed;
} }
} else { } else {
acquire_fcb_lock_exclusive(fcb->Vcb); ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, TRUE);
if (IsListEmpty(&fcb->hardlinks)) { if (IsListEmpty(&fcb->hardlinks)) {
bytes_needed += sizeof(FILE_LINK_ENTRY_INFORMATION) + fileref->dc->name.Length - sizeof(WCHAR); bytes_needed += sizeof(FILE_LINK_ENTRY_INFORMATION) + fileref->dc->name.Length - sizeof(WCHAR);
@ -3603,14 +3339,14 @@ static NTSTATUS fill_in_hard_link_information(FILE_LINKS_INFORMATION* fli, file_
} }
} }
free_fileref(fcb->Vcb, parfr); free_fileref(parfr);
} }
le = le->Flink; le = le->Flink;
} }
} }
release_fcb_lock(fcb->Vcb); ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
} }
fli->BytesNeeded = bytes_needed; fli->BytesNeeded = bytes_needed;

View file

@ -2704,7 +2704,11 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp, LIST_ENTRY*
} }
} }
free_fcb(Vcb, c->old_cache); free_fcb(c->old_cache);
if (c->old_cache->refcount == 0)
reap_fcb(c->old_cache);
c->old_cache = NULL; c->old_cache = NULL;
} }
@ -2810,6 +2814,18 @@ static NTSTATUS split_tree_at(device_extension* Vcb, tree* t, tree_data* newfirs
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
if (t->header.level > 0) {
nt->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(tree_nonpaged), ALLOC_TAG);
if (!nt->nonpaged) {
ERR("out of memory\n");
ExFreePool(nt);
return STATUS_INSUFFICIENT_RESOURCES;
}
ExInitializeFastMutex(&nt->nonpaged->mutex);
} else
nt->nonpaged = NULL;
RtlCopyMemory(&nt->header, &t->header, sizeof(tree_header)); RtlCopyMemory(&nt->header, &t->header, sizeof(tree_header));
nt->header.address = 0; nt->header.address = 0;
nt->header.generation = Vcb->superblock.generation; nt->header.generation = Vcb->superblock.generation;
@ -2924,6 +2940,15 @@ static NTSTATUS split_tree_at(device_extension* Vcb, tree* t, tree_data* newfirs
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
pt->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(tree_nonpaged), ALLOC_TAG);
if (!pt->nonpaged) {
ERR("out of memory\n");
ExFreePool(pt);
return STATUS_INSUFFICIENT_RESOURCES;
}
ExInitializeFastMutex(&pt->nonpaged->mutex);
RtlCopyMemory(&pt->header, &nt->header, sizeof(tree_header)); RtlCopyMemory(&pt->header, &nt->header, sizeof(tree_header));
pt->header.address = 0; pt->header.address = 0;
pt->header.num_items = 2; pt->header.num_items = 2;
@ -3103,7 +3128,6 @@ static NTSTATUS try_tree_amalgamate(device_extension* Vcb, tree* t, BOOL* done,
tree_data* nextparitem = NULL; tree_data* nextparitem = NULL;
NTSTATUS Status; NTSTATUS Status;
tree *next_tree, *par; tree *next_tree, *par;
BOOL loaded;
*done = FALSE; *done = FALSE;
@ -3127,10 +3151,12 @@ static NTSTATUS try_tree_amalgamate(device_extension* Vcb, tree* t, BOOL* done,
TRACE("nextparitem: key = %llx,%x,%llx\n", nextparitem->key.obj_id, nextparitem->key.obj_type, nextparitem->key.offset); TRACE("nextparitem: key = %llx,%x,%llx\n", nextparitem->key.obj_id, nextparitem->key.obj_type, nextparitem->key.offset);
Status = do_load_tree(Vcb, &nextparitem->treeholder, t->root, t->parent, nextparitem, &loaded, NULL); if (!nextparitem->treeholder.tree) {
if (!NT_SUCCESS(Status)) { Status = do_load_tree(Vcb, &nextparitem->treeholder, t->root, t->parent, nextparitem, NULL);
ERR("do_load_tree returned %08x\n", Status); if (!NT_SUCCESS(Status)) {
return Status; ERR("do_load_tree returned %08x\n", Status);
return Status;
}
} }
if (!is_tree_unique(Vcb, nextparitem->treeholder.tree, Irp)) if (!is_tree_unique(Vcb, nextparitem->treeholder.tree, Irp))
@ -3667,7 +3693,27 @@ static NTSTATUS remove_root_extents(device_extension* Vcb, root* r, tree_holder*
NTSTATUS Status; NTSTATUS Status;
if (!th->tree) { if (!th->tree) {
Status = load_tree(Vcb, th->address, r, &th->tree, th->generation, NULL); UINT8* buf;
chunk* c;
buf = ExAllocatePoolWithTag(PagedPool, Vcb->superblock.node_size, ALLOC_TAG);
if (!buf) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = read_data(Vcb, th->address, Vcb->superblock.node_size, NULL, TRUE, buf, NULL,
&c, Irp, th->generation, FALSE, NormalPagePriority);
if (!NT_SUCCESS(Status)) {
ERR("read_data returned 0x%08x\n", Status);
ExFreePool(buf);
return Status;
}
Status = load_tree(Vcb, th->address, buf, r, &th->tree);
if (!th->tree || th->tree->buf != buf)
ExFreePool(buf);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("load_tree(%llx) returned %08x\n", th->address, Status); ERR("load_tree(%llx) returned %08x\n", th->address, Status);
@ -4070,6 +4116,7 @@ static NTSTATUS create_chunk(device_extension* Vcb, chunk* c, PIRP Irp) {
} }
c->created = FALSE; c->created = FALSE;
c->oldused = c->used;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -5194,7 +5241,10 @@ static NTSTATUS drop_chunk(device_extension* Vcb, chunk* c, LIST_ENTRY* batchlis
Status = flush_fcb(c->cache, TRUE, batchlist, Irp); Status = flush_fcb(c->cache, TRUE, batchlist, Irp);
free_fcb(Vcb, c->cache); free_fcb(c->cache);
if (c->cache->refcount == 0)
reap_fcb(c->cache);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("flush_fcb returned %08x\n", Status); ERR("flush_fcb returned %08x\n", Status);
@ -6921,7 +6971,7 @@ static NTSTATUS do_write2(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback)
file_ref* fr = CONTAINING_RECORD(RemoveHeadList(&Vcb->dirty_filerefs), file_ref, list_entry_dirty); file_ref* fr = CONTAINING_RECORD(RemoveHeadList(&Vcb->dirty_filerefs), file_ref, list_entry_dirty);
flush_fileref(fr, &batchlist, Irp); flush_fileref(fr, &batchlist, Irp);
free_fileref(Vcb, fr); free_fileref(fr);
#ifdef DEBUG_FLUSH_TIMES #ifdef DEBUG_FLUSH_TIMES
filerefs++; filerefs++;
@ -6961,7 +7011,7 @@ static NTSTATUS do_write2(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback)
Status = flush_fcb(fcb, FALSE, &batchlist, Irp); Status = flush_fcb(fcb, FALSE, &batchlist, Irp);
ExReleaseResourceLite(fcb->Header.Resource); ExReleaseResourceLite(fcb->Header.Resource);
free_fcb(Vcb, fcb); free_fcb(fcb);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("flush_fcb returned %08x\n", Status); ERR("flush_fcb returned %08x\n", Status);
@ -6994,7 +7044,7 @@ static NTSTATUS do_write2(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback)
ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE); ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
Status = flush_fcb(fcb, FALSE, &batchlist, Irp); Status = flush_fcb(fcb, FALSE, &batchlist, Irp);
ExReleaseResourceLite(fcb->Header.Resource); ExReleaseResourceLite(fcb->Header.Resource);
free_fcb(Vcb, fcb); free_fcb(fcb);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("flush_fcb returned %08x\n", Status); ERR("flush_fcb returned %08x\n", Status);

View file

@ -46,11 +46,11 @@ static NTSTATUS remove_free_space_inode(device_extension* Vcb, UINT64 inode, LIS
Status = flush_fcb(fcb, FALSE, batchlist, Irp); Status = flush_fcb(fcb, FALSE, batchlist, Irp);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("flush_fcb returned %08x\n", Status); ERR("flush_fcb returned %08x\n", Status);
free_fcb(Vcb, fcb); free_fcb(fcb);
return Status; return Status;
} }
free_fcb(Vcb, fcb); free_fcb(fcb);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -103,7 +103,7 @@ NTSTATUS clear_free_space_cache(device_extension* Vcb, LIST_ENTRY* batchlist, PI
chunk* c = CONTAINING_RECORD(le, chunk, list_entry); chunk* c = CONTAINING_RECORD(le, chunk, list_entry);
if (c->offset == tp.item->key.offset && c->cache) { if (c->offset == tp.item->key.offset && c->cache) {
free_fcb(Vcb, c->cache); reap_fcb(c->cache);
c->cache = NULL; c->cache = NULL;
} }
@ -508,7 +508,7 @@ NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, BOOL load
if (c->cache->inode_item.st_size == 0) { if (c->cache->inode_item.st_size == 0) {
WARN("cache had zero length\n"); WARN("cache had zero length\n");
free_fcb(Vcb, c->cache); free_fcb(c->cache);
c->cache = NULL; c->cache = NULL;
return STATUS_NOT_FOUND; return STATUS_NOT_FOUND;
} }
@ -524,11 +524,16 @@ NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, BOOL load
if (!data) { if (!data) {
ERR("out of memory\n"); ERR("out of memory\n");
free_fcb(Vcb, c->cache); free_fcb(c->cache);
c->cache = NULL; c->cache = NULL;
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
if (c->chunk_item->size < 0x6400000) { // 100 MB
WARN("deleting free space cache for chunk smaller than 100MB\n");
goto clearcache;
}
Status = read_file(c->cache, data, 0, c->cache->inode_item.st_size, NULL, NULL); Status = read_file(c->cache, data, 0, c->cache->inode_item.st_size, NULL, NULL);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("read_file returned %08x\n", Status); ERR("read_file returned %08x\n", Status);
@ -537,7 +542,7 @@ NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, BOOL load
c->cache->deleted = TRUE; c->cache->deleted = TRUE;
mark_fcb_dirty(c->cache); mark_fcb_dirty(c->cache);
free_fcb(Vcb, c->cache); free_fcb(c->cache);
c->cache = NULL; c->cache = NULL;
return STATUS_NOT_FOUND; return STATUS_NOT_FOUND;
} }
@ -1126,7 +1131,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
fsi = ExAllocatePoolWithTag(PagedPool, sizeof(FREE_SPACE_ITEM), ALLOC_TAG); fsi = ExAllocatePoolWithTag(PagedPool, sizeof(FREE_SPACE_ITEM), ALLOC_TAG);
if (!fsi) { if (!fsi) {
ERR("out of memory\n"); ERR("out of memory\n");
free_fcb(Vcb, c->cache); reap_fcb(c->cache);
c->cache = NULL; c->cache = NULL;
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -1139,7 +1144,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status); ERR("error - find_item returned %08x\n", Status);
ExFreePool(fsi); ExFreePool(fsi);
free_fcb(Vcb, c->cache); reap_fcb(c->cache);
c->cache = NULL; c->cache = NULL;
return Status; return Status;
} }
@ -1149,7 +1154,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("delete_tree_item returned %08x\n", Status); ERR("delete_tree_item returned %08x\n", Status);
ExFreePool(fsi); ExFreePool(fsi);
free_fcb(Vcb, c->cache); reap_fcb(c->cache);
c->cache = NULL; c->cache = NULL;
return Status; return Status;
} }
@ -1163,7 +1168,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("insert_tree_item returned %08x\n", Status); ERR("insert_tree_item returned %08x\n", Status);
ExFreePool(fsi); ExFreePool(fsi);
free_fcb(Vcb, c->cache); reap_fcb(c->cache);
c->cache = NULL; c->cache = NULL;
return Status; return Status;
} }
@ -1173,7 +1178,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
Status = insert_cache_extent(c->cache, 0, new_cache_size, rollback); Status = insert_cache_extent(c->cache, 0, new_cache_size, rollback);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("insert_cache_extent returned %08x\n", Status); ERR("insert_cache_extent returned %08x\n", Status);
free_fcb(Vcb, c->cache); reap_fcb(c->cache);
c->cache = NULL; c->cache = NULL;
return Status; return Status;
} }
@ -1184,7 +1189,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
Status = flush_fcb(c->cache, TRUE, batchlist, Irp); Status = flush_fcb(c->cache, TRUE, batchlist, Irp);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("flush_fcb returned %08x\n", Status); ERR("flush_fcb returned %08x\n", Status);
free_fcb(Vcb, c->cache); free_fcb(c->cache);
c->cache = NULL; c->cache = NULL;
return Status; return Status;
} }
@ -1357,7 +1362,7 @@ NTSTATUS allocate_cache(device_extension* Vcb, BOOL* changed, PIRP Irp, LIST_ENT
while (le != &Vcb->chunks) { while (le != &Vcb->chunks) {
chunk* c = CONTAINING_RECORD(le, chunk, list_entry); chunk* c = CONTAINING_RECORD(le, chunk, list_entry);
if (c->space_changed) { if (c->space_changed && c->chunk_item->size >= 0x6400000) { // 100MB
BOOL b; BOOL b;
acquire_chunk_lock(c, Vcb); acquire_chunk_lock(c, Vcb);
@ -1827,7 +1832,7 @@ NTSTATUS update_chunk_caches(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollba
while (le != &Vcb->chunks) { while (le != &Vcb->chunks) {
c = CONTAINING_RECORD(le, chunk, list_entry); c = CONTAINING_RECORD(le, chunk, list_entry);
if (c->space_changed) { if (c->space_changed && c->chunk_item->size >= 0x6400000) { // 100MB
acquire_chunk_lock(c, Vcb); acquire_chunk_lock(c, Vcb);
Status = update_chunk_cache(Vcb, c, &now, &batchlist, Irp, rollback); Status = update_chunk_cache(Vcb, c, &now, &batchlist, Irp, rollback);
release_chunk_lock(c, Vcb); release_chunk_lock(c, Vcb);

View file

@ -435,7 +435,7 @@ static NTSTATUS do_create_snapshot(device_extension* Vcb, PFILE_OBJECT parent, f
Status = open_fcb(Vcb, r, r->root_item.objid, BTRFS_TYPE_DIRECTORY, utf8, fcb, &fr->fcb, PagedPool, Irp); Status = open_fcb(Vcb, r, r->root_item.objid, BTRFS_TYPE_DIRECTORY, utf8, fcb, &fr->fcb, PagedPool, Irp);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("open_fcb returned %08x\n", Status); ERR("open_fcb returned %08x\n", Status);
free_fileref(Vcb, fr); free_fileref(fr);
goto end; goto end;
} }
@ -448,9 +448,9 @@ static NTSTATUS do_create_snapshot(device_extension* Vcb, PFILE_OBJECT parent, f
fr->dc = dc; fr->dc = dc;
dc->fileref = fr; dc->fileref = fr;
ExAcquireResourceExclusiveLite(&fileref->nonpaged->children_lock, TRUE); ExAcquireResourceExclusiveLite(&fileref->fcb->nonpaged->dir_children_lock, TRUE);
InsertTailList(&fileref->children, &fr->list_entry); InsertTailList(&fileref->children, &fr->list_entry);
ExReleaseResourceLite(&fileref->nonpaged->children_lock); ExReleaseResourceLite(&fileref->fcb->nonpaged->dir_children_lock);
increase_fileref_refcount(fileref); increase_fileref_refcount(fileref);
@ -462,7 +462,7 @@ static NTSTATUS do_create_snapshot(device_extension* Vcb, PFILE_OBJECT parent, f
fr->fcb->subvol->parent = fileref->fcb->subvol->id; fr->fcb->subvol->parent = fileref->fcb->subvol->id;
free_fileref(Vcb, fr); free_fileref(fr);
// change fcb's INODE_ITEM // change fcb's INODE_ITEM
@ -641,11 +641,11 @@ static NTSTATUS create_snapshot(device_extension* Vcb, PFILE_OBJECT FileObject,
if (NT_SUCCESS(Status)) { if (NT_SUCCESS(Status)) {
if (!fr2->deleted) { if (!fr2->deleted) {
WARN("file already exists\n"); WARN("file already exists\n");
free_fileref(Vcb, fr2); free_fileref(fr2);
Status = STATUS_OBJECT_NAME_COLLISION; Status = STATUS_OBJECT_NAME_COLLISION;
goto end3; goto end3;
} else } else
free_fileref(Vcb, fr2); free_fileref(fr2);
} else if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND) { } else if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND) {
ERR("open_fileref returned %08x\n", Status); ERR("open_fileref returned %08x\n", Status);
goto end3; goto end3;
@ -726,7 +726,7 @@ static NTSTATUS create_snapshot(device_extension* Vcb, PFILE_OBJECT FileObject,
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
} else { } else {
send_notification_fileref(fr, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_ACTION_ADDED, NULL); send_notification_fileref(fr, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_ACTION_ADDED, NULL);
free_fileref(Vcb, fr); free_fileref(fr);
} }
} }
@ -866,11 +866,11 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT FileObject, vo
if (NT_SUCCESS(Status)) { if (NT_SUCCESS(Status)) {
if (!fr2->deleted) { if (!fr2->deleted) {
WARN("file already exists\n"); WARN("file already exists\n");
free_fileref(Vcb, fr2); free_fileref(fr2);
Status = STATUS_OBJECT_NAME_COLLISION; Status = STATUS_OBJECT_NAME_COLLISION;
goto end; goto end;
} else } else
free_fileref(Vcb, fr2); free_fileref(fr2);
} else if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND) { } else if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND) {
ERR("open_fileref returned %08x\n", Status); ERR("open_fileref returned %08x\n", Status);
goto end; goto end;
@ -1005,6 +1005,7 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT FileObject, vo
acquire_fcb_lock_exclusive(Vcb); acquire_fcb_lock_exclusive(Vcb);
InsertTailList(&r->fcbs, &rootfcb->list_entry); InsertTailList(&r->fcbs, &rootfcb->list_entry);
InsertTailList(&Vcb->all_fcbs, &rootfcb->list_entry_all); InsertTailList(&Vcb->all_fcbs, &rootfcb->list_entry_all);
r->fcbs_version++;
release_fcb_lock(Vcb); release_fcb_lock(Vcb);
rootfcb->Header.IsFastIoPossible = fast_io_possible(rootfcb); rootfcb->Header.IsFastIoPossible = fast_io_possible(rootfcb);
@ -1049,9 +1050,7 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT FileObject, vo
if (!fr) { if (!fr) {
ERR("out of memory\n"); ERR("out of memory\n");
acquire_fcb_lock_exclusive(Vcb); reap_fcb(rootfcb);
free_fcb(Vcb, rootfcb);
release_fcb_lock(Vcb);
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
goto end; goto end;
@ -1073,9 +1072,7 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT FileObject, vo
fr->fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG); fr->fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG);
if (!fr->fcb->hash_ptrs) { if (!fr->fcb->hash_ptrs) {
ERR("out of memory\n"); ERR("out of memory\n");
acquire_fcb_lock_exclusive(Vcb); free_fileref(fr);
free_fileref(Vcb, fr);
release_fcb_lock(Vcb);
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
goto end; goto end;
} }
@ -1085,18 +1082,16 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT FileObject, vo
fr->fcb->hash_ptrs_uc = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG); fr->fcb->hash_ptrs_uc = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG);
if (!fr->fcb->hash_ptrs_uc) { if (!fr->fcb->hash_ptrs_uc) {
ERR("out of memory\n"); ERR("out of memory\n");
acquire_fcb_lock_exclusive(Vcb); free_fileref(fr);
free_fileref(Vcb, fr);
release_fcb_lock(Vcb);
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
goto end; goto end;
} }
RtlZeroMemory(fr->fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256); RtlZeroMemory(fr->fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
ExAcquireResourceExclusiveLite(&fileref->nonpaged->children_lock, TRUE); ExAcquireResourceExclusiveLite(&fileref->fcb->nonpaged->dir_children_lock, TRUE);
InsertTailList(&fileref->children, &fr->list_entry); InsertTailList(&fileref->children, &fr->list_entry);
ExReleaseResourceLite(&fileref->nonpaged->children_lock); ExReleaseResourceLite(&fileref->fcb->nonpaged->dir_children_lock);
increase_fileref_refcount(fileref); increase_fileref_refcount(fileref);
@ -1154,11 +1149,8 @@ end:
} }
end2: end2:
if (fr) { if (fr)
acquire_fcb_lock_exclusive(Vcb); free_fileref(fr);
free_fileref(Vcb, fr);
release_fcb_lock(Vcb);
}
return Status; return Status;
} }
@ -2233,15 +2225,15 @@ static NTSTATUS lock_volume(device_extension* Vcb, PIRP Irp) {
if (Vcb->locked) if (Vcb->locked)
return STATUS_SUCCESS; return STATUS_SUCCESS;
acquire_fcb_lock_exclusive(Vcb); ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, TRUE);
if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) { if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) {
Status = STATUS_ACCESS_DENIED; Status = STATUS_ACCESS_DENIED;
release_fcb_lock(Vcb); ExReleaseResourceLite(&Vcb->fileref_lock);
goto end; goto end;
} }
release_fcb_lock(Vcb); ExReleaseResourceLite(&Vcb->fileref_lock);
if (Vcb->balance.thread && KeReadStateEvent(&Vcb->balance.event)) { if (Vcb->balance.thread && KeReadStateEvent(&Vcb->balance.event)) {
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
@ -3768,8 +3760,6 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
name.Length = name.MaximumLength = bmn->namelen; name.Length = name.MaximumLength = bmn->namelen;
name.Buffer = bmn->name; name.Buffer = bmn->name;
acquire_fcb_lock_exclusive(Vcb);
Status = find_file_in_dir(&name, parfcb, &subvol, &inode, &dc, TRUE); Status = find_file_in_dir(&name, parfcb, &subvol, &inode, &dc, TRUE);
if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND) { if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND) {
ERR("find_file_in_dir returned %08x\n", Status); ERR("find_file_in_dir returned %08x\n", Status);
@ -3782,36 +3772,6 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
goto end; goto end;
} }
if (bmn->inode == 0) {
inode = InterlockedIncrement64(&parfcb->subvol->lastinode);
lastle = parfcb->subvol->fcbs.Blink;
} else {
if (bmn->inode > (UINT64)parfcb->subvol->lastinode) {
inode = parfcb->subvol->lastinode = bmn->inode;
lastle = parfcb->subvol->fcbs.Blink;
} else {
LIST_ENTRY* le = parfcb->subvol->fcbs.Flink;
lastle = parfcb->subvol->fcbs.Blink;;
while (le != &parfcb->subvol->fcbs) {
struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry);
if (fcb2->inode == bmn->inode && !fcb2->deleted) {
WARN("inode collision\n");
Status = STATUS_INVALID_PARAMETER;
goto end;
} else if (fcb2->inode > bmn->inode) {
lastle = fcb2->list_entry.Blink;
break;
}
le = le->Flink;
}
inode = bmn->inode;
}
}
KeQuerySystemTime(&time); KeQuerySystemTime(&time);
win_time_to_unix(time, &now); win_time_to_unix(time, &now);
@ -3897,8 +3857,6 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
InterlockedIncrement(&parfcb->refcount); InterlockedIncrement(&parfcb->refcount);
fcb->subvol = parfcb->subvol; fcb->subvol = parfcb->subvol;
fcb->inode = inode;
fcb->type = bmn->type;
SeCaptureSubjectContext(&subjcont); SeCaptureSubjectContext(&subjcont);
@ -3907,7 +3865,7 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("SeAssignSecurityEx returned %08x\n", Status); ERR("SeAssignSecurityEx returned %08x\n", Status);
free_fcb(Vcb, fcb); reap_fcb(fcb);
goto end; goto end;
} }
@ -3922,10 +3880,52 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
find_gid(fcb, parfcb, &subjcont); find_gid(fcb, parfcb, &subjcont);
ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, TRUE);
acquire_fcb_lock_exclusive(Vcb);
if (bmn->inode == 0) {
inode = InterlockedIncrement64(&parfcb->subvol->lastinode);
lastle = parfcb->subvol->fcbs.Blink;
} else {
if (bmn->inode > (UINT64)parfcb->subvol->lastinode) {
inode = parfcb->subvol->lastinode = bmn->inode;
lastle = parfcb->subvol->fcbs.Blink;
} else {
LIST_ENTRY* le = parfcb->subvol->fcbs.Flink;
lastle = parfcb->subvol->fcbs.Blink;;
while (le != &parfcb->subvol->fcbs) {
struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry);
if (fcb2->inode == bmn->inode && !fcb2->deleted) {
release_fcb_lock(Vcb);
ExReleaseResourceLite(&Vcb->fileref_lock);
WARN("inode collision\n");
Status = STATUS_INVALID_PARAMETER;
goto end;
} else if (fcb2->inode > bmn->inode) {
lastle = fcb2->list_entry.Blink;
break;
}
le = le->Flink;
}
inode = bmn->inode;
}
}
fcb->inode = inode;
fcb->type = bmn->type;
fileref = create_fileref(Vcb); fileref = create_fileref(Vcb);
if (!fileref) { if (!fileref) {
release_fcb_lock(Vcb);
ExReleaseResourceLite(&Vcb->fileref_lock);
ERR("out of memory\n"); ERR("out of memory\n");
free_fcb(Vcb, fcb); reap_fcb(fcb);
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
goto end; goto end;
} }
@ -3933,16 +3933,16 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
fileref->fcb = fcb; fileref->fcb = fcb;
fcb->created = TRUE; fcb->created = TRUE;
mark_fcb_dirty(fcb);
fileref->created = TRUE; fileref->created = TRUE;
mark_fileref_dirty(fileref);
fcb->subvol->root_item.ctransid = Vcb->superblock.generation; fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
fcb->subvol->root_item.ctime = now; fcb->subvol->root_item.ctime = now;
fileref->parent = parfileref; fileref->parent = parfileref;
mark_fcb_dirty(fcb);
mark_fileref_dirty(fileref);
Status = add_dir_child(fileref->parent->fcb, fcb->inode, FALSE, &utf8, &name, fcb->type, &dc); Status = add_dir_child(fileref->parent->fcb, fcb->inode, FALSE, &utf8, &name, fcb->type, &dc);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
WARN("add_dir_child returned %08x\n", Status); WARN("add_dir_child returned %08x\n", Status);
@ -3950,17 +3950,20 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
fileref->dc = dc; fileref->dc = dc;
dc->fileref = fileref; dc->fileref = fileref;
ExAcquireResourceExclusiveLite(&parfileref->nonpaged->children_lock, TRUE); ExAcquireResourceExclusiveLite(&parfileref->fcb->nonpaged->dir_children_lock, TRUE);
InsertTailList(&parfileref->children, &fileref->list_entry); InsertTailList(&parfileref->children, &fileref->list_entry);
ExReleaseResourceLite(&parfileref->nonpaged->children_lock); ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock);
increase_fileref_refcount(parfileref); increase_fileref_refcount(parfileref);
if (fcb->type == BTRFS_TYPE_DIRECTORY) { if (fcb->type == BTRFS_TYPE_DIRECTORY) {
fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG); fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG);
if (!fcb->hash_ptrs) { if (!fcb->hash_ptrs) {
release_fcb_lock(Vcb);
ExReleaseResourceLite(&Vcb->fileref_lock);
ERR("out of memory\n"); ERR("out of memory\n");
free_fileref(Vcb, fileref); free_fileref(fileref);
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
goto end; goto end;
} }
@ -3969,8 +3972,11 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
fcb->hash_ptrs_uc = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG); fcb->hash_ptrs_uc = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG);
if (!fcb->hash_ptrs_uc) { if (!fcb->hash_ptrs_uc) {
release_fcb_lock(Vcb);
ExReleaseResourceLite(&Vcb->fileref_lock);
ERR("out of memory\n"); ERR("out of memory\n");
free_fileref(Vcb, fileref); free_fileref(fileref);
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
goto end; goto end;
} }
@ -3995,7 +4001,11 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
if (!parccb->user_set_write_time) if (!parccb->user_set_write_time)
parfcb->inode_item.st_mtime = now; parfcb->inode_item.st_mtime = now;
parfcb->subvol->fcbs_version++;
ExReleaseResourceLite(parfcb->Header.Resource); ExReleaseResourceLite(parfcb->Header.Resource);
release_fcb_lock(Vcb);
ExReleaseResourceLite(&Vcb->fileref_lock);
parfcb->inode_item_changed = TRUE; parfcb->inode_item_changed = TRUE;
mark_fcb_dirty(parfcb); mark_fcb_dirty(parfcb);
@ -4008,7 +4018,6 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
end: end:
release_fcb_lock(Vcb);
ExFreePool(utf8.Buffer); ExFreePool(utf8.Buffer);
@ -4458,11 +4467,11 @@ static NTSTATUS get_subvol_path(device_extension* Vcb, UINT64 id, WCHAR* out, UL
return STATUS_INTERNAL_ERROR; return STATUS_INTERNAL_ERROR;
} }
acquire_fcb_lock_shared(Vcb); ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, TRUE);
Status = open_fileref_by_inode(Vcb, r, r->root_item.objid, &fr, Irp); Status = open_fileref_by_inode(Vcb, r, r->root_item.objid, &fr, Irp);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
release_fcb_lock(Vcb); ExReleaseResourceLite(&Vcb->fileref_lock);
ERR("open_fileref_by_inode returned %08x\n", Status); ERR("open_fileref_by_inode returned %08x\n", Status);
return Status; return Status;
} }
@ -4478,9 +4487,9 @@ static NTSTATUS get_subvol_path(device_extension* Vcb, UINT64 id, WCHAR* out, UL
else else
ERR("fileref_get_filename returned %08x\n", Status); ERR("fileref_get_filename returned %08x\n", Status);
free_fileref(Vcb, fr); free_fileref(fr);
release_fcb_lock(Vcb); ExReleaseResourceLite(&Vcb->fileref_lock);
return Status; return Status;
} }

View file

@ -161,7 +161,7 @@ static NTSTATUS pnp_cancel_remove_device(PDEVICE_OBJECT DeviceObject) {
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE); ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
acquire_fcb_lock_exclusive(Vcb); ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, TRUE);
if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) { if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) {
Status = STATUS_ACCESS_DENIED; Status = STATUS_ACCESS_DENIED;
@ -175,7 +175,7 @@ static NTSTATUS pnp_cancel_remove_device(PDEVICE_OBJECT DeviceObject) {
} }
end: end:
release_fcb_lock(Vcb); ExReleaseResourceLite(&Vcb->fileref_lock);
ExReleaseResourceLite(&Vcb->tree_lock); ExReleaseResourceLite(&Vcb->tree_lock);
return STATUS_SUCCESS; return STATUS_SUCCESS;
@ -187,8 +187,6 @@ NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
acquire_fcb_lock_exclusive(Vcb);
if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) { if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) {
Status = STATUS_ACCESS_DENIED; Status = STATUS_ACCESS_DENIED;
goto end; goto end;
@ -216,8 +214,6 @@ NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
end: end:
release_fcb_lock(Vcb);
ExReleaseResourceLite(&Vcb->tree_lock); ExReleaseResourceLite(&Vcb->tree_lock);
return Status; return Status;

View file

@ -3359,7 +3359,7 @@ NTSTATUS NTAPI drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
if (Irp->Flags & IRP_PAGING_IO) if (Irp->Flags & IRP_PAGING_IO)
wait = TRUE; wait = TRUE;
if (!(Irp->Flags & IRP_PAGING_IO) && FileObject->SectionObjectPointer->DataSectionObject) { if (!(Irp->Flags & IRP_PAGING_IO) && FileObject->SectionObjectPointer && FileObject->SectionObjectPointer->DataSectionObject) {
IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK iosb;
CcFlushCache(FileObject->SectionObjectPointer, &IrpSp->Parameters.Read.ByteOffset, IrpSp->Parameters.Read.Length, &iosb); CcFlushCache(FileObject->SectionObjectPointer, &IrpSp->Parameters.Read.ByteOffset, IrpSp->Parameters.Read.Length, &iosb);

View file

@ -1,6 +1,7 @@
//{{NO_DEPENDENCIES}} //{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file. // Microsoft Visual C++ generated include file.
// Used by btrfs.rc // Used by btrfs.rc
//
// Next default values for new objects // Next default values for new objects
// //

View file

@ -483,8 +483,6 @@ void remove_volume_child(_Inout_ _Requires_exclusive_lock_held_(_Curr_->child_lo
} }
if (remove) { if (remove) {
PDEVICE_OBJECT pdo;
if (vde->name.Buffer) if (vde->name.Buffer)
ExFreePool(vde->name.Buffer); ExFreePool(vde->name.Buffer);
@ -493,11 +491,7 @@ void remove_volume_child(_Inout_ _Requires_exclusive_lock_held_(_Curr_->child_lo
ExDeleteResourceLite(&pdode->child_lock); ExDeleteResourceLite(&pdode->child_lock);
pdo = vde->pdo;
IoDeleteDevice(vde->device); IoDeleteDevice(vde->device);
if (!no_pnp)
IoDeleteDevice(pdo);
} }
} else } else
ExReleaseResourceLite(&pdode->child_lock); ExReleaseResourceLite(&pdode->child_lock);

View file

@ -17,39 +17,34 @@
#include "btrfs_drv.h" #include "btrfs_drv.h"
NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT64 generation, PIRP Irp) { NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, UINT8* buf, root* r, tree** pt) {
UINT8* buf;
NTSTATUS Status;
tree_header* th; tree_header* th;
tree* t; tree* t;
tree_data* td; tree_data* td;
chunk* c;
UINT8 h; UINT8 h;
BOOL inserted; BOOL inserted;
LIST_ENTRY* le; LIST_ENTRY* le;
buf = ExAllocatePoolWithTag(PagedPool, Vcb->superblock.node_size, ALLOC_TAG);
if (!buf) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = read_data(Vcb, addr, Vcb->superblock.node_size, NULL, TRUE, buf, NULL, &c, Irp, generation, FALSE, NormalPagePriority);
if (!NT_SUCCESS(Status)) {
ERR("read_data returned 0x%08x\n", Status);
ExFreePool(buf);
return Status;
}
th = (tree_header*)buf; th = (tree_header*)buf;
t = ExAllocatePoolWithTag(PagedPool, sizeof(tree), ALLOC_TAG); t = ExAllocatePoolWithTag(PagedPool, sizeof(tree), ALLOC_TAG);
if (!t) { if (!t) {
ERR("out of memory\n"); ERR("out of memory\n");
ExFreePool(buf);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
if (th->level > 0) {
t->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(tree_nonpaged), ALLOC_TAG);
if (!t->nonpaged) {
ERR("out of memory\n");
ExFreePool(t);
return STATUS_INSUFFICIENT_RESOURCES;
}
ExInitializeFastMutex(&t->nonpaged->mutex);
} else
t->nonpaged = NULL;
RtlCopyMemory(&t->header, th, sizeof(tree_header)); RtlCopyMemory(&t->header, th, sizeof(tree_header));
t->hash = calc_crc32c(0xffffffff, (UINT8*)&addr, sizeof(UINT64)); t->hash = calc_crc32c(0xffffffff, (UINT8*)&addr, sizeof(UINT64));
t->has_address = TRUE; t->has_address = TRUE;
@ -73,7 +68,6 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT6
if ((t->header.num_items * sizeof(leaf_node)) + sizeof(tree_header) > Vcb->superblock.node_size) { if ((t->header.num_items * sizeof(leaf_node)) + sizeof(tree_header) > Vcb->superblock.node_size) {
ERR("tree at %llx has more items than expected (%x)\n", t->header.num_items); ERR("tree at %llx has more items than expected (%x)\n", t->header.num_items);
ExFreePool(t); ExFreePool(t);
ExFreePool(buf);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -82,7 +76,6 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT6
if (!td) { if (!td) {
ERR("out of memory\n"); ERR("out of memory\n");
ExFreePool(t); ExFreePool(t);
ExFreePool(buf);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -97,7 +90,6 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT6
ERR("overlarge item in tree %llx: %u > %u\n", addr, ln[i].size, Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node)); ERR("overlarge item in tree %llx: %u > %u\n", addr, ln[i].size, Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node));
ExFreeToPagedLookasideList(&t->Vcb->tree_data_lookaside, td); ExFreeToPagedLookasideList(&t->Vcb->tree_data_lookaside, td);
ExFreePool(t); ExFreePool(t);
ExFreePool(buf);
return STATUS_INTERNAL_ERROR; return STATUS_INTERNAL_ERROR;
} }
@ -119,7 +111,6 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT6
if ((t->header.num_items * sizeof(internal_node)) + sizeof(tree_header) > Vcb->superblock.node_size) { if ((t->header.num_items * sizeof(internal_node)) + sizeof(tree_header) > Vcb->superblock.node_size) {
ERR("tree at %llx has more items than expected (%x)\n", t->header.num_items); ERR("tree at %llx has more items than expected (%x)\n", t->header.num_items);
ExFreePool(t); ExFreePool(t);
ExFreePool(buf);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -128,7 +119,6 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT6
if (!td) { if (!td) {
ERR("out of memory\n"); ERR("out of memory\n");
ExFreePool(t); ExFreePool(t);
ExFreePool(buf);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -145,9 +135,10 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT6
t->size = t->header.num_items * sizeof(internal_node); t->size = t->header.num_items * sizeof(internal_node);
t->buf = NULL; t->buf = NULL;
ExFreePool(buf);
} }
ExAcquireFastMutex(&Vcb->trees_list_mutex);
InsertTailList(&Vcb->trees, &t->list_entry); InsertTailList(&Vcb->trees, &t->list_entry);
h = t->hash >> 24; h = t->hash >> 24;
@ -190,6 +181,8 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT6
if (!Vcb->trees_ptrs[h] || t->list_entry_hash.Flink == Vcb->trees_ptrs[h]) if (!Vcb->trees_ptrs[h] || t->list_entry_hash.Flink == Vcb->trees_ptrs[h])
Vcb->trees_ptrs[h] = &t->list_entry_hash; Vcb->trees_ptrs[h] = &t->list_entry_hash;
ExReleaseFastMutex(&Vcb->trees_list_mutex);
TRACE("returning %p\n", t); TRACE("returning %p\n", t);
*pt = t; *pt = t;
@ -197,10 +190,79 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT6
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static tree* free_tree2(tree* t) { static NTSTATUS do_load_tree2(device_extension* Vcb, tree_holder* th, UINT8* buf, root* r, tree* t, tree_data* td) {
if (!th->tree) {
NTSTATUS Status;
tree* nt;
Status = load_tree(Vcb, th->address, buf, r, &nt);
if (!NT_SUCCESS(Status)) {
ERR("load_tree returned %08x\n", Status);
return Status;
}
nt->parent = t;
#ifdef DEBUG_PARANOID
if (t && t->header.level <= nt->header.level) int3;
#endif
nt->paritem = td;
th->tree = nt;
}
return STATUS_SUCCESS;
}
NTSTATUS do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, PIRP Irp) {
NTSTATUS Status;
UINT8* buf;
chunk* c;
buf = ExAllocatePoolWithTag(PagedPool, Vcb->superblock.node_size, ALLOC_TAG);
if (!buf) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = read_data(Vcb, th->address, Vcb->superblock.node_size, NULL, TRUE, buf, NULL,
&c, Irp, th->generation, FALSE, NormalPagePriority);
if (!NT_SUCCESS(Status)) {
ERR("read_data returned 0x%08x\n", Status);
ExFreePool(buf);
return Status;
}
if (t)
ExAcquireFastMutex(&t->nonpaged->mutex);
else
ExAcquireResourceExclusiveLite(&r->nonpaged->load_tree_lock, TRUE);
Status = do_load_tree2(Vcb, th, buf, r, t, td);
if (t)
ExReleaseFastMutex(&t->nonpaged->mutex);
else
ExReleaseResourceLite(&r->nonpaged->load_tree_lock);
if (!th->tree || th->tree->buf != buf)
ExFreePool(buf);
if (!NT_SUCCESS(Status)) {
ERR("do_load_tree2 returned %08x\n", Status);
return Status;
}
return Status;
}
void free_tree(tree* t) {
tree* par; tree* par;
root* r = t->root; root* r = t->root;
// No need to acquire lock, as this is only ever called while Vcb->tree_lock held exclusively
par = t->parent; par = t->parent;
if (r && r->treeholder.tree != t) if (r && r->treeholder.tree != t)
@ -245,59 +307,10 @@ static tree* free_tree2(tree* t) {
if (t->buf) if (t->buf)
ExFreePool(t->buf); ExFreePool(t->buf);
if (t->nonpaged)
ExFreePool(t->nonpaged);
ExFreePool(t); ExFreePool(t);
return NULL;
}
NTSTATUS do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, BOOL* loaded, PIRP Irp) {
BOOL ret;
ExAcquireResourceExclusiveLite(&r->nonpaged->load_tree_lock, TRUE);
if (!th->tree) {
NTSTATUS Status;
tree* nt;
Status = load_tree(Vcb, th->address, r, &nt, th->generation, Irp);
if (!NT_SUCCESS(Status)) {
ERR("load_tree returned %08x\n", Status);
ExReleaseResourceLite(&r->nonpaged->load_tree_lock);
return Status;
}
nt->parent = t;
#ifdef DEBUG_PARANOID
if (t && t->header.level <= nt->header.level) int3;
#endif
nt->paritem = td;
th->tree = nt;
ret = TRUE;
} else
ret = FALSE;
ExReleaseResourceLite(&r->nonpaged->load_tree_lock);
*loaded = ret;
return STATUS_SUCCESS;
}
tree* free_tree(tree* t) {
tree* ret;
root* r = t->root;
ExAcquireResourceExclusiveLite(&r->nonpaged->load_tree_lock, TRUE);
ret = free_tree2(t);
ExReleaseResourceLite(&r->nonpaged->load_tree_lock);
return ret;
} }
static __inline tree_data* first_item(tree* t) { static __inline tree_data* first_item(tree* t) {
@ -504,7 +517,6 @@ static NTSTATUS find_item_in_tree(device_extension* Vcb, tree* t, traverse_ptr*
return STATUS_SUCCESS; return STATUS_SUCCESS;
} else { } else {
NTSTATUS Status; NTSTATUS Status;
BOOL loaded;
while (td && td->treeholder.tree && IsListEmpty(&td->treeholder.tree->itemlist)) { while (td && td->treeholder.tree && IsListEmpty(&td->treeholder.tree->itemlist)) {
td = prev_item(t, td); td = prev_item(t, td);
@ -520,7 +532,7 @@ static NTSTATUS find_item_in_tree(device_extension* Vcb, tree* t, traverse_ptr*
} }
if (!td->treeholder.tree) { if (!td->treeholder.tree) {
Status = do_load_tree(Vcb, &td->treeholder, t->root, t, td, &loaded, Irp); Status = do_load_tree(Vcb, &td->treeholder, t->root, t, td, Irp);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("do_load_tree returned %08x\n", Status); ERR("do_load_tree returned %08x\n", Status);
return Status; return Status;
@ -536,10 +548,9 @@ static NTSTATUS find_item_in_tree(device_extension* Vcb, tree* t, traverse_ptr*
NTSTATUS find_item(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _Out_ traverse_ptr* tp, NTSTATUS find_item(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _Out_ traverse_ptr* tp,
_In_ const KEY* searchkey, _In_ BOOL ignore, _In_opt_ PIRP Irp) { _In_ const KEY* searchkey, _In_ BOOL ignore, _In_opt_ PIRP Irp) {
NTSTATUS Status; NTSTATUS Status;
BOOL loaded;
if (!r->treeholder.tree) { if (!r->treeholder.tree) {
Status = do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, &loaded, Irp); Status = do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, Irp);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("do_load_tree returned %08x\n", Status); ERR("do_load_tree returned %08x\n", Status);
return Status; return Status;
@ -556,10 +567,9 @@ NTSTATUS find_item(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension
NTSTATUS find_item_to_level(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, BOOL ignore, UINT8 level, PIRP Irp) { NTSTATUS find_item_to_level(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, BOOL ignore, UINT8 level, PIRP Irp) {
NTSTATUS Status; NTSTATUS Status;
BOOL loaded;
if (!r->treeholder.tree) { if (!r->treeholder.tree) {
Status = do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, &loaded, Irp); Status = do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, Irp);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("do_load_tree returned %08x\n", Status); ERR("do_load_tree returned %08x\n", Status);
return Status; return Status;
@ -583,7 +593,6 @@ BOOL find_next_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vc
tree* t; tree* t;
tree_data *td = NULL, *next; tree_data *td = NULL, *next;
NTSTATUS Status; NTSTATUS Status;
BOOL loaded;
next = next_item(tp->tree, tp->item); next = next_item(tp->tree, tp->item);
@ -623,10 +632,12 @@ BOOL find_next_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vc
if (!t) if (!t)
return FALSE; return FALSE;
Status = do_load_tree(Vcb, &td->treeholder, t->parent->root, t->parent, td, &loaded, Irp); if (!td->treeholder.tree) {
if (!NT_SUCCESS(Status)) { Status = do_load_tree(Vcb, &td->treeholder, t->parent->root, t->parent, td, Irp);
ERR("do_load_tree returned %08x\n", Status); if (!NT_SUCCESS(Status)) {
return FALSE; ERR("do_load_tree returned %08x\n", Status);
return FALSE;
}
} }
t = td->treeholder.tree; t = td->treeholder.tree;
@ -636,10 +647,12 @@ BOOL find_next_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vc
fi = first_item(t); fi = first_item(t);
Status = do_load_tree(Vcb, &fi->treeholder, t->parent->root, t, fi, &loaded, Irp); if (!fi->treeholder.tree) {
if (!NT_SUCCESS(Status)) { Status = do_load_tree(Vcb, &fi->treeholder, t->parent->root, t, fi, Irp);
ERR("do_load_tree returned %08x\n", Status); if (!NT_SUCCESS(Status)) {
return FALSE; ERR("do_load_tree returned %08x\n", Status);
return FALSE;
}
} }
t = fi->treeholder.tree; t = fi->treeholder.tree;
@ -686,7 +699,6 @@ BOOL find_prev_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vc
tree* t; tree* t;
tree_data* td; tree_data* td;
NTSTATUS Status; NTSTATUS Status;
BOOL loaded;
// FIXME - support ignore flag // FIXME - support ignore flag
if (prev_item(tp->tree, tp->item)) { if (prev_item(tp->tree, tp->item)) {
@ -709,10 +721,12 @@ BOOL find_prev_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vc
td = prev_item(t->parent, t->paritem); td = prev_item(t->parent, t->paritem);
Status = do_load_tree(Vcb, &td->treeholder, t->parent->root, t->parent, td, &loaded, Irp); if (!td->treeholder.tree) {
if (!NT_SUCCESS(Status)) { Status = do_load_tree(Vcb, &td->treeholder, t->parent->root, t->parent, td, Irp);
ERR("do_load_tree returned %08x\n", Status); if (!NT_SUCCESS(Status)) {
return FALSE; ERR("do_load_tree returned %08x\n", Status);
return FALSE;
}
} }
t = td->treeholder.tree; t = td->treeholder.tree;
@ -722,10 +736,12 @@ BOOL find_prev_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vc
li = last_item(t); li = last_item(t);
Status = do_load_tree(Vcb, &li->treeholder, t->parent->root, t, li, &loaded, Irp); if (!li->treeholder.tree) {
if (!NT_SUCCESS(Status)) { Status = do_load_tree(Vcb, &li->treeholder, t->parent->root, t, li, Irp);
ERR("do_load_tree returned %08x\n", Status); if (!NT_SUCCESS(Status)) {
return FALSE; ERR("do_load_tree returned %08x\n", Status);
return FALSE;
}
} }
t = li->treeholder.tree; t = li->treeholder.tree;
@ -756,7 +772,7 @@ void free_trees_root(device_extension* Vcb, root* r) {
empty = FALSE; empty = FALSE;
free_tree2(t); free_tree(t);
if (top && r->treeholder.tree == t) if (top && r->treeholder.tree == t)
r->treeholder.tree = NULL; r->treeholder.tree = NULL;
@ -793,7 +809,7 @@ void free_trees(device_extension* Vcb) {
empty = FALSE; empty = FALSE;
free_tree2(t); free_tree(t);
if (top && r->treeholder.tree == t) if (top && r->treeholder.tree == t)
r->treeholder.tree = NULL; r->treeholder.tree = NULL;
@ -808,6 +824,9 @@ void free_trees(device_extension* Vcb) {
if (empty) if (empty)
break; break;
} }
reap_filerefs(Vcb, Vcb->root_fileref);
reap_fcbs(Vcb);
} }
#ifdef _MSC_VER #ifdef _MSC_VER
@ -859,9 +878,7 @@ NTSTATUS insert_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock)
if (Status == STATUS_NOT_FOUND) { if (Status == STATUS_NOT_FOUND) {
if (r) { if (r) {
if (!r->treeholder.tree) { if (!r->treeholder.tree) {
BOOL loaded; Status = do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, Irp);
Status = do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, &loaded, Irp);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("do_load_tree returned %08x\n", Status); ERR("do_load_tree returned %08x\n", Status);
return Status; return Status;

View file

@ -774,6 +774,30 @@ static NTSTATUS vol_ioctl_passthrough(volume_device_extension* vde, PIRP Irp) {
return Status; return Status;
} }
static NTSTATUS vol_query_stable_guid(volume_device_extension* vde, PIRP Irp) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
MOUNTDEV_STABLE_GUID* mdsg;
pdo_device_extension* pdode;
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_STABLE_GUID)) {
Irp->IoStatus.Information = sizeof(MOUNTDEV_STABLE_GUID);
return STATUS_BUFFER_TOO_SMALL;
}
mdsg = Irp->AssociatedIrp.SystemBuffer;
if (!vde->pdo)
return STATUS_INVALID_PARAMETER;
pdode = vde->pdode;
RtlCopyMemory(&mdsg->StableGuid, &pdode->uuid, sizeof(BTRFS_UUID));
Irp->IoStatus.Information = sizeof(MOUNTDEV_STABLE_GUID);
return STATUS_SUCCESS;
}
NTSTATUS vol_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS vol_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
volume_device_extension* vde = DeviceObject->DeviceExtension; volume_device_extension* vde = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
@ -797,8 +821,7 @@ NTSTATUS vol_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
break; break;
case IOCTL_MOUNTDEV_QUERY_STABLE_GUID: case IOCTL_MOUNTDEV_QUERY_STABLE_GUID:
TRACE("unhandled control code IOCTL_MOUNTDEV_QUERY_STABLE_GUID\n"); return vol_query_stable_guid(vde, Irp);
break;
case IOCTL_MOUNTDEV_LINK_CREATED: case IOCTL_MOUNTDEV_LINK_CREATED:
TRACE("unhandled control code IOCTL_MOUNTDEV_LINK_CREATED\n"); TRACE("unhandled control code IOCTL_MOUNTDEV_LINK_CREATED\n");
@ -811,12 +834,12 @@ NTSTATUS vol_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
return vol_is_dynamic(Irp); return vol_is_dynamic(Irp);
case IOCTL_VOLUME_ONLINE: case IOCTL_VOLUME_ONLINE:
TRACE("unhandled control code IOCTL_VOLUME_ONLINE\n"); Irp->IoStatus.Information = 0;
break; return STATUS_SUCCESS;
case IOCTL_VOLUME_POST_ONLINE: case IOCTL_VOLUME_POST_ONLINE:
TRACE("unhandled control code IOCTL_VOLUME_POST_ONLINE\n"); Irp->IoStatus.Information = 0;
break; return STATUS_SUCCESS;
case IOCTL_DISK_GET_DRIVE_GEOMETRY: case IOCTL_DISK_GET_DRIVE_GEOMETRY:
return vol_get_drive_geometry(DeviceObject, Irp); return vol_get_drive_geometry(DeviceObject, Irp);