https://git.reactos.org/?p=reactos.git;a=commitdiff;h=883b1f31ac8b4b30e21144...
commit 883b1f31ac8b4b30e21144053b9ada0383ad17d3 Author: Pierre Schweitzer pierre@reactos.org AuthorDate: Sat May 11 11:20:02 2019 +0200 Commit: Pierre Schweitzer pierre@reactos.org CommitDate: Sat May 11 11:20:02 2019 +0200
[BTRFS] Upgrade to 1.2.1
CORE-16004 --- drivers/filesystems/btrfs/balance.c | 4 - drivers/filesystems/btrfs/btrfs.c | 180 +-- drivers/filesystems/btrfs/btrfs.rc | 22 +- drivers/filesystems/btrfs/btrfs_drv.h | 31 +- drivers/filesystems/btrfs/create.c | 1921 +++++++++++++++++++------------ drivers/filesystems/btrfs/dirctrl.c | 26 +- drivers/filesystems/btrfs/fileinfo.c | 388 +------ drivers/filesystems/btrfs/flushthread.c | 72 +- drivers/filesystems/btrfs/free-space.c | 33 +- drivers/filesystems/btrfs/fsctl.c | 161 +-- drivers/filesystems/btrfs/pnp.c | 8 +- drivers/filesystems/btrfs/read.c | 2 +- drivers/filesystems/btrfs/resource.h | 3 +- drivers/filesystems/btrfs/search.c | 6 - drivers/filesystems/btrfs/treefuncs.c | 229 ++-- drivers/filesystems/btrfs/volume.c | 35 +- 16 files changed, 1734 insertions(+), 1387 deletions(-)
diff --git a/drivers/filesystems/btrfs/balance.c b/drivers/filesystems/btrfs/balance.c index fe641f4f41..83546f0371 100644 --- a/drivers/filesystems/btrfs/balance.c +++ b/drivers/filesystems/btrfs/balance.c @@ -2108,8 +2108,6 @@ end: // update open FCBs // FIXME - speed this up(?)
- acquire_fcb_lock_shared(Vcb); - le = Vcb->all_fcbs.Flink; while (le != &Vcb->all_fcbs) { struct _fcb* fcb = CONTAINING_RECORD(le, struct _fcb, list_entry_all); @@ -2148,8 +2146,6 @@ end:
le = le->Flink; } - - release_fcb_lock(Vcb); } else do_rollback(Vcb, &rollback);
diff --git a/drivers/filesystems/btrfs/btrfs.c b/drivers/filesystems/btrfs/btrfs.c index 2582ee0b3f..4cd6bb10a1 100644 --- a/drivers/filesystems/btrfs/btrfs.c +++ b/drivers/filesystems/btrfs/btrfs.c @@ -1036,6 +1036,8 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi return STATUS_INSUFFICIENT_RESOURCES; }
+ t->nonpaged = NULL; + t->is_unique = TRUE; t->uniqueness_determined = TRUE; t->buf = NULL; @@ -1065,7 +1067,9 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi r->send_ops = 0; RtlZeroMemory(&r->root_item, sizeof(ROOT_ITEM)); r->root_item.num_references = 1; + r->fcbs_version = 0; InitializeListHead(&r->fcbs); + RtlZeroMemory(r->fcbs_ptrs, sizeof(LIST_ENTRY*) * 256);
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; }
- acquire_fcb_lock_exclusive(fcb->Vcb); + ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, TRUE);
le = fcb->hardlinks.Flink; 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); if (Status != STATUS_BUFFER_OVERFLOW) { ERR("fileref_get_filename returned %08x\n", Status); - free_fileref(fcb->Vcb, parfr); + free_fileref(parfr); break; }
@@ -1419,7 +1423,7 @@ void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_
if (pathlen + hl->name.Length > 0xffff) { WARN("pathlen + hl->name.Length was too long for FsRtlNotifyFilterReportChange\n"); - free_fileref(fcb->Vcb, parfr); + free_fileref(parfr); 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); if (!fn.Buffer) { ERR("out of memory\n"); - free_fileref(fcb->Vcb, parfr); + free_fileref(parfr); break; }
Status = fileref_get_filename(parfr, &fn, NULL, NULL); if (!NT_SUCCESS(Status)) { ERR("fileref_get_filename returned %08x\n", Status); - free_fileref(fcb->Vcb, parfr); + free_fileref(parfr); ExFreePool(fn.Buffer); break; } @@ -1452,13 +1456,13 @@ void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_
ExFreePool(fn.Buffer);
- free_fileref(fcb->Vcb, parfr); + free_fileref(parfr); }
le = le->Flink; }
- release_fcb_lock(fcb->Vcb); + ExReleaseResourceLite(&fcb->Vcb->fileref_lock); }
void mark_fcb_dirty(_In_ fcb* fcb) { @@ -1497,24 +1501,31 @@ void mark_fileref_dirty(_In_ file_ref* fileref) { }
#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 -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 - LONG rc; - - rc = InterlockedDecrement(&fcb->refcount);
#ifdef DEBUG_FCB_REFCOUNTS #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 - 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 +}
- if (rc > 0) - return; +void reap_fcb(fcb* fcb) { + 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) 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->dir_children_lock);
- ExFreeToNPagedLookasideList(&Vcb->fcb_np_lookaside, fcb->nonpaged); + ExFreeToNPagedLookasideList(&fcb->Vcb->fcb_np_lookaside, fcb->nonpaged);
if (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) ExFreePool(fcb); 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 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(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ file_ref* fr) { +void free_fileref(_Inout_ file_ref* fr) { LONG rc;
rc = InterlockedDecrement(&fr->refcount); +#ifdef __REACTOS__ + (void)rc; +#endif
#ifdef DEBUG_FCB_REFCOUNTS 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; } #endif +}
- if (rc > 0) - return; - - if (fr->parent) - ExAcquireResourceExclusiveLite(&fr->parent->nonpaged->children_lock, TRUE); - +void reap_fileref(device_extension* Vcb, file_ref* fr) { // FIXME - do we need a file_ref lock?
// 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) ExFreePool(fr->debug_desc);
- ExDeleteResourceLite(&fr->nonpaged->children_lock); ExDeleteResourceLite(&fr->nonpaged->fileref_lock);
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) RemoveEntryList(&fr->list_entry);
- if (fr->parent) { - ExReleaseResourceLite(&fr->parent->nonpaged->children_lock); - free_fileref(Vcb, fr->parent); - } + if (fr->parent) + free_fileref(fr->parent);
- free_fcb(Vcb, fr->fcb); + free_fcb(fr->fcb);
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) { fcb* fcb; ccb* ccb; file_ref* fileref = NULL; LONG open_files; - device_extension* Vcb;
UNUSED(Irp);
@@ -1735,16 +1767,10 @@ static NTSTATUS close_file(_In_ PFILE_OBJECT FileObject, _In_ PIRP Irp) { if (!(fcb->Vcb->Vpb->Flags & VPB_MOUNTED)) return STATUS_SUCCESS;
- Vcb = fcb->Vcb; - - acquire_fcb_lock_exclusive(Vcb); - if (fileref) - free_fileref(fcb->Vcb, fileref); + free_fileref(fileref); else - free_fcb(Vcb, fcb); - - release_fcb_lock(Vcb); + free_fcb(fcb);
return STATUS_SUCCESS; } @@ -1835,10 +1861,8 @@ void uninit(_In_ device_extension* Vcb) { KeSetTimer(&Vcb->flush_thread_timer, time, NULL); // trigger the timer early KeWaitForSingleObject(&Vcb->flush_thread_finished, Executive, KernelMode, FALSE, NULL);
- acquire_fcb_lock_exclusive(Vcb); - free_fcb(Vcb, Vcb->volume_fcb); - free_fcb(Vcb, Vcb->dummy_fcb); - release_fcb_lock(Vcb); + reap_fcb(Vcb->volume_fcb); + reap_fcb(Vcb->dummy_fcb);
if (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);
if (c->cache) { - acquire_fcb_lock_exclusive(Vcb); - free_fcb(Vcb, c->cache); - release_fcb_lock(Vcb); + reap_fcb(c->cache); c->cache = NULL; }
@@ -1885,11 +1907,8 @@ void uninit(_In_ device_extension* Vcb) { if (c->devices) ExFreePool(c->devices);
- if (c->cache) { - acquire_fcb_lock_exclusive(Vcb); - free_fcb(Vcb, c->cache); - release_fcb_lock(Vcb); - } + if (c->cache) + reap_fcb(c->cache);
ExDeleteResourceLite(&c->range_locks_lock); ExDeleteResourceLite(&c->partial_stripes_lock); @@ -1924,6 +1943,7 @@ void uninit(_In_ device_extension* Vcb) { ExReleaseResourceLite(&Vcb->scrub.stats_lock);
ExDeleteResourceLite(&Vcb->fcb_lock); + ExDeleteResourceLite(&Vcb->fileref_lock); ExDeleteResourceLite(&Vcb->load_lock); ExDeleteResourceLite(&Vcb->tree_lock); ExDeleteResourceLite(&Vcb->chunk_lock); @@ -2269,21 +2289,19 @@ static NTSTATUS drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { ExReleaseResourceLite(fcb->Header.Resource); locked = FALSE;
- // fcb_lock needs to be acquired before fcb->Header.Resource - acquire_fcb_lock_exclusive(fcb->Vcb); + // fileref_lock needs to be acquired before fcb->Header.Resource + ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, TRUE);
Status = delete_fileref(fileref, FileObject, Irp, &rollback); if (!NT_SUCCESS(Status)) { ERR("delete_fileref returned %08x\n", Status); do_rollback(fcb->Vcb, &rollback); - release_fcb_lock(fcb->Vcb); + ExReleaseResourceLite(&fcb->Vcb->fileref_lock); ExReleaseResourceLite(&fcb->Vcb->tree_lock); goto exit; }
- release_fcb_lock(fcb->Vcb); - - locked = FALSE; + ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
clear_rollback(&rollback); } 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->parent = 0; r->send_ops = 0; + r->fcbs_version = 0; InitializeListHead(&r->fcbs); + RtlZeroMemory(r->fcbs_ptrs, sizeof(LIST_ENTRY*) * 256);
r->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(root_nonpaged), ALLOC_TAG); if (!r->nonpaged) { @@ -4132,6 +4152,7 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { Vcb->need_write = FALSE;
ExInitializeResourceLite(&Vcb->fcb_lock); + ExInitializeResourceLite(&Vcb->fileref_lock); ExInitializeResourceLite(&Vcb->chunk_lock); ExInitializeResourceLite(&Vcb->dirty_fcbs_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->send_ops);
+ ExInitializeFastMutex(&Vcb->trees_list_mutex); + InitializeListHead(&Vcb->DirNotifyList); 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->inode = SUBVOL_ROOT_INODE; + root_fcb->hash = calc_crc32c(0xffffffff, (UINT8*)&root_fcb->inode, sizeof(UINT64)); root_fcb->type = BTRFS_TYPE_DIRECTORY;
#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(&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_ccb = ExAllocatePoolWithTag(PagedPool, sizeof(ccb), ALLOC_TAG); @@ -4596,25 +4622,21 @@ exit2:
if (Vcb->root_file) ObDereferenceObject(Vcb->root_file); - else if (Vcb->root_fileref) { - acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, Vcb->root_fileref); - release_fcb_lock(Vcb); - } else if (root_fcb) { - acquire_fcb_lock_exclusive(Vcb); - free_fcb(Vcb, root_fcb); - release_fcb_lock(Vcb); - } + else if (Vcb->root_fileref) + free_fileref(Vcb->root_fileref); + else if (root_fcb) + free_fcb(root_fcb);
- if (Vcb->volume_fcb) { - acquire_fcb_lock_exclusive(Vcb); - free_fcb(Vcb, Vcb->volume_fcb); - release_fcb_lock(Vcb); - } + if (root_fcb && root_fcb->refcount == 0) + reap_fcb(root_fcb); + + if (Vcb->volume_fcb) + reap_fcb(Vcb->volume_fcb);
ExDeleteResourceLite(&Vcb->tree_lock); ExDeleteResourceLite(&Vcb->load_lock); ExDeleteResourceLite(&Vcb->fcb_lock); + ExDeleteResourceLite(&Vcb->fileref_lock); ExDeleteResourceLite(&Vcb->chunk_lock); ExDeleteResourceLite(&Vcb->dirty_fcbs_lock); ExDeleteResourceLite(&Vcb->dirty_filerefs_lock); diff --git a/drivers/filesystems/btrfs/btrfs.rc b/drivers/filesystems/btrfs/btrfs.rc index 957792add5..d10323e56c 100644 --- a/drivers/filesystems/btrfs/btrfs.rc +++ b/drivers/filesystems/btrfs/btrfs.rc @@ -13,13 +13,11 @@ #undef APSTUDIO_READONLY_SYMBOLS
///////////////////////////////////////////////////////////////////////////// -// English (U.K.) resources +// English (United Kingdom) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) -#ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK #pragma code_page(1252) -#endif //_WIN32
#ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// @@ -27,18 +25,18 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK // TEXTINCLUDE //
-1 TEXTINCLUDE +1 TEXTINCLUDE BEGIN "resource.h\0" END
-2 TEXTINCLUDE +2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END
-3 TEXTINCLUDE +3 TEXTINCLUDE BEGIN "\r\n" "\0" @@ -53,8 +51,8 @@ END //
VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,1,0,0 - PRODUCTVERSION 1,1,0,0 + FILEVERSION 1,2,1,0 + PRODUCTVERSION 1,2,1,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -70,12 +68,12 @@ BEGIN BLOCK "080904b0" BEGIN VALUE "FileDescription", "WinBtrfs" - VALUE "FileVersion", "1.1" + VALUE "FileVersion", "1.2.1" VALUE "InternalName", "btrfs" - VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-18" + VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-19" VALUE "OriginalFilename", "btrfs.sys" VALUE "ProductName", "WinBtrfs" - VALUE "ProductVersion", "1.1" + VALUE "ProductVersion", "1.2.1" END END BLOCK "VarFileInfo" @@ -84,7 +82,7 @@ BEGIN END END
-#endif // English (U.K.) resources +#endif // English (United Kingdom) resources /////////////////////////////////////////////////////////////////////////////
diff --git a/drivers/filesystems/btrfs/btrfs_drv.h b/drivers/filesystems/btrfs/btrfs_drv.h index 3ccb10ac06..b41c9794d3 100644 --- a/drivers/filesystems/btrfs/btrfs_drv.h +++ b/drivers/filesystems/btrfs/btrfs_drv.h @@ -260,6 +260,7 @@ typedef struct _fcb { struct _device_extension* Vcb; struct _root* subvol; UINT64 inode; + UINT32 hash; UINT8 type; INODE_ITEM inode_item; SECURITY_DESCRIPTOR* sd; @@ -309,7 +310,6 @@ typedef struct _fcb {
typedef struct { ERESOURCE fileref_lock; - ERESOURCE children_lock; } file_ref_nonpaged;
typedef struct _file_ref { @@ -392,7 +392,12 @@ typedef struct _tree_data { }; } tree_data;
+typedef struct { + FAST_MUTEX mutex; +} tree_nonpaged; + typedef struct _tree { + tree_nonpaged* nonpaged; tree_header header; UINT32 hash; BOOL has_address; @@ -428,7 +433,9 @@ typedef struct _root { PEPROCESS reserved; UINT64 parent; LONG send_ops; + UINT64 fcbs_version; LIST_ENTRY fcbs; + LIST_ENTRY* fcbs_ptrs[256]; LIST_ENTRY list_entry; LIST_ENTRY list_entry_dirty; } root; @@ -742,6 +749,7 @@ typedef struct _device_extension { file_ref* root_fileref; LONG open_files; _Has_lock_level_(fcb_lock) ERESOURCE fcb_lock; + ERESOURCE fileref_lock; ERESOURCE load_lock; _Has_lock_level_(tree_lock) ERESOURCE tree_lock; PNOTIFY_SYNC NotifySync; @@ -768,6 +776,7 @@ typedef struct _device_extension { LIST_ENTRY trees; LIST_ENTRY trees_hash; LIST_ENTRY* trees_ptrs[256]; + FAST_MUTEX trees_list_mutex; LIST_ENTRY all_fcbs; LIST_ENTRY dirty_fcbs; 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);
#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 -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); BOOL is_top_level(_In_ PIRP Irp); 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 NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject); #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 #define funcname __FUNCTION__ @@ -1192,8 +1205,8 @@ void _debug_message(_In_ const char* func, _In_ char* s, ...); #endif
#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); -#define free_fcb(Vcb, fcb) _free_fcb(Vcb, fcb, funcname) +void _free_fcb(_Inout_ fcb* fcb, _In_ const char* func); +#define free_fcb(fcb) _free_fcb(fcb, funcname) #endif
// 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_ 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); -tree* free_tree(tree* t); -NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT64 generation, PIRP Irp); -NTSTATUS do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, BOOL* loaded, PIRP Irp); +void free_tree(tree* t); +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, PIRP Irp); void clear_rollback(LIST_ENTRY* rollback); void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback); void free_trees_root(device_extension* Vcb, root* r); @@ -1380,7 +1393,6 @@ NTSTATUS NTAPI drv_set_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); 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 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 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); UINT32 inherit_mode(fcb* parfcb, BOOL is_dir); 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 NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp, UINT32 type); diff --git a/drivers/filesystems/btrfs/create.c b/drivers/filesystems/btrfs/create.c index 2cde2371e8..089b19c8a8 100644 --- a/drivers/filesystems/btrfs/create.c +++ b/drivers/filesystems/btrfs/create.c @@ -137,7 +137,6 @@ file_ref* create_fileref(device_extension* Vcb) { InitializeListHead(&fr->children);
ExInitializeResourceLite(&fr->nonpaged->fileref_lock); - ExInitializeResourceLite(&fr->nonpaged->children_lock);
return fr; } @@ -282,11 +281,17 @@ static NTSTATUS split_path(device_extension* Vcb, PUNICODE_STRING path, LIST_ENT BOOL has_stream; WCHAR* buf; name_bit* nb; + NTSTATUS Status;
len = path->Length / sizeof(WCHAR); if (len > 0 && (path->Buffer[len - 1] == '/' || path->Buffer[len - 1] == '\')) len--;
+ if (len == 0 || (path->Buffer[len - 1] == '/' || path->Buffer[len - 1] == '\')) { + WARN("zero-length filename part\n"); + return STATUS_OBJECT_NAME_INVALID; + } + has_stream = FALSE; for (i = 0; i < len; i++) { if (path->Buffer[i] == '/' || path->Buffer[i] == '\') { @@ -300,10 +305,17 @@ static NTSTATUS split_path(device_extension* Vcb, PUNICODE_STRING path, LIST_ENT
for (i = 0; i < len; i++) { if (path->Buffer[i] == '/' || path->Buffer[i] == '\') { + if (buf[0] == '/' || buf[0] == '\') { + WARN("zero-length filename part\n"); + Status = STATUS_OBJECT_NAME_INVALID; + goto cleanup; + } + nb = ExAllocateFromPagedLookasideList(&Vcb->name_bit_lookaside); if (!nb) { ERR("out of memory\n"); - return STATUS_INSUFFICIENT_RESOURCES; + Status = STATUS_INSUFFICIENT_RESOURCES; + goto cleanup; }
nb->us.Buffer = buf; @@ -317,7 +329,8 @@ static NTSTATUS split_path(device_extension* Vcb, PUNICODE_STRING path, LIST_ENT nb = ExAllocateFromPagedLookasideList(&Vcb->name_bit_lookaside); if (!nb) { ERR("out of memory\n"); - return STATUS_INSUFFICIENT_RESOURCES; + Status = STATUS_INSUFFICIENT_RESOURCES; + goto cleanup; }
nb->us.Buffer = buf; @@ -335,10 +348,17 @@ static NTSTATUS split_path(device_extension* Vcb, PUNICODE_STRING path, LIST_ENT if (nb->us.Buffer[i] == ':') { name_bit* nb2;
+ if (nb->us.Buffer[i+1] == 0) { + WARN("zero-length stream name\n"); + Status = STATUS_OBJECT_NAME_INVALID; + goto cleanup; + } + nb2 = ExAllocateFromPagedLookasideList(&Vcb->name_bit_lookaside); if (!nb2) { ERR("out of memory\n"); - return STATUS_INSUFFICIENT_RESOURCES; + Status = STATUS_INSUFFICIENT_RESOURCES; + goto cleanup; }
nb2->us.Buffer = &nb->us.Buffer[i+1]; @@ -377,6 +397,15 @@ static NTSTATUS split_path(device_extension* Vcb, PUNICODE_STRING path, LIST_ENT *stream = has_stream;
return STATUS_SUCCESS; + +cleanup: + while (!IsListEmpty(parts)) { + nb = CONTAINING_RECORD(RemoveHeadList(parts), name_bit, list_entry); + + ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb); + } + + return Status; }
NTSTATUS load_csum(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, UINT32* csum, UINT64 start, UINT64 length, PIRP Irp) { @@ -560,11 +589,6 @@ cont: break; }
- // If a directory has a lot of files, force it to stick around until the next flush - // so we aren't constantly re-reading. - if (num_children >= 100) - mark_fcb_dirty(fcb); - return STATUS_SUCCESS; }
@@ -577,9 +601,15 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo BOOL atts_set = FALSE, sd_set = FALSE, no_data; LIST_ENTRY* lastle = NULL; EXTENT_DATA* ed = NULL; + UINT64 fcbs_version; + UINT32 hash; + + hash = calc_crc32c(0xffffffff, (UINT8*)&inode, sizeof(UINT64));
- if (!IsListEmpty(&subvol->fcbs)) { - LIST_ENTRY* le = subvol->fcbs.Flink; + acquire_fcb_lock_shared(Vcb); + + if (subvol->fcbs_ptrs[hash >> 24]) { + LIST_ENTRY* le = subvol->fcbs_ptrs[hash >> 24];
while (le != &subvol->fcbs) { fcb = CONTAINING_RECORD(le, struct _fcb, list_entry); @@ -598,17 +628,21 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo #endif
*pfcb = fcb; + release_fcb_lock(Vcb); return STATUS_SUCCESS; } } - } else if (fcb->inode > inode) { + } else if (fcb->hash > hash) { if (deleted_fcb) { InterlockedIncrement(&deleted_fcb->refcount); *pfcb = deleted_fcb; + release_fcb_lock(Vcb); return STATUS_SUCCESS; }
lastle = le->Blink; + fcbs_version = subvol->fcbs_version; + break; }
@@ -616,6 +650,8 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo } }
+ release_fcb_lock(Vcb); + if (deleted_fcb) { InterlockedIncrement(&deleted_fcb->refcount); *pfcb = deleted_fcb; @@ -632,6 +668,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo
fcb->subvol = subvol; fcb->inode = inode; + fcb->hash = hash; fcb->type = type;
searchkey.obj_id = inode; @@ -641,13 +678,13 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE, Irp); if (!NT_SUCCESS(Status)) { ERR("error - find_item returned %08x\n", Status); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return Status; }
if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) { WARN("couldn't find INODE_ITEM for inode %llx in subvol %llx\n", inode, subvol->id); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INVALID_PARAMETER; }
@@ -696,7 +733,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo hl = ExAllocatePoolWithTag(pooltype, sizeof(hardlink), ALLOC_TAG); if (!hl) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -714,7 +751,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo if (!NT_SUCCESS(Status)) { ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status); ExFreePool(hl); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return Status; }
@@ -728,7 +765,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo if (!hl->name.Buffer) { ERR("out of memory\n"); ExFreePool(hl); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -737,7 +774,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status); ExFreePool(hl->name.Buffer); ExFreePool(hl); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return Status; } } @@ -761,7 +798,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo hl = ExAllocatePoolWithTag(pooltype, sizeof(hardlink), ALLOC_TAG); if (!hl) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -779,7 +816,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo if (!NT_SUCCESS(Status)) { ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status); ExFreePool(hl); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return Status; }
@@ -793,7 +830,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo if (!hl->name.Buffer) { ERR("out of memory\n"); ExFreePool(hl); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -802,7 +839,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status); ExFreePool(hl->name.Buffer); ExFreePool(hl); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return Status; } } @@ -835,7 +872,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo fcb->reparse_xattr.Buffer = ExAllocatePoolWithTag(PagedPool, di->m, ALLOC_TAG); if (!fcb->reparse_xattr.Buffer) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -858,7 +895,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo fcb->ea_xattr.Buffer = ExAllocatePoolWithTag(PagedPool, di->m, ALLOC_TAG); if (!fcb->ea_xattr.Buffer) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -906,7 +943,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo fcb->sd = ExAllocatePoolWithTag(PagedPool, di->m, ALLOC_TAG); if (!fcb->sd) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -941,14 +978,14 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo Status = RtlUTF8ToUnicodeN(NULL, 0, &utf16len, &di->name[sizeof(xapref) - 1], di->n + 1 - sizeof(xapref)); if (!NT_SUCCESS(Status)) { ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return Status; }
dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG); if (!dc) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -959,7 +996,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo if (!dc->utf8.Buffer) { ERR("out of memory\n"); ExFreePool(dc); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -971,7 +1008,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo ERR("out of memory\n"); ExFreePool(dc->utf8.Buffer); ExFreePool(dc); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -981,7 +1018,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo ExFreePool(dc->utf8.Buffer); ExFreePool(dc->name.Buffer); ExFreePool(dc); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return Status; }
@@ -991,7 +1028,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo ExFreePool(dc->utf8.Buffer); ExFreePool(dc->name.Buffer); ExFreePool(dc); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return Status; }
@@ -1004,7 +1041,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo xa = ExAllocatePoolWithTag(PagedPool, offsetof(xattr, data[0]) + di->m + di->n, ALLOC_TAG); if (!xa) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -1033,7 +1070,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA));
- free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INTERNAL_ERROR; }
@@ -1044,7 +1081,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2));
- free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INTERNAL_ERROR; }
@@ -1058,7 +1095,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo ext = ExAllocatePoolWithTag(pooltype, offsetof(extent, extent_data) + tp.item->size, ALLOC_TAG); if (!ext) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -1078,7 +1115,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo Status = load_dir_children(Vcb, fcb, FALSE, Irp); if (!NT_SUCCESS(Status)) { ERR("load_dir_children returned %08x\n", Status); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return Status; } } @@ -1103,25 +1140,102 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo if (!sd_set) fcb_get_sd(fcb, parent, FALSE, Irp);
- if (fcb->type == BTRFS_TYPE_DIRECTORY && fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT && fcb->reparse_xattr.Length == 0) { - fcb->atts &= ~FILE_ATTRIBUTE_REPARSE_POINT; + acquire_fcb_lock_exclusive(Vcb); + + if (lastle && subvol->fcbs_version == fcbs_version) + InsertHeadList(lastle, &fcb->list_entry); + else { + if (subvol->fcbs_ptrs[hash >> 24]) { + LIST_ENTRY* le = subvol->fcbs_ptrs[hash >> 24]; + + while (le != &subvol->fcbs) { + struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry); + + if (fcb2->inode == inode) { + if (!fcb2->ads) { + if (fcb2->deleted) + deleted_fcb = fcb2; + else { +#ifdef DEBUG_FCB_REFCOUNTS + LONG rc = InterlockedIncrement(&fcb2->refcount); + + WARN("fcb %p: refcount now %i (subvol %llx, inode %llx)\n", fcb2, rc, fcb2->subvol->id, fcb2->inode); +#else + InterlockedIncrement(&fcb2->refcount); +#endif + + *pfcb = fcb2; + release_fcb_lock(Vcb); + reap_fcb(fcb); + return STATUS_SUCCESS; + } + } + } else if (fcb2->hash > hash) { + if (deleted_fcb) { + InterlockedIncrement(&deleted_fcb->refcount); + *pfcb = deleted_fcb; + release_fcb_lock(Vcb); + reap_fcb(fcb); + return STATUS_SUCCESS; + } + + lastle = le->Blink; + break; + } + + le = le->Flink; + } + } + + if (fcb->type == BTRFS_TYPE_DIRECTORY && fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT && fcb->reparse_xattr.Length == 0) { + fcb->atts &= ~FILE_ATTRIBUTE_REPARSE_POINT; + + if (!Vcb->readonly && !is_subvol_readonly(subvol, Irp)) { + fcb->atts_changed = TRUE; + mark_fcb_dirty(fcb); + } + } + + if (!lastle) { + UINT8 c = hash >> 24; + + if (c != 0xff) { + UINT8 d = c + 1; + + do { + if (subvol->fcbs_ptrs[d]) { + lastle = subvol->fcbs_ptrs[d]->Blink; + break; + } + + d++; + } while (d != 0); + } + } + + if (lastle) { + InsertHeadList(lastle, &fcb->list_entry); + + if (lastle == &subvol->fcbs || (CONTAINING_RECORD(lastle, struct _fcb, list_entry)->hash >> 24) != (hash >> 24)) + subvol->fcbs_ptrs[hash >> 24] = &fcb->list_entry; + } else { + InsertTailList(&subvol->fcbs, &fcb->list_entry);
- if (!Vcb->readonly && !is_subvol_readonly(subvol, Irp)) { - fcb->atts_changed = TRUE; - mark_fcb_dirty(fcb); + if (fcb->list_entry.Blink == &subvol->fcbs || (CONTAINING_RECORD(fcb->list_entry.Blink, struct _fcb, list_entry)->hash >> 24) != (hash >> 24)) + subvol->fcbs_ptrs[hash >> 24] = &fcb->list_entry; } }
- if (lastle) - InsertHeadList(lastle, &fcb->list_entry); - else - InsertTailList(&subvol->fcbs, &fcb->list_entry); + subvol->fcbs_version++;
InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
+ release_fcb_lock(Vcb); + fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
*pfcb = fcb; + return STATUS_SUCCESS; }
@@ -1162,7 +1276,7 @@ static NTSTATUS open_fcb_stream(_Requires_lock_held_(_Curr_->tree_lock) _Require
if (!get_xattr(Vcb, parent->subvol, parent->inode, xattr.Buffer, crc32, &xattrdata, &xattrlen, Irp)) { ERR("get_xattr failed\n"); - free_fcb(Vcb, fcb); + reap_fcb(fcb); ExFreePool(xattr.Buffer); return STATUS_INTERNAL_ERROR; } @@ -1183,19 +1297,19 @@ static NTSTATUS open_fcb_stream(_Requires_lock_held_(_Curr_->tree_lock) _Require Status = find_item(Vcb, parent->subvol, &tp, &searchkey, FALSE, Irp); if (!NT_SUCCESS(Status)) { ERR("find_item returned %08x\n", Status); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return Status; }
if (keycmp(tp.item->key, searchkey)) { ERR("error - could not find key for xattr\n"); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INTERNAL_ERROR; }
if (tp.item->size < xattrlen) { 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, xattrlen); - free_fcb(Vcb, fcb); + reap_fcb(fcb); return STATUS_INTERNAL_ERROR; }
@@ -1213,10 +1327,6 @@ static NTSTATUS open_fcb_stream(_Requires_lock_held_(_Curr_->tree_lock) _Require
TRACE("stream found: size = %x, hash = %08x\n", xattrlen, fcb->adshash);
- InsertHeadList(&parent->list_entry, &fcb->list_entry); - - InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all); - *pfcb = fcb;
return STATUS_SUCCESS; @@ -1237,6 +1347,8 @@ NTSTATUS open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex UNICODE_STRING name_uc; dir_child* dc = NULL; fcb* fcb; + struct _fcb* duff_fcb = NULL; + file_ref* duff_fr = NULL;
if (!case_sensitive) { Status = RtlUpcaseUnicodeString(&name_uc, name, TRUE); @@ -1268,46 +1380,102 @@ NTSTATUS open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex le = le->Flink; }
- if (!case_sensitive) - ExFreePool(name_uc.Buffer); + if (!dc) { + if (locked) + ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
- if (locked) - ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock); + if (!case_sensitive) + ExFreePool(name_uc.Buffer);
- if (!dc) return STATUS_OBJECT_NAME_NOT_FOUND; + }
if (dc->fileref) { + if (locked) + ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock); + + if (!case_sensitive) + ExFreePool(name_uc.Buffer); + increase_fileref_refcount(dc->fileref); *psf2 = dc->fileref; return STATUS_SUCCESS; }
+ if (locked) + ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock); + + if (!case_sensitive) + ExFreePool(name_uc.Buffer); + Status = open_fcb_stream(Vcb, dc, sf->fcb, &fcb, Irp); if (!NT_SUCCESS(Status)) { ERR("open_fcb_stream returned %08x\n", Status); return Status; }
+ fcb->hash = sf->fcb->hash; + + acquire_fcb_lock_exclusive(Vcb); + + if (sf->fcb->subvol->fcbs_ptrs[fcb->hash >> 24]) { + LIST_ENTRY* le = sf->fcb->subvol->fcbs_ptrs[fcb->hash >> 24]; + + while (le != &sf->fcb->subvol->fcbs) { + struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry); + + if (fcb2->inode == fcb->inode) { + if (fcb2->ads && fcb2->adshash == fcb->adshash) { // FIXME - handle hash collisions + duff_fcb = fcb; + fcb = fcb2; + break; + } + } else if (fcb2->hash > fcb->hash) + break; + + le = le->Flink; + } + } + + if (!duff_fcb) { + InsertHeadList(&sf->fcb->list_entry, &fcb->list_entry); + InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all); + fcb->subvol->fcbs_version++; + } + + release_fcb_lock(Vcb); + + if (duff_fcb) { + reap_fcb(duff_fcb); + InterlockedIncrement(&fcb->refcount); + } + sf2 = create_fileref(Vcb); if (!sf2) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + free_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
- sf2->fcb = fcb; - - sf2->parent = (struct _file_ref*)sf; + ExAcquireResourceExclusiveLite(&sf->fcb->nonpaged->dir_children_lock, TRUE);
- sf2->dc = dc; - dc->fileref = sf2; + if (dc->fileref) { + duff_fr = sf2; + sf2 = dc->fileref; + increase_fileref_refcount(sf2); + } else { + sf2->fcb = fcb; + sf2->parent = (struct _file_ref*)sf; + sf2->dc = dc; + dc->fileref = sf2; + increase_fileref_refcount(sf); + InsertTailList(&sf->children, &sf2->list_entry); + }
- ExAcquireResourceExclusiveLite(&sf->nonpaged->children_lock, TRUE); - InsertTailList(&sf->children, &sf2->list_entry); - ExReleaseResourceLite(&sf->nonpaged->children_lock); + ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
- increase_fileref_refcount(sf); + if (duff_fr) + reap_fileref(Vcb, duff_fr); } else { root* subvol; UINT64 inode; @@ -1323,6 +1491,7 @@ NTSTATUS open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex return Status; } else { fcb* fcb; + file_ref* duff_fr = NULL; #ifdef DEBUG_STATS LARGE_INTEGER time1, time2; #endif @@ -1360,14 +1529,14 @@ NTSTATUS open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex
if (dc->type != BTRFS_TYPE_DIRECTORY && !lastpart && !(fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT)) { TRACE("passed path including file as subdirectory\n"); - free_fcb(Vcb, fcb); + free_fcb(fcb); return STATUS_OBJECT_PATH_NOT_FOUND; }
sf2 = create_fileref(Vcb); if (!sf2) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + free_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -1376,16 +1545,24 @@ NTSTATUS open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex if (dc->type == BTRFS_TYPE_DIRECTORY) fcb->fileref = sf2;
- sf2->dc = dc; - dc->fileref = sf2; + ExAcquireResourceExclusiveLite(&sf->fcb->nonpaged->dir_children_lock, TRUE);
- sf2->parent = (struct _file_ref*)sf; + if (!dc->fileref) { + sf2->parent = (struct _file_ref*)sf; + sf2->dc = dc; + dc->fileref = sf2; + InsertTailList(&sf->children, &sf2->list_entry); + increase_fileref_refcount(sf); + } else { + duff_fr = sf2; + sf2 = dc->fileref; + increase_fileref_refcount(sf2); + }
- ExAcquireResourceExclusiveLite(&sf->nonpaged->children_lock, TRUE); - InsertTailList(&sf->children, &sf2->list_entry); - ExReleaseResourceLite(&sf->nonpaged->children_lock); + ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
- increase_fileref_refcount(sf); + if (duff_fr) + reap_fileref(Vcb, duff_fr); } }
@@ -1406,13 +1583,6 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusiv
TRACE("(%p, %p, %p, %u, %p)\n", Vcb, pfr, related, parent, parsed);
-#ifdef DEBUG - if (!ExIsResourceAcquiredExclusiveLite(&Vcb->fcb_lock) && !ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock)) { - ERR("fcb_lock not acquired exclusively\n"); - int3; - } -#endif - if (Vcb->removing || Vcb->locked) return STATUS_ACCESS_DENIED;
@@ -1456,7 +1626,8 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusiv *fn_offset = 0;
return STATUS_SUCCESS; - } + } else if (fnus2.Length >= 2 * sizeof(WCHAR) && fnus2.Buffer[1] == '\') + return STATUS_OBJECT_NAME_INVALID;
dir = Vcb->root_fileref;
@@ -1559,7 +1730,7 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusiv break; }
- free_fileref(Vcb, sf); + free_fileref(sf); sf = sf2;
le = le->Flink; @@ -1570,7 +1741,7 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusiv *pfr = sf2;
end: - free_fileref(Vcb, sf); + free_fileref(sf);
while (!IsListEmpty(&parts)) { name_bit* nb = CONTAINING_RECORD(RemoveHeadList(&parts), name_bit, list_entry); @@ -1586,6 +1757,7 @@ end2: NTSTATUS add_dir_child(fcb* fcb, UINT64 inode, BOOL subvol, PANSI_STRING utf8, PUNICODE_STRING name, UINT8 type, dir_child** pdc) { NTSTATUS Status; dir_child* dc; + BOOL locked;
dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG); if (!dc) { @@ -1632,7 +1804,10 @@ NTSTATUS add_dir_child(fcb* fcb, UINT64 inode, BOOL subvol, PANSI_STRING utf8, P dc->hash = calc_crc32c(0xffffffff, (UINT8*)dc->name.Buffer, dc->name.Length); dc->hash_uc = calc_crc32c(0xffffffff, (UINT8*)dc->name_uc.Buffer, dc->name_uc.Length);
- ExAcquireResourceExclusiveLite(&fcb->nonpaged->dir_children_lock, TRUE); + locked = ExIsResourceAcquiredExclusive(&fcb->nonpaged->dir_children_lock); + + if (!locked) + ExAcquireResourceExclusiveLite(&fcb->nonpaged->dir_children_lock, TRUE);
if (IsListEmpty(&fcb->dir_children_index)) dc->index = 2; @@ -1646,7 +1821,8 @@ NTSTATUS add_dir_child(fcb* fcb, UINT64 inode, BOOL subvol, PANSI_STRING utf8, P
insert_dir_child_into_hash_lists(fcb, dc);
- ExReleaseResourceLite(&fcb->nonpaged->dir_children_lock); + if (!locked) + ExReleaseResourceLite(&fcb->nonpaged->dir_children_lock);
*pdc = dc;
@@ -1883,7 +2059,7 @@ end:
static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _In_ PUNICODE_STRING fpus, _In_ file_ref* parfileref, _In_ ULONG options, _In_reads_bytes_opt_(ealen) FILE_FULL_EA_INFORMATION* ea, _In_ ULONG ealen, - _Out_ file_ref** pfr, _In_ LIST_ENTRY* rollback) { + _Out_ file_ref** pfr, BOOL case_sensitive, _In_ LIST_ENTRY* rollback) { NTSTATUS Status; fcb* fcb; ULONG utf8len; @@ -1898,6 +2074,8 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr file_ref* fileref; dir_child* dc; ANSI_STRING utf8as; + LIST_ENTRY* lastle = NULL; + file_ref* existing_fileref = NULL; #ifdef DEBUG_FCB_REFCOUNTS LONG rc; #endif @@ -2057,18 +2235,74 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr fcb->created = TRUE; fcb->deleted = TRUE;
+ fcb->hash = calc_crc32c(0xffffffff, (UINT8*)&inode, sizeof(UINT64)); + + acquire_fcb_lock_exclusive(Vcb); + + if (fcb->subvol->fcbs_ptrs[fcb->hash >> 24]) { + LIST_ENTRY* le = fcb->subvol->fcbs_ptrs[fcb->hash >> 24]; + + while (le != &fcb->subvol->fcbs) { + struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry); + + if (fcb2->hash > fcb->hash) { + lastle = le->Blink; + break; + } + + le = le->Flink; + } + } + + if (!lastle) { + UINT8 c = fcb->hash >> 24; + + if (c != 0xff) { + UINT8 d = c + 1; + + do { + if (fcb->subvol->fcbs_ptrs[d]) { + lastle = fcb->subvol->fcbs_ptrs[d]->Blink; + break; + } + + d++; + } while (d != 0); + } + } + + if (lastle) { + InsertHeadList(lastle, &fcb->list_entry); + + if (lastle == &fcb->subvol->fcbs || (CONTAINING_RECORD(lastle, struct _fcb, list_entry)->hash >> 24) != (fcb->hash >> 24)) + fcb->subvol->fcbs_ptrs[fcb->hash >> 24] = &fcb->list_entry; + } else { + InsertTailList(&fcb->subvol->fcbs, &fcb->list_entry); + + if (fcb->list_entry.Blink == &fcb->subvol->fcbs || (CONTAINING_RECORD(fcb->list_entry.Blink, struct _fcb, list_entry)->hash >> 24) != (fcb->hash >> 24)) + fcb->subvol->fcbs_ptrs[fcb->hash >> 24] = &fcb->list_entry; + } + + InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all); + + fcb->subvol->fcbs_version++; + + release_fcb_lock(Vcb); + mark_fcb_dirty(fcb);
Status = fcb_get_new_sd(fcb, parfileref, IrpSp->Parameters.Create.SecurityContext->AccessState);
if (!NT_SUCCESS(Status)) { ERR("fcb_get_new_sd returned %08x\n", Status); - free_fcb(Vcb, fcb); + free_fcb(fcb);
ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE); parfileref->fcb->inode_item.st_size -= utf8len * 2; ExReleaseResourceLite(parfileref->fcb->Header.Resource);
+ ExFreePool(utf8); + return Status; }
@@ -2078,12 +2312,14 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr Status = file_create_parse_ea(fcb, ea); if (!NT_SUCCESS(Status)) { ERR("file_create_parse_ea returned %08x\n", Status); - free_fcb(Vcb, fcb); + free_fcb(fcb);
ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE); parfileref->fcb->inode_item.st_size -= utf8len * 2; ExReleaseResourceLite(parfileref->fcb->Header.Resource);
+ ExFreePool(utf8); + return Status; } } @@ -2091,12 +2327,14 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr fileref = create_fileref(Vcb); if (!fileref) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + free_fcb(fcb);
ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE); parfileref->fcb->inode_item.st_size -= utf8len * 2; ExReleaseResourceLite(parfileref->fcb->Header.Resource);
+ ExFreePool(utf8); + return STATUS_INSUFFICIENT_RESOURCES; }
@@ -2107,12 +2345,14 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr
if (!NT_SUCCESS(Status)) { ERR("extend_file returned %08x\n", Status); - free_fileref(Vcb, fileref); + reap_fileref(Vcb, fileref);
ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE); parfileref->fcb->inode_item.st_size -= utf8len * 2; ExReleaseResourceLite(parfileref->fcb->Header.Resource);
+ ExFreePool(utf8); + return Status; } } @@ -2121,12 +2361,14 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG); if (!fcb->hash_ptrs) { ERR("out of memory\n"); - free_fileref(Vcb, fileref); + reap_fileref(Vcb, fileref);
ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE); parfileref->fcb->inode_item.st_size -= utf8len * 2; ExReleaseResourceLite(parfileref->fcb->Header.Resource);
+ ExFreePool(utf8); + return STATUS_INSUFFICIENT_RESOURCES; }
@@ -2135,12 +2377,14 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr fcb->hash_ptrs_uc = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG); if (!fcb->hash_ptrs_uc) { ERR("out of memory\n"); - free_fileref(Vcb, fileref); + reap_fileref(Vcb, fileref);
ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE); parfileref->fcb->inode_item.st_size -= utf8len * 2; ExReleaseResourceLite(parfileref->fcb->Header.Resource);
+ ExFreePool(utf8); + return STATUS_INSUFFICIENT_RESOURCES; }
@@ -2150,39 +2394,126 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr fcb->deleted = FALSE;
fileref->created = TRUE; - mark_fileref_dirty(fileref);
fcb->subvol->root_item.ctransid = Vcb->superblock.generation; fcb->subvol->root_item.ctime = now;
- fileref->parent = parfileref; - utf8as.Buffer = utf8; utf8as.Length = utf8as.MaximumLength = (UINT16)utf8len;
- Status = add_dir_child(fileref->parent->fcb, fcb->inode, FALSE, &utf8as, fpus, fcb->type, &dc); - if (!NT_SUCCESS(Status)) - WARN("add_dir_child returned %08x\n", Status); + ExAcquireResourceExclusiveLite(&parfileref->fcb->nonpaged->dir_children_lock, TRUE);
- ExFreePool(utf8); + // check again doesn't already exist + if (case_sensitive) { + UINT32 dc_hash = calc_crc32c(0xffffffff, (UINT8*)fpus->Buffer, fpus->Length); + + if (parfileref->fcb->hash_ptrs[dc_hash >> 24]) { + LIST_ENTRY* le = parfileref->fcb->hash_ptrs[dc_hash >> 24]; + while (le != &parfileref->fcb->dir_children_hash) { + dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_hash); + + if (dc->hash == dc_hash && dc->name.Length == fpus->Length && RtlCompareMemory(dc->name.Buffer, fpus->Buffer, fpus->Length) == fpus->Length) { + existing_fileref = dc->fileref; + break; + } else if (dc->hash > dc_hash) + break; + + le = le->Flink; + } + } + } else { + UNICODE_STRING fpusuc; +#ifdef __REACTOS__ + UINT32 dc_hash; +#endif + + Status = RtlUpcaseUnicodeString(&fpusuc, fpus, TRUE); + if (!NT_SUCCESS(Status)) { + ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock); + ERR("RtlUpcaseUnicodeString returned %08x\n", Status); + reap_fileref(Vcb, fileref);
+ ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE); + parfileref->fcb->inode_item.st_size -= utf8len * 2; + ExReleaseResourceLite(parfileref->fcb->Header.Resource); + + ExFreePool(utf8); + + return Status; + } + +#ifndef __REACTOS__ + UINT32 dc_hash = calc_crc32c(0xffffffff, (UINT8*)fpusuc.Buffer, fpusuc.Length); +#else + dc_hash = calc_crc32c(0xffffffff, (UINT8*)fpusuc.Buffer, fpusuc.Length); +#endif + + if (parfileref->fcb->hash_ptrs_uc[dc_hash >> 24]) { + LIST_ENTRY* le = parfileref->fcb->hash_ptrs_uc[dc_hash >> 24]; + while (le != &parfileref->fcb->dir_children_hash_uc) { + dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_hash_uc); + + if (dc->hash_uc == dc_hash && dc->name.Length == fpusuc.Length && RtlCompareMemory(dc->name.Buffer, fpusuc.Buffer, fpusuc.Length) == fpusuc.Length) { + existing_fileref = dc->fileref; + break; + } else if (dc->hash_uc > dc_hash) + break; + + le = le->Flink; + } + } + + ExFreePool(fpusuc.Buffer); + } + + if (existing_fileref) { + ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock); + reap_fileref(Vcb, fileref); + + ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE); + parfileref->fcb->inode_item.st_size -= utf8len * 2; + ExReleaseResourceLite(parfileref->fcb->Header.Resource); + + ExFreePool(utf8); + + increase_fileref_refcount(existing_fileref); + *pfr = existing_fileref; + + return STATUS_OBJECT_NAME_COLLISION; + } + + Status = add_dir_child(parfileref->fcb, fcb->inode, FALSE, &utf8as, fpus, fcb->type, &dc); + if (!NT_SUCCESS(Status)) { + ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock); + ERR("add_dir_child returned %08x\n", Status); + reap_fileref(Vcb, fileref); + + ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE); + parfileref->fcb->inode_item.st_size -= utf8len * 2; + ExReleaseResourceLite(parfileref->fcb->Header.Resource); + + ExFreePool(utf8); + + return Status; + } + + fileref->parent = parfileref; fileref->dc = dc; dc->fileref = fileref;
- ExAcquireResourceExclusiveLite(&parfileref->nonpaged->children_lock, TRUE); + if (type == BTRFS_TYPE_DIRECTORY) + fileref->fcb->fileref = fileref; + InsertTailList(&parfileref->children, &fileref->list_entry); - ExReleaseResourceLite(&parfileref->nonpaged->children_lock); + ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock);
- increase_fileref_refcount(parfileref); + ExFreePool(utf8);
- InsertTailList(&fcb->subvol->fcbs, &fcb->list_entry); - InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all); + mark_fileref_dirty(fileref); + increase_fileref_refcount(parfileref);
*pfr = fileref;
- if (type == BTRFS_TYPE_DIRECTORY) - fileref->fcb->fileref = fileref; - TRACE("created new file %S in subvol %llx, inode %llx\n", file_desc_fileref(fileref), fcb->subvol->id, fcb->inode);
return STATUS_SUCCESS; @@ -2205,10 +2536,14 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ KEY searchkey; traverse_ptr tp; dir_child* dc; + dir_child* existing_dc = NULL; ACCESS_MASK granted_access; #ifdef DEBUG_FCB_REFCOUNTS LONG rc; #endif +#ifdef __REACTOS__ + LIST_ENTRY* le; +#endif
TRACE("fpus = %.*S\n", fpus->Length / sizeof(WCHAR), fpus->Buffer); TRACE("stream = %.*S\n", stream->Length / sizeof(WCHAR), stream->Buffer); @@ -2248,16 +2583,18 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
- Status = file_create2(Irp, Vcb, &fpus2, parfileref, options, NULL, 0, &newpar, rollback); + Status = file_create2(Irp, Vcb, &fpus2, parfileref, options, NULL, 0, &newpar, case_sensitive, rollback);
if (!NT_SUCCESS(Status)) { ERR("file_create2 returned %08x\n", Status); ExFreePool(fpus2.Buffer); return Status; + } else if (Status != STATUS_OBJECT_NAME_COLLISION) { + send_notification_fileref(newpar, options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL); + send_notification_fcb(newpar->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); }
- send_notification_fileref(newpar, options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL); - send_notification_fcb(newpar->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); + ExFreePool(fpus2.Buffer); } else if (!NT_SUCCESS(Status)) { ERR("open_fileref returned %08x\n", Status); return Status; @@ -2268,16 +2605,20 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
if (parfileref->fcb->type != BTRFS_TYPE_FILE && parfileref->fcb->type != BTRFS_TYPE_SYMLINK && parfileref->fcb->type != BTRFS_TYPE_DIRECTORY) { WARN("parent not file, directory, or symlink\n"); + free_fileref(parfileref); return STATUS_INVALID_PARAMETER; }
if (options & FILE_DIRECTORY_FILE) { WARN("tried to create directory as stream\n"); + free_fileref(parfileref); return STATUS_INVALID_PARAMETER; }
- if (parfileref->fcb->atts & FILE_ATTRIBUTE_READONLY) + if (parfileref->fcb->atts & FILE_ATTRIBUTE_READONLY) { + free_fileref(parfileref); return STATUS_ACCESS_DENIED; + }
SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
@@ -2285,6 +2626,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ TRUE, FILE_WRITE_DATA, 0, NULL, IoGetFileObjectGenericMapping(), IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode, &granted_access, &Status)) { SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext); + free_fileref(parfileref); return Status; }
@@ -2293,12 +2635,14 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ if ((stream->Length == sizeof(DOSATTRIB) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, DOSATTRIB, stream->Length) == stream->Length) || (stream->Length == sizeof(EA) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, EA, stream->Length) == stream->Length) || (stream->Length == sizeof(reparse) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, reparse, stream->Length) == stream->Length)) { + free_fileref(parfileref); return STATUS_OBJECT_NAME_INVALID; }
fcb = create_fcb(Vcb, pool_type); if (!fcb) { ERR("out of memory\n"); + free_fileref(parfileref); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -2324,7 +2668,8 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, stream->Buffer, stream->Length); if (!NT_SUCCESS(Status)) { ERR("RtlUnicodeToUTF8N 1 returned %08x\n", Status); - free_fcb(Vcb, fcb); + reap_fcb(fcb); + free_fileref(parfileref); return Status; }
@@ -2333,7 +2678,8 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ fcb->adsxattr.Buffer = ExAllocatePoolWithTag(pool_type, fcb->adsxattr.MaximumLength, ALLOC_TAG); if (!fcb->adsxattr.Buffer) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + reap_fcb(fcb); + free_fileref(parfileref); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -2342,7 +2688,8 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ Status = RtlUnicodeToUTF8N(&fcb->adsxattr.Buffer[sizeof(xapref) - 1], utf8len, &utf8len, stream->Buffer, stream->Length); if (!NT_SUCCESS(Status)) { ERR("RtlUnicodeToUTF8N 2 returned %08x\n", Status); - free_fcb(Vcb, fcb); + reap_fcb(fcb); + free_fileref(parfileref); return Status; }
@@ -2360,7 +2707,8 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ Status = find_item(Vcb, parfileref->fcb->subvol, &tp, &searchkey, FALSE, Irp); if (!NT_SUCCESS(Status)) { ERR("find_item returned %08x\n", Status); - free_fcb(Vcb, fcb); + reap_fcb(fcb); + free_fileref(parfileref); return Status; }
@@ -2373,24 +2721,38 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
if (utf8len + sizeof(xapref) - 1 + overhead > fcb->adsmaxlen) { WARN("not enough room for new DIR_ITEM (%u + %u > %u)", utf8len + sizeof(xapref) - 1, overhead, fcb->adsmaxlen); - free_fcb(Vcb, fcb); + reap_fcb(fcb); + free_fileref(parfileref); return STATUS_DISK_FULL; } else fcb->adsmaxlen -= overhead + utf8len + sizeof(xapref) - 1;
- fileref = create_fileref(Vcb); - if (!fileref) { - ERR("out of memory\n"); - free_fcb(Vcb, fcb); - return STATUS_INSUFFICIENT_RESOURCES; - } + fcb->created = TRUE; + fcb->deleted = TRUE; + + acquire_fcb_lock_exclusive(Vcb); + InsertHeadList(&parfileref->fcb->list_entry, &fcb->list_entry); // insert in list after parent fcb + InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all); + parfileref->fcb->subvol->fcbs_version++; + release_fcb_lock(Vcb); + + mark_fcb_dirty(fcb); + + fileref = create_fileref(Vcb); + if (!fileref) { + ERR("out of memory\n"); + free_fcb(fcb); + free_fileref(parfileref); + return STATUS_INSUFFICIENT_RESOURCES; + }
fileref->fcb = fcb;
dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG); if (!dc) { ERR("out of memory\n"); - free_fileref(Vcb, fileref); + reap_fileref(Vcb, fileref); + free_fileref(parfileref); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -2401,7 +2763,8 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ if (!dc->utf8.Buffer) { ERR("out of memory\n"); ExFreePool(dc); - free_fileref(Vcb, fileref); + reap_fileref(Vcb, fileref); + free_fileref(parfileref); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -2413,7 +2776,8 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ ERR("out of memory\n"); ExFreePool(dc->utf8.Buffer); ExFreePool(dc); - free_fileref(Vcb, fileref); + reap_fileref(Vcb, fileref); + free_fileref(parfileref); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -2425,23 +2789,62 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ ExFreePool(dc->utf8.Buffer); ExFreePool(dc->name.Buffer); ExFreePool(dc); - free_fileref(Vcb, fileref); + reap_fileref(Vcb, fileref); + free_fileref(parfileref); return Status; }
+ KeQuerySystemTime(&time); + win_time_to_unix(time, &now); + + ExAcquireResourceExclusiveLite(&parfileref->fcb->nonpaged->dir_children_lock, TRUE); + +#ifndef __REACTOS__ + LIST_ENTRY* le = parfileref->fcb->dir_children_index.Flink; +#else + le = parfileref->fcb->dir_children_index.Flink; +#endif + while (le != &parfileref->fcb->dir_children_index) { + dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_index); + + if (dc2->index == 0) { + if ((case_sensitive && dc2->name.Length == dc->name.Length && RtlCompareMemory(dc2->name.Buffer, dc->name.Buffer, dc2->name.Length) == dc2->name.Length) || + (!case_sensitive && dc2->name_uc.Length == dc->name_uc.Length && RtlCompareMemory(dc2->name_uc.Buffer, dc->name_uc.Buffer, dc2->name_uc.Length) == dc2->name_uc.Length) + ) { + existing_dc = dc2; + break; + } + } else + break; + + le = le->Flink; + } + + if (existing_dc) { + ExFreePool(dc->utf8.Buffer); + ExFreePool(dc->name.Buffer); + ExFreePool(dc); + reap_fileref(Vcb, fileref); + free_fileref(parfileref); + + increase_fileref_refcount(existing_dc->fileref); + *pfileref = existing_dc->fileref; + + return STATUS_OBJECT_NAME_COLLISION; + } + dc->fileref = fileref; fileref->dc = dc; + fileref->parent = (struct _file_ref*)parfileref; + fcb->deleted = FALSE;
InsertHeadList(&parfileref->fcb->dir_children_index, &dc->list_entry_index);
- mark_fcb_dirty(fcb); - mark_fileref_dirty(fileref); + InsertTailList(&parfileref->children, &fileref->list_entry);
- InsertHeadList(&parfileref->fcb->list_entry, &fcb->list_entry); // insert in list after parent fcb - InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all); + ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock);
- KeQuerySystemTime(&time); - win_time_to_unix(time, &now); + mark_fileref_dirty(fileref);
parfileref->fcb->inode_item.transid = Vcb->superblock.generation; parfileref->fcb->inode_item.sequence++; @@ -2453,12 +2856,6 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ parfileref->fcb->subvol->root_item.ctransid = Vcb->superblock.generation; parfileref->fcb->subvol->root_item.ctime = now;
- fileref->parent = (struct _file_ref*)parfileref; - - ExAcquireResourceExclusiveLite(&parfileref->nonpaged->children_lock, TRUE); - InsertTailList(&parfileref->children, &fileref->list_entry); - ExReleaseResourceLite(&parfileref->nonpaged->children_lock); - increase_fileref_refcount(parfileref);
*pfileref = fileref; @@ -2501,7 +2898,8 @@ static __inline BOOL called_from_lxss() { #endif
static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb, - PFILE_OBJECT FileObject, file_ref* related, BOOL loaded_related, PUNICODE_STRING fnus, ULONG disposition, ULONG options, LIST_ENTRY* rollback) { + PFILE_OBJECT FileObject, file_ref* related, BOOL loaded_related, PUNICODE_STRING fnus, ULONG disposition, ULONG options, + file_ref** existing_fileref, LIST_ENTRY* rollback) { NTSTATUS Status; file_ref *fileref, *parfileref = NULL; ULONG i, j; @@ -2655,9 +3053,12 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R }
Status = file_create2(Irp, Vcb, &fpus, parfileref, options, Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength, - &fileref, rollback); + &fileref, IrpSp->Flags & SL_CASE_SENSITIVE, rollback);
- if (!NT_SUCCESS(Status)) { + if (Status == STATUS_OBJECT_NAME_COLLISION) { + *existing_fileref = fileref; + goto end; + } else if (!NT_SUCCESS(Status)) { ERR("file_create2 returned %08x\n", Status); goto end; } @@ -2683,7 +3084,7 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R ExReleaseResourceLite(parfileref->fcb->Header.Resource); }
- free_fileref(Vcb, fileref); + free_fileref(fileref); goto end; }
@@ -2739,7 +3140,7 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R ExReleaseResourceLite(parfileref->fcb->Header.Resource); }
- free_fileref(Vcb, fileref); + free_fileref(fileref); return Status; } } @@ -2757,7 +3158,7 @@ end:
end2: if (parfileref && !loaded_related) - free_fileref(Vcb, parfileref); + free_fileref(parfileref);
return Status; } @@ -3050,791 +3451,887 @@ end: fcb->csum_loaded = TRUE; }
-static NTSTATUS open_file(PDEVICE_OBJECT DeviceObject, _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback) { - PFILE_OBJECT FileObject = NULL; - ULONG RequestedDisposition; - ULONG options; +static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, POOL_TYPE pool_type, file_ref* fileref, ACCESS_MASK* granted_access, + PFILE_OBJECT FileObject, UNICODE_STRING* fn, ULONG options, PIRP Irp, LIST_ENTRY* rollback) { NTSTATUS Status; + file_ref* sf; + BOOL readonly; ccb* ccb; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); - USHORT parsed; - ULONG fn_offset = 0; - file_ref *related, *fileref = NULL; - POOL_TYPE pool_type = IrpSp->Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : PagedPool; - ACCESS_MASK granted_access; - BOOL loaded_related = FALSE; - UNICODE_STRING fn; -#ifdef DEBUG_FCB_REFCOUNTS - LONG oc; -#endif -#ifdef DEBUG_STATS - LARGE_INTEGER time1, time2; - UINT8 open_type = 0;
- time1 = KeQueryPerformanceCounter(NULL); + if (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) { + LARGE_INTEGER zero; + +#ifdef DEBUG_STATS + open_type = 1; #endif + if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY || is_subvol_readonly(fileref->fcb->subvol, Irp)) { + free_fileref(fileref);
- Irp->IoStatus.Information = 0; + return STATUS_ACCESS_DENIED; + }
- RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 0xff); - options = IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS; + if (Vcb->readonly) { + free_fileref(fileref);
- if (options & FILE_DIRECTORY_FILE && RequestedDisposition == FILE_SUPERSEDE) { - WARN("error - supersede requested with FILE_DIRECTORY_FILE\n"); - return STATUS_INVALID_PARAMETER; - } + return STATUS_MEDIA_WRITE_PROTECTED; + }
- FileObject = IrpSp->FileObject; + zero.QuadPart = 0; + if (!MmCanFileBeTruncated(&fileref->fcb->nonpaged->segment_object, &zero)) { + free_fileref(fileref);
- if (!FileObject) { - ERR("FileObject was NULL\n"); - return STATUS_INVALID_PARAMETER; + return STATUS_USER_MAPPED_FILE; + } }
- if (FileObject->RelatedFileObject && FileObject->RelatedFileObject->FsContext2) { - struct _ccb* relatedccb = FileObject->RelatedFileObject->FsContext2; - - related = relatedccb->fileref; - } else - related = NULL; + if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess != 0) { + SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
- debug_create_options(options); + if (!SeAccessCheck((fileref->fcb->ads || fileref->fcb == Vcb->dummy_fcb) ? fileref->parent->fcb->sd : fileref->fcb->sd, + &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext, + TRUE, IrpSp->Parameters.Create.SecurityContext->DesiredAccess, 0, NULL, + IoGetFileObjectGenericMapping(), IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode, + granted_access, &Status)) { + SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext); + TRACE("SeAccessCheck failed, returning %08x\n", Status);
- switch (RequestedDisposition) { - case FILE_SUPERSEDE: - TRACE("requested disposition: FILE_SUPERSEDE\n"); - break; + free_fileref(fileref);
- case FILE_CREATE: - TRACE("requested disposition: FILE_CREATE\n"); - break; + return Status; + }
- case FILE_OPEN: - TRACE("requested disposition: FILE_OPEN\n"); - break; + SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext); + } else + *granted_access = 0;
- case FILE_OPEN_IF: - TRACE("requested disposition: FILE_OPEN_IF\n"); - break; + TRACE("deleted = %s\n", fileref->deleted ? "TRUE" : "FALSE");
- case FILE_OVERWRITE: - TRACE("requested disposition: FILE_OVERWRITE\n"); - break; + sf = fileref; + while (sf) { + if (sf->delete_on_close) { + TRACE("could not open as deletion pending\n");
- case FILE_OVERWRITE_IF: - TRACE("requested disposition: FILE_OVERWRITE_IF\n"); - break; + free_fileref(fileref);
- default: - ERR("unknown disposition: %x\n", RequestedDisposition); - Status = STATUS_NOT_IMPLEMENTED; - goto exit; + return STATUS_DELETE_PENDING; + } + sf = sf->parent; }
- fn = FileObject->FileName; + readonly = (!fileref->fcb->ads && fileref->fcb->atts & FILE_ATTRIBUTE_READONLY) || (fileref->fcb->ads && fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY) || + is_subvol_readonly(fileref->fcb->subvol, Irp) || fileref->fcb == Vcb->dummy_fcb || Vcb->readonly;
- TRACE("(%.*S)\n", fn.Length / sizeof(WCHAR), fn.Buffer); - TRACE("FileObject = %p\n", FileObject); + if (options & FILE_DELETE_ON_CLOSE && (fileref == Vcb->root_fileref || readonly)) { + free_fileref(fileref);
- if (Vcb->readonly && (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_CREATE || RequestedDisposition == FILE_OVERWRITE)) { - Status = STATUS_MEDIA_WRITE_PROTECTED; - goto exit; + return STATUS_CANNOT_DELETE; }
- acquire_fcb_lock_exclusive(Vcb); - - if (options & FILE_OPEN_BY_FILE_ID) { - if (fn.Length == sizeof(UINT64) && related && RequestedDisposition == FILE_OPEN) { - UINT64 inode; - - RtlCopyMemory(&inode, fn.Buffer, sizeof(UINT64)); - - if (related->fcb == Vcb->root_fileref->fcb && inode == 0) - inode = Vcb->root_fileref->fcb->inode; + if (readonly) { + ACCESS_MASK allowed;
- if (inode == 0) { // we use 0 to mean the parent of a subvolume - fileref = related->parent; - increase_fileref_refcount(fileref); - Status = STATUS_SUCCESS; - } else { - Status = open_fileref_by_inode(Vcb, related->fcb->subvol, inode, &fileref, Irp); - } - } else { - WARN("FILE_OPEN_BY_FILE_ID only supported for inodes\n"); - Status = STATUS_NOT_IMPLEMENTED; - release_fcb_lock(Vcb); - goto exit; - } - } else { - if (related && fn.Length != 0 && fn.Buffer[0] == '\') { - Status = STATUS_INVALID_PARAMETER; - release_fcb_lock(Vcb); - goto exit; - } + allowed = READ_CONTROL | SYNCHRONIZE | ACCESS_SYSTEM_SECURITY | FILE_READ_DATA | + FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_EXECUTE | FILE_LIST_DIRECTORY | + FILE_TRAVERSE;
- if (!related && RequestedDisposition != FILE_OPEN && !(IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY)) { - ULONG fnoff; + if (!Vcb->readonly && (fileref->fcb == Vcb->dummy_fcb || fileref->fcb->inode == SUBVOL_ROOT_INODE)) + allowed |= DELETE;
- Status = open_fileref(Vcb, &related, &fn, NULL, TRUE, &parsed, &fnoff, - pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp); + if (fileref->fcb != Vcb->dummy_fcb && !is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) { + allowed |= DELETE | WRITE_OWNER | WRITE_DAC | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES;
- if (Status == STATUS_OBJECT_NAME_NOT_FOUND) - Status = STATUS_OBJECT_PATH_NOT_FOUND; - else if (Status == STATUS_REPARSE) - fileref = related; - else if (NT_SUCCESS(Status)) { - fnoff *= sizeof(WCHAR); - fnoff += (related->dc ? related->dc->name.Length : 0) + sizeof(WCHAR); - - if (related->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) { - Status = STATUS_REPARSE; - fileref = related; - parsed = (USHORT)fnoff - sizeof(WCHAR); - } else { - fn.Buffer = &fn.Buffer[fnoff / sizeof(WCHAR)]; - fn.Length -= (USHORT)fnoff; + if (!fileref->fcb->ads && fileref->fcb->type == BTRFS_TYPE_DIRECTORY) + allowed |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | FILE_DELETE_CHILD; + } else if (fileref->fcb->inode == SUBVOL_ROOT_INODE && is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) { + // We allow a subvolume root to be opened read-write even if its readonly flag is set, so it can be cleared
- Status = open_fileref(Vcb, &fileref, &fn, related, IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY, &parsed, &fn_offset, - pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp); + allowed |= FILE_WRITE_ATTRIBUTES; + }
- loaded_related = TRUE; - } + if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess & MAXIMUM_ALLOWED) { + *granted_access &= allowed; + IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess &= allowed; + } else if (*granted_access & ~allowed) { + free_fileref(fileref);
- } - } else { - Status = open_fileref(Vcb, &fileref, &fn, related, IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY, &parsed, &fn_offset, - pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp); + return Vcb->readonly ? STATUS_MEDIA_WRITE_PROTECTED : STATUS_ACCESS_DENIED; } }
- if (Status == STATUS_REPARSE) { + if ((fileref->fcb->type == BTRFS_TYPE_SYMLINK || fileref->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) && !(options & FILE_OPEN_REPARSE_POINT)) { REPARSE_DATA_BUFFER* data;
- ExAcquireResourceSharedLite(fileref->fcb->Header.Resource, TRUE); - Status = get_reparse_block(fileref->fcb, (UINT8**)&data); - ExReleaseResourceLite(fileref->fcb->Header.Resource); + /* How reparse points work from the point of view of the filesystem appears to + * undocumented. When returning STATUS_REPARSE, MSDN encourages us to return + * IO_REPARSE in Irp->IoStatus.Information, but that means we have to do our own + * translation. If we instead return the reparse tag in Information, and store + * a pointer to the reparse data buffer in Irp->Tail.Overlay.AuxiliaryBuffer, + * IopSymlinkProcessReparse will do the translation for us. */
+ Status = get_reparse_block(fileref->fcb, (UINT8**)&data); if (!NT_SUCCESS(Status)) { ERR("get_reparse_block returned %08x\n", Status); - Status = STATUS_SUCCESS; } else { - Status = STATUS_REPARSE; - RtlCopyMemory(&Irp->IoStatus.Information, data, sizeof(ULONG)); + Irp->IoStatus.Information = data->ReparseTag;
- data->Reserved = FileObject->FileName.Length - parsed; + if (fn->Buffer[(fn->Length / sizeof(WCHAR)) - 1] == '\') + data->Reserved = sizeof(WCHAR);
Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
- free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + free_fileref(fileref);
- goto exit; + return STATUS_REPARSE; } }
- if (NT_SUCCESS(Status) && fileref->deleted) - Status = STATUS_OBJECT_NAME_NOT_FOUND; + if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY && !fileref->fcb->ads) { + if (options & FILE_NON_DIRECTORY_FILE && !(fileref->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT)) { + free_fileref(fileref);
- if (NT_SUCCESS(Status)) { - if (RequestedDisposition == FILE_CREATE) { - TRACE("file %S already exists, returning STATUS_OBJECT_NAME_COLLISION\n", file_desc_fileref(fileref)); - Status = STATUS_OBJECT_NAME_COLLISION; + return STATUS_FILE_IS_A_DIRECTORY; + } + } else if (options & FILE_DIRECTORY_FILE) { + TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u, %S)\n", fileref->fcb->type, file_desc_fileref(fileref));
- free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + free_fileref(fileref);
- goto exit; - } - } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { - if (RequestedDisposition == FILE_OPEN || RequestedDisposition == FILE_OVERWRITE) { - TRACE("file doesn't exist, returning STATUS_OBJECT_NAME_NOT_FOUND\n"); - release_fcb_lock(Vcb); - goto exit; - } - } else if (Status == STATUS_OBJECT_PATH_NOT_FOUND) { - TRACE("open_fileref returned %08x\n", Status); - release_fcb_lock(Vcb); - goto exit; - } else { - ERR("open_fileref returned %08x\n", Status); - release_fcb_lock(Vcb); - goto exit; + return STATUS_NOT_A_DIRECTORY; }
- if (NT_SUCCESS(Status)) { // file already exists - file_ref* sf; - BOOL readonly; + if (fileref->open_count > 0) { + Status = IoCheckShareAccess(*granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access, FALSE);
- release_fcb_lock(Vcb); + if (!NT_SUCCESS(Status)) { + if (Status == STATUS_SHARING_VIOLATION) + TRACE("IoCheckShareAccess failed, returning %08x\n", Status); + else + WARN("IoCheckShareAccess failed, returning %08x\n", Status);
- if (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) { - LARGE_INTEGER zero; + free_fileref(fileref);
-#ifdef DEBUG_STATS - open_type = 1; -#endif - if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY || is_subvol_readonly(fileref->fcb->subvol, Irp)) { - Status = STATUS_ACCESS_DENIED; + return Status; + }
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + IoUpdateShareAccess(FileObject, &fileref->fcb->share_access); + } else + IoSetShareAccess(*granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access);
- goto exit; - } + if (*granted_access & FILE_WRITE_DATA || options & FILE_DELETE_ON_CLOSE) { + if (!MmFlushImageSection(&fileref->fcb->nonpaged->segment_object, MmFlushForWrite)) {
- if (Vcb->readonly) { - Status = STATUS_MEDIA_WRITE_PROTECTED; + IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + free_fileref(fileref);
- goto exit; - } + return (options & FILE_DELETE_ON_CLOSE) ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION; + } + }
- zero.QuadPart = 0; - if (!MmCanFileBeTruncated(&fileref->fcb->nonpaged->segment_object, &zero)) { - Status = STATUS_USER_MAPPED_FILE; + if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) { + ULONG defda, oldatts, filter; + LARGE_INTEGER time; + BTRFS_TIME now;
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + if ((RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) && readonly) { + WARN("cannot overwrite readonly file\n");
- goto exit; - } - } + IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess != 0) { - SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext); + free_fileref(fileref);
- if (!SeAccessCheck((fileref->fcb->ads || fileref->fcb == Vcb->dummy_fcb) ? fileref->parent->fcb->sd : fileref->fcb->sd, - &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext, - TRUE, IrpSp->Parameters.Create.SecurityContext->DesiredAccess, 0, NULL, - IoGetFileObjectGenericMapping(), IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode, - &granted_access, &Status)) { - SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext); - TRACE("SeAccessCheck failed, returning %08x\n", Status); + return STATUS_ACCESS_DENIED; + }
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + if (!fileref->fcb->ads && (IrpSp->Parameters.Create.FileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != ((fileref->fcb->atts & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)))) { + IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- goto exit; - } + free_fileref(fileref);
- SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext); - } else - granted_access = 0; + return STATUS_ACCESS_DENIED; + }
- TRACE("deleted = %s\n", fileref->deleted ? "TRUE" : "FALSE"); + if (fileref->fcb->ads) { + Status = stream_set_end_of_file_information(Vcb, 0, fileref->fcb, fileref, FALSE); + if (!NT_SUCCESS(Status)) { + ERR("stream_set_end_of_file_information returned %08x\n", Status);
- sf = fileref; - while (sf) { - if (sf->delete_on_close) { - TRACE("could not open as deletion pending\n"); - Status = STATUS_DELETE_PENDING; + IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + free_fileref(fileref);
- goto exit; + return Status; } - sf = sf->parent; - } - - readonly = (!fileref->fcb->ads && fileref->fcb->atts & FILE_ATTRIBUTE_READONLY) || (fileref->fcb->ads && fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY) || - is_subvol_readonly(fileref->fcb->subvol, Irp) || fileref->fcb == Vcb->dummy_fcb || Vcb->readonly; + } else { + Status = truncate_file(fileref->fcb, 0, Irp, rollback); + if (!NT_SUCCESS(Status)) { + ERR("truncate_file returned %08x\n", Status);
- if (options & FILE_DELETE_ON_CLOSE && (fileref == Vcb->root_fileref || readonly)) { - Status = STATUS_CANNOT_DELETE; + IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + free_fileref(fileref);
- goto exit; + return Status; + } }
- if (readonly) { - ACCESS_MASK allowed; + if (Irp->Overlay.AllocationSize.QuadPart > 0) { + Status = extend_file(fileref->fcb, fileref, Irp->Overlay.AllocationSize.QuadPart, TRUE, NULL, rollback);
- allowed = READ_CONTROL | SYNCHRONIZE | ACCESS_SYSTEM_SECURITY | FILE_READ_DATA | - FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_EXECUTE | FILE_LIST_DIRECTORY | - FILE_TRAVERSE; - - if (!Vcb->readonly && (fileref->fcb == Vcb->dummy_fcb || fileref->fcb->inode == SUBVOL_ROOT_INODE)) - allowed |= DELETE; + if (!NT_SUCCESS(Status)) { + ERR("extend_file returned %08x\n", Status);
- if (fileref->fcb != Vcb->dummy_fcb && !is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) { - allowed |= DELETE | WRITE_OWNER | WRITE_DAC | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES; + IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- if (!fileref->fcb->ads && fileref->fcb->type == BTRFS_TYPE_DIRECTORY) - allowed |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | FILE_DELETE_CHILD; - } else if (fileref->fcb->inode == SUBVOL_ROOT_INODE && is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) { - // We allow a subvolume root to be opened read-write even if its readonly flag is set, so it can be cleared + free_fileref(fileref);
- allowed |= FILE_WRITE_ATTRIBUTES; + return Status; } + }
- if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess & MAXIMUM_ALLOWED) { - granted_access &= allowed; - IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess &= allowed; - } else if (granted_access & ~allowed) { - Status = Vcb->readonly ? STATUS_MEDIA_WRITE_PROTECTED : STATUS_ACCESS_DENIED; + if (!fileref->fcb->ads) { + LIST_ENTRY* le;
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + if (Irp->AssociatedIrp.SystemBuffer && IrpSp->Parameters.Create.EaLength > 0) { + ULONG offset; + FILE_FULL_EA_INFORMATION* eainfo;
- goto exit; - } - } + Status = IoCheckEaBufferValidity(Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength, &offset); + if (!NT_SUCCESS(Status)) { + ERR("IoCheckEaBufferValidity returned %08x (error at offset %u)\n", Status, offset);
- if ((fileref->fcb->type == BTRFS_TYPE_SYMLINK || fileref->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) && !(options & FILE_OPEN_REPARSE_POINT)) { - REPARSE_DATA_BUFFER* data; + IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- /* How reparse points work from the point of view of the filesystem appears to - * undocumented. When returning STATUS_REPARSE, MSDN encourages us to return - * IO_REPARSE in Irp->IoStatus.Information, but that means we have to do our own - * translation. If we instead return the reparse tag in Information, and store - * a pointer to the reparse data buffer in Irp->Tail.Overlay.AuxiliaryBuffer, - * IopSymlinkProcessReparse will do the translation for us. */ + free_fileref(fileref);
- Status = get_reparse_block(fileref->fcb, (UINT8**)&data); - if (!NT_SUCCESS(Status)) { - ERR("get_reparse_block returned %08x\n", Status); - Status = STATUS_SUCCESS; - } else { - Status = STATUS_REPARSE; - Irp->IoStatus.Information = data->ReparseTag; + return Status; + }
- if (fn.Buffer[(fn.Length / sizeof(WCHAR)) - 1] == '\') - data->Reserved = sizeof(WCHAR); + fileref->fcb->ealen = 4;
- Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data; + // capitalize EA name + eainfo = Irp->AssociatedIrp.SystemBuffer; + do { + STRING s;
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + s.Length = s.MaximumLength = eainfo->EaNameLength; + s.Buffer = eainfo->EaName;
- goto exit; - } - } + RtlUpperString(&s, &s);
- if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY && !fileref->fcb->ads) { - if (options & FILE_NON_DIRECTORY_FILE && !(fileref->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT)) { - Status = STATUS_FILE_IS_A_DIRECTORY; + fileref->fcb->ealen += 5 + eainfo->EaNameLength + eainfo->EaValueLength;
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + if (eainfo->NextEntryOffset == 0) + break;
- goto exit; - } - } else if (options & FILE_DIRECTORY_FILE) { - TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u, %S)\n", fileref->fcb->type, file_desc_fileref(fileref)); - Status = STATUS_NOT_A_DIRECTORY; + eainfo = (FILE_FULL_EA_INFORMATION*)(((UINT8*)eainfo) + eainfo->NextEntryOffset); + } while (TRUE);
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + if (fileref->fcb->ea_xattr.Buffer) + ExFreePool(fileref->fcb->ea_xattr.Buffer);
- goto exit; - } + fileref->fcb->ea_xattr.Buffer = ExAllocatePoolWithTag(pool_type, IrpSp->Parameters.Create.EaLength, ALLOC_TAG); + if (!fileref->fcb->ea_xattr.Buffer) { + ERR("out of memory\n");
- if (fileref->open_count > 0) { - Status = IoCheckShareAccess(granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access, FALSE); + IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- if (!NT_SUCCESS(Status)) { - if (Status == STATUS_SHARING_VIOLATION) - TRACE("IoCheckShareAccess failed, returning %08x\n", Status); - else - WARN("IoCheckShareAccess failed, returning %08x\n", Status); + free_fileref(fileref);
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + return STATUS_INSUFFICIENT_RESOURCES; + }
- goto exit; + fileref->fcb->ea_xattr.Length = fileref->fcb->ea_xattr.MaximumLength = (USHORT)IrpSp->Parameters.Create.EaLength; + RtlCopyMemory(fileref->fcb->ea_xattr.Buffer, Irp->AssociatedIrp.SystemBuffer, fileref->fcb->ea_xattr.Length); + } else { + if (fileref->fcb->ea_xattr.Length > 0) { + ExFreePool(fileref->fcb->ea_xattr.Buffer); + fileref->fcb->ea_xattr.Buffer = NULL; + fileref->fcb->ea_xattr.Length = fileref->fcb->ea_xattr.MaximumLength = 0; + + fileref->fcb->ea_changed = TRUE; + fileref->fcb->ealen = 0; + } }
- IoUpdateShareAccess(FileObject, &fileref->fcb->share_access); - } else - IoSetShareAccess(granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access); + // remove streams and send notifications + le = fileref->fcb->dir_children_index.Flink; + while (le != &fileref->fcb->dir_children_index) { + dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index); + LIST_ENTRY* le2 = le->Flink;
- if (granted_access & FILE_WRITE_DATA || options & FILE_DELETE_ON_CLOSE) { - if (!MmFlushImageSection(&fileref->fcb->nonpaged->segment_object, MmFlushForWrite)) { - Status = (options & FILE_DELETE_ON_CLOSE) ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION; + if (dc->index == 0) { + if (!dc->fileref) { + file_ref* fr2;
- IoRemoveShareAccess(FileObject, &fileref->fcb->share_access); + Status = open_fileref_child(Vcb, fileref, &dc->name, TRUE, TRUE, TRUE, PagedPool, &fr2, NULL); + if (!NT_SUCCESS(Status)) + WARN("open_fileref_child returned %08x\n", Status); + }
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + if (dc->fileref) { + send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_REMOVED_STREAM, &dc->name);
- goto exit; + Status = delete_fileref(dc->fileref, NULL, NULL, rollback); + if (!NT_SUCCESS(Status)) { + ERR("delete_fileref returned %08x\n", Status); + + free_fileref(fileref); + + return Status; + } + } + } else + break; + + le = le2; } }
- if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) { - ULONG defda, oldatts, filter; - LARGE_INTEGER time; - BTRFS_TIME now; + KeQuerySystemTime(&time); + win_time_to_unix(time, &now);
- if ((RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) && readonly) { - WARN("cannot overwrite readonly file\n"); - Status = STATUS_ACCESS_DENIED; + filter = FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE;
- IoRemoveShareAccess(FileObject, &fileref->fcb->share_access); + if (fileref->fcb->ads) { + fileref->parent->fcb->inode_item.st_mtime = now; + fileref->parent->fcb->inode_item_changed = TRUE; + mark_fcb_dirty(fileref->parent->fcb);
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + send_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED, &fileref->dc->name); + } else { + mark_fcb_dirty(fileref->fcb);
- goto exit; - } + oldatts = fileref->fcb->atts;
- if (!fileref->fcb->ads && (IrpSp->Parameters.Create.FileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != ((fileref->fcb->atts & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)))) { - IoRemoveShareAccess(FileObject, &fileref->fcb->share_access); + defda = get_file_attributes(Vcb, fileref->fcb->subvol, fileref->fcb->inode, fileref->fcb->type, + fileref->dc && fileref->dc->name.Length >= sizeof(WCHAR) && fileref->dc->name.Buffer[0] == '.', TRUE, Irp);
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + if (RequestedDisposition == FILE_SUPERSEDE) + fileref->fcb->atts = IrpSp->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE; + else + fileref->fcb->atts |= IrpSp->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
- Status = STATUS_ACCESS_DENIED; - goto exit; + if (fileref->fcb->atts != oldatts) { + fileref->fcb->atts_changed = TRUE; + fileref->fcb->atts_deleted = IrpSp->Parameters.Create.FileAttributes == defda; + filter |= FILE_NOTIFY_CHANGE_ATTRIBUTES; }
- if (fileref->fcb->ads) { - Status = stream_set_end_of_file_information(Vcb, 0, fileref->fcb, fileref, FALSE); - if (!NT_SUCCESS(Status)) { - ERR("stream_set_end_of_file_information returned %08x\n", Status); + fileref->fcb->inode_item.transid = Vcb->superblock.generation; + fileref->fcb->inode_item.sequence++; + fileref->fcb->inode_item.st_ctime = now; + fileref->fcb->inode_item.st_mtime = now; + fileref->fcb->inode_item_changed = TRUE; + + send_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL); + } + } else { + if (options & FILE_NO_EA_KNOWLEDGE && fileref->fcb->ea_xattr.Length > 0) { + FILE_FULL_EA_INFORMATION* ffei = (FILE_FULL_EA_INFORMATION*)fileref->fcb->ea_xattr.Buffer; + + do { + if (ffei->Flags & FILE_NEED_EA) { + WARN("returning STATUS_ACCESS_DENIED as no EA knowledge\n");
IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + free_fileref(fileref);
- goto exit; + return STATUS_ACCESS_DENIED; } - } else { - Status = truncate_file(fileref->fcb, 0, Irp, rollback); - if (!NT_SUCCESS(Status)) { - ERR("truncate_file returned %08x\n", Status);
- IoRemoveShareAccess(FileObject, &fileref->fcb->share_access); + if (ffei->NextEntryOffset == 0) + break;
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + ffei = (FILE_FULL_EA_INFORMATION*)(((UINT8*)ffei) + ffei->NextEntryOffset); + } while (TRUE); + } + }
- goto exit; - } - } + FileObject->FsContext = fileref->fcb;
- if (Irp->Overlay.AllocationSize.QuadPart > 0) { - Status = extend_file(fileref->fcb, fileref, Irp->Overlay.AllocationSize.QuadPart, TRUE, NULL, rollback); + ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ccb), ALLOC_TAG); + if (!ccb) { + ERR("out of memory\n");
- if (!NT_SUCCESS(Status)) { - ERR("extend_file returned %08x\n", Status); + IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- IoRemoveShareAccess(FileObject, &fileref->fcb->share_access); + free_fileref(fileref);
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + return STATUS_INSUFFICIENT_RESOURCES; + }
- goto exit; - } - } + RtlZeroMemory(ccb, sizeof(*ccb));
- if (!fileref->fcb->ads) { - LIST_ENTRY* le; + ccb->NodeType = BTRFS_NODE_TYPE_CCB; + ccb->NodeSize = sizeof(*ccb); + ccb->disposition = RequestedDisposition; + ccb->options = options; + ccb->query_dir_offset = 0; + RtlInitUnicodeString(&ccb->query_string, NULL); + ccb->has_wildcard = FALSE; + ccb->specific_file = FALSE; + ccb->access = *granted_access; + ccb->case_sensitive = IrpSp->Flags & SL_CASE_SENSITIVE; + ccb->reserving = FALSE; + ccb->lxss = called_from_lxss();
- if (Irp->AssociatedIrp.SystemBuffer && IrpSp->Parameters.Create.EaLength > 0) { - ULONG offset; - FILE_FULL_EA_INFORMATION* eainfo; + ccb->fileref = fileref;
- Status = IoCheckEaBufferValidity(Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength, &offset); - if (!NT_SUCCESS(Status)) { - ERR("IoCheckEaBufferValidity returned %08x (error at offset %u)\n", Status, offset); + FileObject->FsContext2 = ccb; + FileObject->SectionObjectPointer = &fileref->fcb->nonpaged->segment_object;
- IoRemoveShareAccess(FileObject, &fileref->fcb->share_access); + if (NT_SUCCESS(Status)) { + switch (RequestedDisposition) { + case FILE_SUPERSEDE: + Irp->IoStatus.Information = FILE_SUPERSEDED; + break;
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + case FILE_OPEN: + case FILE_OPEN_IF: + Irp->IoStatus.Information = FILE_OPENED; + break;
- goto exit; - } + case FILE_OVERWRITE: + case FILE_OVERWRITE_IF: + Irp->IoStatus.Information = FILE_OVERWRITTEN; + break; + } + }
- fileref->fcb->ealen = 4; + // Make sure paging files don't have any extents marked as being prealloc, + // as this would mean we'd have to lock exclusively when writing. + if (IrpSp->Flags & SL_OPEN_PAGING_FILE) { + LIST_ENTRY* le; + BOOL changed = FALSE;
- // capitalize EA name - eainfo = Irp->AssociatedIrp.SystemBuffer; - do { - STRING s; + ExAcquireResourceExclusiveLite(fileref->fcb->Header.Resource, TRUE);
- s.Length = s.MaximumLength = eainfo->EaNameLength; - s.Buffer = eainfo->EaName; + le = fileref->fcb->extents.Flink;
- RtlUpperString(&s, &s); + while (le != &fileref->fcb->extents) { + extent* ext = CONTAINING_RECORD(le, extent, list_entry);
- fileref->fcb->ealen += 5 + eainfo->EaNameLength + eainfo->EaValueLength; + if (ext->extent_data.type == EXTENT_TYPE_PREALLOC) { + ext->extent_data.type = EXTENT_TYPE_REGULAR; + changed = TRUE; + }
- if (eainfo->NextEntryOffset == 0) - break; + le = le->Flink; + }
- eainfo = (FILE_FULL_EA_INFORMATION*)(((UINT8*)eainfo) + eainfo->NextEntryOffset); - } while (TRUE); + ExReleaseResourceLite(fileref->fcb->Header.Resource);
- if (fileref->fcb->ea_xattr.Buffer) - ExFreePool(fileref->fcb->ea_xattr.Buffer); + if (changed) { + fileref->fcb->extents_changed = TRUE; + mark_fcb_dirty(fileref->fcb); + }
- fileref->fcb->ea_xattr.Buffer = ExAllocatePoolWithTag(pool_type, IrpSp->Parameters.Create.EaLength, ALLOC_TAG); - if (!fileref->fcb->ea_xattr.Buffer) { - ERR("out of memory\n"); - Status = STATUS_INSUFFICIENT_RESOURCES; + fileref->fcb->Header.Flags2 |= FSRTL_FLAG2_IS_PAGING_FILE; + Vcb->disallow_dismount = TRUE; + }
- IoRemoveShareAccess(FileObject, &fileref->fcb->share_access); +#ifdef DEBUG_FCB_REFCOUNTS + LONG oc = InterlockedIncrement(&fileref->open_count); + ERR("fileref %p: open_count now %i\n", fileref, oc); +#else + InterlockedIncrement(&fileref->open_count); +#endif + InterlockedIncrement(&Vcb->open_files);
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + return STATUS_SUCCESS; +}
- goto exit; - } +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; +#ifdef __REACTOS__ + hardlink* hl; +#endif
- fileref->fcb->ea_xattr.Length = fileref->fcb->ea_xattr.MaximumLength = (USHORT)IrpSp->Parameters.Create.EaLength; - RtlCopyMemory(fileref->fcb->ea_xattr.Buffer, Irp->AssociatedIrp.SystemBuffer, fileref->fcb->ea_xattr.Length); - } else { - if (fileref->fcb->ea_xattr.Length > 0) { - ExFreePool(fileref->fcb->ea_xattr.Buffer); - fileref->fcb->ea_xattr.Buffer = NULL; - fileref->fcb->ea_xattr.Length = fileref->fcb->ea_xattr.MaximumLength = 0; + 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; + }
- fileref->fcb->ea_changed = TRUE; - fileref->fcb->ealen = 0; - } - } + if (fcb->fileref) { + *pfr = fcb->fileref; + increase_fileref_refcount(fcb->fileref); + return STATUS_SUCCESS; + }
- // remove streams and send notifications - le = fileref->fcb->dir_children_index.Flink; - while (le != &fileref->fcb->dir_children_index) { - dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index); - LIST_ENTRY* le2 = le->Flink; +#ifndef __REACTOS__ + hardlink* hl = CONTAINING_RECORD(fcb->hardlinks.Flink, hardlink, list_entry); +#else + hl = CONTAINING_RECORD(fcb->hardlinks.Flink, hardlink, list_entry); +#endif
- if (dc->index == 0) { - if (!dc->fileref) { - file_ref* fr2; + name = hl->name; + parent = hl->parent;
- Status = open_fileref_child(Vcb, fileref, &dc->name, TRUE, TRUE, TRUE, PagedPool, &fr2, NULL); - if (!NT_SUCCESS(Status)) - WARN("open_fileref_child returned %08x\n", Status); - } + if (parent == inode) { // subvolume root + KEY searchkey; + traverse_ptr tp;
- if (dc->fileref) { - send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_REMOVED_STREAM, &dc->name); + searchkey.obj_id = subvol->id; + searchkey.obj_type = TYPE_ROOT_BACKREF; + searchkey.offset = 0xffffffffffffffff;
- Status = delete_fileref(dc->fileref, NULL, NULL, rollback); - if (!NT_SUCCESS(Status)) { - ERR("delete_fileref returned %08x\n", Status); + Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp); + if (!NT_SUCCESS(Status)) { + ERR("find_item returned %08x\n", Status); + free_fcb(fcb); + return Status; + }
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + 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;
- goto exit; - } - } - } else - break; + 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(fcb); + return STATUS_INTERNAL_ERROR; + }
- le = le2; - } + 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(fcb); + return STATUS_INTERNAL_ERROR; }
- KeQuerySystemTime(&time); - win_time_to_unix(time, &now); + 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; + }
- filter = FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE; + le = le->Flink; + }
- if (fileref->fcb->ads) { - fileref->parent->fcb->inode_item.st_mtime = now; - fileref->parent->fcb->inode_item_changed = TRUE; - mark_fcb_dirty(fileref->parent->fcb); + if (!r) { + ERR("couldn't find subvol %llx\n", tp.item->key.offset); + free_fcb(fcb); + return STATUS_INTERNAL_ERROR; + }
- send_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED, &fileref->dc->name); - } else { - mark_fcb_dirty(fileref->fcb); + 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(fcb); + return Status; + }
- oldatts = fileref->fcb->atts; + Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, rr->name, rr->n); + if (!NT_SUCCESS(Status)) { + ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status); + free_fcb(fcb); + return Status; + }
- defda = get_file_attributes(Vcb, fileref->fcb->subvol, fileref->fcb->inode, fileref->fcb->type, - fileref->dc && fileref->dc->name.Length >= sizeof(WCHAR) && fileref->dc->name.Buffer[0] == '.', TRUE, Irp); + name.Length = name.MaximumLength = (UINT16)stringlen;
- if (RequestedDisposition == FILE_SUPERSEDE) - fileref->fcb->atts = IrpSp->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE; - else - fileref->fcb->atts |= IrpSp->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE; + if (stringlen == 0) + name.Buffer = NULL; + else { + name.Buffer = ExAllocatePoolWithTag(PagedPool, name.MaximumLength, ALLOC_TAG);
- if (fileref->fcb->atts != oldatts) { - fileref->fcb->atts_changed = TRUE; - fileref->fcb->atts_deleted = IrpSp->Parameters.Create.FileAttributes == defda; - filter |= FILE_NOTIFY_CHANGE_ATTRIBUTES; + if (!name.Buffer) { + ERR("out of memory\n"); + free_fcb(fcb); + return STATUS_INSUFFICIENT_RESOURCES; }
- fileref->fcb->inode_item.transid = Vcb->superblock.generation; - fileref->fcb->inode_item.sequence++; - fileref->fcb->inode_item.st_ctime = now; - fileref->fcb->inode_item.st_mtime = now; - fileref->fcb->inode_item_changed = TRUE; + 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(fcb); + return Status; + }
- send_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL); + hl_alloc = TRUE; } } else { - if (options & FILE_NO_EA_KNOWLEDGE && fileref->fcb->ea_xattr.Length > 0) { - FILE_FULL_EA_INFORMATION* ffei = (FILE_FULL_EA_INFORMATION*)fileref->fcb->ea_xattr.Buffer; + ERR("couldn't find parent for subvol %llx\n", subvol->id); + free_fcb(fcb); + 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(fcb); + return Status; + } + }
- do { - if (ffei->Flags & FILE_NEED_EA) { - WARN("returning STATUS_ACCESS_DENIED as no EA knowledge\n"); - Status = STATUS_ACCESS_DENIED; + Status = open_fileref_child(Vcb, parfr, &name, TRUE, TRUE, FALSE, PagedPool, &fr, Irp);
- IoRemoveShareAccess(FileObject, &fileref->fcb->share_access); + if (hl_alloc) + ExFreePool(name.Buffer);
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + if (!NT_SUCCESS(Status)) { + ERR("open_fileref_child returned %08x\n", Status);
- goto exit; - } + free_fcb(fcb); + free_fileref(parfr);
- if (ffei->NextEntryOffset == 0) - break; + return Status; + }
- ffei = (FILE_FULL_EA_INFORMATION*)(((UINT8*)ffei) + ffei->NextEntryOffset); - } while (TRUE); - } - } + *pfr = fr;
- FileObject->FsContext = fileref->fcb; + free_fcb(fcb); + free_fileref(parfr);
- ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ccb), ALLOC_TAG); - if (!ccb) { - ERR("out of memory\n"); - Status = STATUS_INSUFFICIENT_RESOURCES; + return STATUS_SUCCESS; +}
- IoRemoveShareAccess(FileObject, &fileref->fcb->share_access); +static NTSTATUS open_file(PDEVICE_OBJECT DeviceObject, _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback) { + PFILE_OBJECT FileObject = NULL; + ULONG RequestedDisposition; + ULONG options; + NTSTATUS Status; + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + USHORT parsed; + ULONG fn_offset = 0; + file_ref *related, *fileref = NULL; + POOL_TYPE pool_type = IrpSp->Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : PagedPool; + ACCESS_MASK granted_access; + BOOL loaded_related = FALSE; + UNICODE_STRING fn; +#ifdef DEBUG_STATS + LARGE_INTEGER time1, time2; + UINT8 open_type = 0; + + time1 = KeQueryPerformanceCounter(NULL); +#endif + + Irp->IoStatus.Information = 0; + + RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 0xff); + options = IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS; + + if (options & FILE_DIRECTORY_FILE && RequestedDisposition == FILE_SUPERSEDE) { + WARN("error - supersede requested with FILE_DIRECTORY_FILE\n"); + return STATUS_INVALID_PARAMETER; + } + + FileObject = IrpSp->FileObject; + + if (!FileObject) { + ERR("FileObject was NULL\n"); + return STATUS_INVALID_PARAMETER; + } + + if (FileObject->RelatedFileObject && FileObject->RelatedFileObject->FsContext2) { + struct _ccb* relatedccb = FileObject->RelatedFileObject->FsContext2; + + related = relatedccb->fileref; + } else + related = NULL; + + debug_create_options(options); + + switch (RequestedDisposition) { + case FILE_SUPERSEDE: + TRACE("requested disposition: FILE_SUPERSEDE\n"); + break; + + case FILE_CREATE: + TRACE("requested disposition: FILE_CREATE\n"); + break; + + case FILE_OPEN: + TRACE("requested disposition: FILE_OPEN\n"); + break; + + case FILE_OPEN_IF: + TRACE("requested disposition: FILE_OPEN_IF\n"); + break; + + case FILE_OVERWRITE: + TRACE("requested disposition: FILE_OVERWRITE\n"); + break; + + case FILE_OVERWRITE_IF: + TRACE("requested disposition: FILE_OVERWRITE_IF\n"); + break; + + default: + ERR("unknown disposition: %x\n", RequestedDisposition); + Status = STATUS_NOT_IMPLEMENTED; + goto exit; + } + + fn = FileObject->FileName; + + TRACE("(%.*S)\n", fn.Length / sizeof(WCHAR), fn.Buffer); + TRACE("FileObject = %p\n", FileObject); + + if (Vcb->readonly && (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_CREATE || RequestedDisposition == FILE_OVERWRITE)) { + Status = STATUS_MEDIA_WRITE_PROTECTED; + goto exit; + } + + if (options & FILE_OPEN_BY_FILE_ID) { + if (fn.Length == sizeof(UINT64) && related && RequestedDisposition == FILE_OPEN) { + UINT64 inode; + + RtlCopyMemory(&inode, fn.Buffer, sizeof(UINT64)); + + if (related->fcb == Vcb->root_fileref->fcb && inode == 0) + inode = Vcb->root_fileref->fcb->inode;
- acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fileref); - release_fcb_lock(Vcb); + if (inode == 0) { // we use 0 to mean the parent of a subvolume + fileref = related->parent; + increase_fileref_refcount(fileref); + Status = STATUS_SUCCESS; + } else + Status = open_fileref_by_inode(Vcb, related->fcb->subvol, inode, &fileref, Irp);
+ goto loaded; + } else { + WARN("FILE_OPEN_BY_FILE_ID only supported for inodes\n"); + Status = STATUS_NOT_IMPLEMENTED; goto exit; } + }
- RtlZeroMemory(ccb, sizeof(*ccb)); + if (related && fn.Length != 0 && fn.Buffer[0] == '\') { + Status = STATUS_INVALID_PARAMETER; + goto exit; + }
- ccb->NodeType = BTRFS_NODE_TYPE_CCB; - ccb->NodeSize = sizeof(*ccb); - ccb->disposition = RequestedDisposition; - ccb->options = options; - ccb->query_dir_offset = 0; - RtlInitUnicodeString(&ccb->query_string, NULL); - ccb->has_wildcard = FALSE; - ccb->specific_file = FALSE; - ccb->access = granted_access; - ccb->case_sensitive = IrpSp->Flags & SL_CASE_SENSITIVE; - ccb->reserving = FALSE; - ccb->lxss = called_from_lxss(); + if (!related && RequestedDisposition != FILE_OPEN && !(IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY)) { + ULONG fnoff;
- ccb->fileref = fileref; + Status = open_fileref(Vcb, &related, &fn, NULL, TRUE, &parsed, &fnoff, + pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
- FileObject->FsContext2 = ccb; - FileObject->SectionObjectPointer = &fileref->fcb->nonpaged->segment_object; + if (Status == STATUS_OBJECT_NAME_NOT_FOUND) + Status = STATUS_OBJECT_PATH_NOT_FOUND; + else if (Status == STATUS_REPARSE) + fileref = related; + else if (NT_SUCCESS(Status)) { + fnoff *= sizeof(WCHAR); + fnoff += (related->dc ? related->dc->name.Length : 0) + sizeof(WCHAR);
- if (NT_SUCCESS(Status)) { - switch (RequestedDisposition) { - case FILE_SUPERSEDE: - Irp->IoStatus.Information = FILE_SUPERSEDED; - break; + if (related->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) { + Status = STATUS_REPARSE; + fileref = related; + parsed = (USHORT)fnoff - sizeof(WCHAR); + } else { + fn.Buffer = &fn.Buffer[fnoff / sizeof(WCHAR)]; + fn.Length -= (USHORT)fnoff;
- case FILE_OPEN: - case FILE_OPEN_IF: - Irp->IoStatus.Information = FILE_OPENED; - break; + Status = open_fileref(Vcb, &fileref, &fn, related, IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY, &parsed, &fn_offset, + pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
- case FILE_OVERWRITE: - case FILE_OVERWRITE_IF: - Irp->IoStatus.Information = FILE_OVERWRITTEN; - break; + loaded_related = TRUE; } } + } else { + Status = open_fileref(Vcb, &fileref, &fn, related, IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY, &parsed, &fn_offset, + pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp); + }
- // Make sure paging files don't have any extents marked as being prealloc, - // as this would mean we'd have to lock exclusively when writing. - if (IrpSp->Flags & SL_OPEN_PAGING_FILE) { - LIST_ENTRY* le; - BOOL changed = FALSE; +loaded: + if (Status == STATUS_REPARSE) { + REPARSE_DATA_BUFFER* data;
- ExAcquireResourceExclusiveLite(fileref->fcb->Header.Resource, TRUE); + ExAcquireResourceSharedLite(fileref->fcb->Header.Resource, TRUE); + Status = get_reparse_block(fileref->fcb, (UINT8**)&data); + ExReleaseResourceLite(fileref->fcb->Header.Resource);
- le = fileref->fcb->extents.Flink; + if (!NT_SUCCESS(Status)) { + ERR("get_reparse_block returned %08x\n", Status);
- while (le != &fileref->fcb->extents) { - extent* ext = CONTAINING_RECORD(le, extent, list_entry); + Status = STATUS_SUCCESS; + } else { + Status = STATUS_REPARSE; + RtlCopyMemory(&Irp->IoStatus.Information, data, sizeof(ULONG));
- if (ext->extent_data.type == EXTENT_TYPE_PREALLOC) { - ext->extent_data.type = EXTENT_TYPE_REGULAR; - changed = TRUE; - } + data->Reserved = FileObject->FileName.Length - parsed;
- le = le->Flink; - } + Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
- ExReleaseResourceLite(fileref->fcb->Header.Resource); + free_fileref(fileref);
- if (changed) { - fileref->fcb->extents_changed = TRUE; - mark_fcb_dirty(fileref->fcb); - } + goto exit; + } + } + + if (NT_SUCCESS(Status) && fileref->deleted) + Status = STATUS_OBJECT_NAME_NOT_FOUND;
- fileref->fcb->Header.Flags2 |= FSRTL_FLAG2_IS_PAGING_FILE; - Vcb->disallow_dismount = TRUE; + if (NT_SUCCESS(Status)) { + if (RequestedDisposition == FILE_CREATE) { + TRACE("file %S already exists, returning STATUS_OBJECT_NAME_COLLISION\n", file_desc_fileref(fileref)); + Status = STATUS_OBJECT_NAME_COLLISION; + + free_fileref(fileref); + + goto exit; } + } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { + if (RequestedDisposition == FILE_OPEN || RequestedDisposition == FILE_OVERWRITE) { + TRACE("file doesn't exist, returning STATUS_OBJECT_NAME_NOT_FOUND\n"); + goto exit; + } + } else if (Status == STATUS_OBJECT_PATH_NOT_FOUND) { + TRACE("open_fileref returned %08x\n", Status); + goto exit; + } else { + ERR("open_fileref returned %08x\n", Status); + goto exit; + }
-#ifdef DEBUG_FCB_REFCOUNTS - oc = InterlockedIncrement(&fileref->open_count); - ERR("fileref %p: open_count now %i\n", fileref, oc); -#else - InterlockedIncrement(&fileref->open_count); -#endif - InterlockedIncrement(&Vcb->open_files); + if (NT_SUCCESS(Status)) { // file already exists + Status = open_file2(Vcb, RequestedDisposition, pool_type, fileref, &granted_access, FileObject, &fn, options, Irp, rollback); + if (!NT_SUCCESS(Status)) + goto exit; } else { + file_ref* existing_file; + #ifdef DEBUG_STATS open_type = 2; #endif - Status = file_create(Irp, Vcb, FileObject, related, loaded_related, &fn, RequestedDisposition, options, rollback); - release_fcb_lock(Vcb); + Status = file_create(Irp, Vcb, FileObject, related, loaded_related, &fn, RequestedDisposition, options, &existing_file, rollback); + + if (Status == STATUS_OBJECT_NAME_COLLISION) { // already exists + fileref = existing_file;
- Irp->IoStatus.Information = NT_SUCCESS(Status) ? FILE_CREATED : 0; - granted_access = IrpSp->Parameters.Create.SecurityContext->DesiredAccess; + Status = open_file2(Vcb, RequestedDisposition, pool_type, fileref, &granted_access, FileObject, &fn, options, Irp, rollback); + if (!NT_SUCCESS(Status)) + goto exit; + } else { + Irp->IoStatus.Information = NT_SUCCESS(Status) ? FILE_CREATED : 0; + granted_access = IrpSp->Parameters.Create.SecurityContext->DesiredAccess; + } }
if (NT_SUCCESS(Status) && !(options & FILE_NO_INTERMEDIATE_BUFFERING)) FileObject->Flags |= FO_CACHE_SUPPORTED;
exit: - if (loaded_related) { - acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, related); - release_fcb_lock(Vcb); - } + if (loaded_related) + free_fileref(related);
if (Status == STATUS_SUCCESS) { fcb* fcb2; @@ -4128,6 +4625,8 @@ NTSTATUS NTAPI drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { if (!skip_lock) ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
+ ExAcquireResourceSharedLite(&Vcb->fileref_lock, TRUE); + Status = open_file(DeviceObject, Vcb, Irp, &rollback);
if (!NT_SUCCESS(Status)) @@ -4135,6 +4634,8 @@ NTSTATUS NTAPI drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { else clear_rollback(&rollback);
+ ExReleaseResourceLite(&Vcb->fileref_lock); + if (!skip_lock) ExReleaseResourceLite(&Vcb->tree_lock); } diff --git a/drivers/filesystems/btrfs/dirctrl.c b/drivers/filesystems/btrfs/dirctrl.c index 4d8df559d0..19b261b018 100644 --- a/drivers/filesystems/btrfs/dirctrl.c +++ b/drivers/filesystems/btrfs/dirctrl.c @@ -91,7 +91,7 @@ ULONG get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 t
ExReleaseResourceLite(fcb->Header.Resource);
- free_fcb(Vcb, fcb); + free_fcb(fcb);
return tag; } @@ -602,7 +602,6 @@ static NTSTATUS query_directory(PIRP Irp) { BOOL has_wildcard = FALSE, specific_file = FALSE, initial; dir_entry de; UINT64 newoffset; - ANSI_STRING utf8; dir_child* dc = NULL;
TRACE("query directory\n"); @@ -612,8 +611,6 @@ static NTSTATUS query_directory(PIRP Irp) { ccb = IrpSp->FileObject->FsContext2; fileref = ccb ? ccb->fileref : NULL;
- utf8.Buffer = NULL; - if (!fileref) return STATUS_INVALID_PARAMETER;
@@ -642,11 +639,6 @@ static NTSTATUS query_directory(PIRP Irp) { if (fileref->fcb == Vcb->dummy_fcb) 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) { TRACE("QD flags: (none)\n"); } else { @@ -708,8 +700,7 @@ static NTSTATUS query_directory(PIRP Irp) { ccb->query_string.Buffer = ExAllocatePoolWithTag(PagedPool, IrpSp->Parameters.QueryDirectory.FileName->Length, ALLOC_TAG); if (!ccb->query_string.Buffer) { ERR("out of memory\n"); - Status = STATUS_INSUFFICIENT_RESOURCES; - goto end2; + return STATUS_INSUFFICIENT_RESOURCES; }
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)) { initial = FALSE;
- if (specific_file) { - Status = STATUS_NO_MORE_FILES; - goto end2; - } + if (specific_file) + return STATUS_NO_MORE_FILES; } }
@@ -738,6 +727,8 @@ static NTSTATUS query_directory(PIRP Irp) {
newoffset = ccb->query_dir_offset;
+ ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE); + ExAcquireResourceSharedLite(&fileref->fcb->nonpaged->dir_children_lock, TRUE);
Status = next_dir_entry(fileref, &newoffset, &de, &dc); @@ -923,15 +914,10 @@ static NTSTATUS query_directory(PIRP Irp) { end: ExReleaseResourceLite(&fileref->fcb->nonpaged->dir_children_lock);
-end2: - release_fcb_lock(Vcb); ExReleaseResourceLite(&Vcb->tree_lock);
TRACE("returning %08x\n", Status);
- if (utf8.Buffer) - ExFreePool(utf8.Buffer); - return Status; }
diff --git a/drivers/filesystems/btrfs/fileinfo.c b/drivers/filesystems/btrfs/fileinfo.c index 1c342b0f55..2339c5deda 100644 --- a/drivers/filesystems/btrfs/fileinfo.c +++ b/drivers/filesystems/btrfs/fileinfo.c @@ -19,7 +19,7 @@
#if (NTDDI_VERSION >= NTDDI_WIN10) // not currently in mingw - introduced with Windows 10 -#ifndef FileIdInformation +#ifndef _MSC_VER #define FileIdInformation (enum _FILE_INFORMATION_CLASS)59 #define FileStatLxInformation (enum _FILE_INFORMATION_CLASS)70
@@ -230,8 +230,6 @@ static NTSTATUS set_disposition_information(device_extension* Vcb, PIRP Irp, PFI if (!fileref) return STATUS_INVALID_PARAMETER;
- acquire_fcb_lock_exclusive(Vcb); - 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); @@ -277,8 +275,6 @@ static NTSTATUS set_disposition_information(device_extension* Vcb, PIRP Irp, PFI end: ExReleaseResourceLite(fcb->Header.Resource);
- release_fcb_lock(Vcb); - // send notification that directory is about to be deleted if (NT_SUCCESS(Status) && fdi->DeleteFile && fcb->type == BTRFS_TYPE_DIRECTORY) { FsRtlNotifyFullChangeDirectory(Vcb->NotifySync, &Vcb->DirNotifyList, FileObject->FsContext, @@ -343,7 +339,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
if (!fcb->adsxattr.Buffer) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + free_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -357,7 +353,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
if (!fcb->adsdata.Buffer) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + free_fcb(fcb); 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); if (!fcb->sd) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + free_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -392,7 +388,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
if (!ext2) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + free_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -420,7 +416,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) { ext2->csum = ExAllocatePoolWithTag(PagedPool, len, ALLOC_TAG); if (!ext2->csum) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + free_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -442,7 +438,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
if (!hl2) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + free_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -455,7 +451,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) { if (!hl2->name.Buffer) { ERR("out of memory\n"); ExFreePool(hl2); - free_fcb(Vcb, fcb); + free_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -468,7 +464,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) { ERR("out of memory\n"); ExFreePool(hl2->name.Buffer); ExFreePool(hl2); - free_fcb(Vcb, fcb); + free_fcb(fcb); 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); if (!fcb->reparse_xattr.Buffer) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + free_fcb(fcb); 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); if (!fcb->ea_xattr.Buffer) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + free_fcb(fcb); return STATUS_INSUFFICIENT_RESOURCES; }
@@ -518,7 +514,7 @@ static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
if (!xa2) { ERR("out of memory\n"); - free_fcb(Vcb, fcb); + free_fcb(fcb); 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);
if (!NT_SUCCESS(Status)) { + reap_fcb(fcb); ERR("SeAssignSecurity returned %08x\n", Status); return Status; }
if (!fcb->sd) { + reap_fcb(fcb); ERR("SeAssignSecurity returned NULL security descriptor\n"); 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;
- InsertTailList(&r->fcbs, &fcb->list_entry); - InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all); - fcb->Header.IsFastIoPossible = fast_io_possible(fcb); fcb->Header.AllocationSize.QuadPart = 0; fcb->Header.FileSize.QuadPart = 0; fcb->Header.ValidDataLength.QuadPart = 0;
fcb->created = TRUE; - mark_fcb_dirty(fcb);
if (parfcb->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);
+ 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;
return STATUS_SUCCESS; @@ -735,11 +737,15 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb, file_ref* destd BTRFS_TIME now; file_ref* origparent;
+ // FIXME - make sure me->dummyfileref and me->dummyfcb get freed properly + InitializeListHead(&move_list);
KeQuerySystemTime(&time); win_time_to_unix(time, &now);
+ acquire_fcb_lock_exclusive(fileref->fcb->Vcb); + me = ExAllocatePoolWithTag(PagedPool, sizeof(move_entry), ALLOC_TAG);
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; 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); - ExReleaseResourceLite(&me->dummyfileref->parent->nonpaged->children_lock); + ExReleaseResourceLite(&me->dummyfileref->parent->fcb->nonpaged->dir_children_lock);
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); }
- free_fileref(fileref->fcb->Vcb, me->fileref->parent); + free_fileref(me->fileref->parent); 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); - 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); 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);
if (me->dummyfcb) - free_fcb(fileref->fcb->Vcb, me->dummyfcb); + free_fcb(me->dummyfcb);
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); }
+ destdir->fcb->subvol->fcbs_version++; + fileref->fcb->subvol->fcbs_version++; + + release_fcb_lock(fileref->fcb->Vcb); + return Status; }
@@ -1390,7 +1401,7 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB }
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE); - acquire_fcb_lock_exclusive(Vcb); + ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, TRUE); ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
if (fcb->ads) { @@ -1457,7 +1468,7 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB }
if (fileref == oldfileref || oldfileref->deleted) { - free_fileref(Vcb, oldfileref); + free_fileref(oldfileref); oldfileref = NULL; } } @@ -1726,10 +1737,10 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB fileref->created = TRUE; 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); 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(fileref); @@ -1794,9 +1805,9 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB 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); - ExReleaseResourceLite(&related->nonpaged->children_lock); + ExReleaseResourceLite(&related->fcb->nonpaged->dir_children_lock);
if (fcb->inode_item.st_nlink > 1) { // 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_mtime = now;
- free_fileref(Vcb, fr2); + free_fileref(fr2);
fr2->parent->fcb->inode_item_changed = TRUE; mark_fcb_dirty(fr2->parent->fcb); @@ -1913,13 +1924,13 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB
end: if (oldfileref) - free_fileref(Vcb, oldfileref); + free_fileref(oldfileref);
if (!NT_SUCCESS(Status) && related) - free_fileref(Vcb, related); + free_fileref(related);
if (!NT_SUCCESS(Status) && fr2) - free_fileref(Vcb, fr2); + free_fileref(fr2);
if (NT_SUCCESS(Status)) clear_rollback(&rollback); @@ -1927,7 +1938,7 @@ end: do_rollback(Vcb, &rollback);
ExReleaseResourceLite(fcb->Header.Resource); - release_fcb_lock(Vcb); + ExReleaseResourceLite(&Vcb->fileref_lock); ExReleaseResourceLite(&Vcb->tree_lock);
return Status; @@ -2227,7 +2238,7 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJE }
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE); - acquire_fcb_lock_exclusive(Vcb); + ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, TRUE); ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
if (fcb->type == BTRFS_TYPE_DIRECTORY) { @@ -2299,7 +2310,7 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJE goto end; } } else { - free_fileref(Vcb, oldfileref); + free_fileref(oldfileref); oldfileref = NULL; } } @@ -2364,9 +2375,9 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJE fr2->dc = dc; dc->fileref = fr2;
- ExAcquireResourceExclusiveLite(&related->nonpaged->children_lock, TRUE); + ExAcquireResourceExclusiveLite(&related->fcb->nonpaged->dir_children_lock, TRUE); 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 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);
mark_fileref_dirty(fr2); - free_fileref(Vcb, fr2); + free_fileref(fr2);
// update inode's INODE_ITEM
@@ -2482,13 +2493,13 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJE
end: if (oldfileref) - free_fileref(Vcb, oldfileref); + free_fileref(oldfileref);
if (!NT_SUCCESS(Status) && related) - free_fileref(Vcb, related); + free_fileref(related);
if (!NT_SUCCESS(Status) && fr2) - free_fileref(Vcb, fr2); + free_fileref(fr2);
if (NT_SUCCESS(Status)) clear_rollback(&rollback); @@ -2496,7 +2507,7 @@ end: do_rollback(Vcb, &rollback);
ExReleaseResourceLite(fcb->Header.Resource); - release_fcb_lock(Vcb); + ExReleaseResourceLite(&Vcb->fileref_lock); ExReleaseResourceLite(&Vcb->tree_lock);
return Status; @@ -3186,282 +3197,7 @@ static NTSTATUS fill_in_file_standard_link_information(FILE_STANDARD_LINK_INFORM
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) { NTSTATUS Status; LIST_ENTRY* le; @@ -3517,7 +3253,7 @@ static NTSTATUS fill_in_hard_link_information(FILE_LINKS_INFORMATION* fli, file_ len = bytes_needed; } } else { - acquire_fcb_lock_exclusive(fcb->Vcb); + ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, TRUE);
if (IsListEmpty(&fcb->hardlinks)) { 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; } }
- release_fcb_lock(fcb->Vcb); + ExReleaseResourceLite(&fcb->Vcb->fileref_lock); }
fli->BytesNeeded = bytes_needed; diff --git a/drivers/filesystems/btrfs/flushthread.c b/drivers/filesystems/btrfs/flushthread.c index 6353abb583..6784de5277 100644 --- a/drivers/filesystems/btrfs/flushthread.c +++ b/drivers/filesystems/btrfs/flushthread.c @@ -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; }
@@ -2810,6 +2814,18 @@ static NTSTATUS split_tree_at(device_extension* Vcb, tree* t, tree_data* newfirs 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)); nt->header.address = 0; 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; }
+ 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)); pt->header.address = 0; 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; NTSTATUS Status; tree *next_tree, *par; - BOOL loaded;
*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);
- Status = do_load_tree(Vcb, &nextparitem->treeholder, t->root, t->parent, nextparitem, &loaded, NULL); - if (!NT_SUCCESS(Status)) { - ERR("do_load_tree returned %08x\n", Status); - return Status; + if (!nextparitem->treeholder.tree) { + Status = do_load_tree(Vcb, &nextparitem->treeholder, t->root, t->parent, nextparitem, NULL); + if (!NT_SUCCESS(Status)) { + ERR("do_load_tree returned %08x\n", Status); + return Status; + } }
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;
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)) { 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->oldused = c->used;
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);
- free_fcb(Vcb, c->cache); + free_fcb(c->cache); + + if (c->cache->refcount == 0) + reap_fcb(c->cache);
if (!NT_SUCCESS(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);
flush_fileref(fr, &batchlist, Irp); - free_fileref(Vcb, fr); + free_fileref(fr);
#ifdef DEBUG_FLUSH_TIMES filerefs++; @@ -6961,7 +7011,7 @@ static NTSTATUS do_write2(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback) Status = flush_fcb(fcb, FALSE, &batchlist, Irp); ExReleaseResourceLite(fcb->Header.Resource);
- free_fcb(Vcb, fcb); + free_fcb(fcb);
if (!NT_SUCCESS(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); Status = flush_fcb(fcb, FALSE, &batchlist, Irp); ExReleaseResourceLite(fcb->Header.Resource); - free_fcb(Vcb, fcb); + free_fcb(fcb);
if (!NT_SUCCESS(Status)) { ERR("flush_fcb returned %08x\n", Status); diff --git a/drivers/filesystems/btrfs/free-space.c b/drivers/filesystems/btrfs/free-space.c index f6248e9038..cd3de367f4 100644 --- a/drivers/filesystems/btrfs/free-space.c +++ b/drivers/filesystems/btrfs/free-space.c @@ -46,11 +46,11 @@ static NTSTATUS remove_free_space_inode(device_extension* Vcb, UINT64 inode, LIS Status = flush_fcb(fcb, FALSE, batchlist, Irp); if (!NT_SUCCESS(Status)) { ERR("flush_fcb returned %08x\n", Status); - free_fcb(Vcb, fcb); + free_fcb(fcb); return Status; }
- free_fcb(Vcb, fcb); + free_fcb(fcb);
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);
if (c->offset == tp.item->key.offset && c->cache) { - free_fcb(Vcb, c->cache); + reap_fcb(c->cache); 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) { WARN("cache had zero length\n"); - free_fcb(Vcb, c->cache); + free_fcb(c->cache); c->cache = NULL; return STATUS_NOT_FOUND; } @@ -524,11 +524,16 @@ NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, BOOL load
if (!data) { ERR("out of memory\n"); - free_fcb(Vcb, c->cache); + free_fcb(c->cache); c->cache = NULL; 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); if (!NT_SUCCESS(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; mark_fcb_dirty(c->cache);
- free_fcb(Vcb, c->cache); + free_fcb(c->cache); c->cache = NULL; 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); if (!fsi) { ERR("out of memory\n"); - free_fcb(Vcb, c->cache); + reap_fcb(c->cache); c->cache = NULL; return STATUS_INSUFFICIENT_RESOURCES; } @@ -1139,7 +1144,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan if (!NT_SUCCESS(Status)) { ERR("error - find_item returned %08x\n", Status); ExFreePool(fsi); - free_fcb(Vcb, c->cache); + reap_fcb(c->cache); c->cache = NULL; return Status; } @@ -1149,7 +1154,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan if (!NT_SUCCESS(Status)) { ERR("delete_tree_item returned %08x\n", Status); ExFreePool(fsi); - free_fcb(Vcb, c->cache); + reap_fcb(c->cache); c->cache = NULL; return Status; } @@ -1163,7 +1168,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan if (!NT_SUCCESS(Status)) { ERR("insert_tree_item returned %08x\n", Status); ExFreePool(fsi); - free_fcb(Vcb, c->cache); + reap_fcb(c->cache); c->cache = NULL; 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); if (!NT_SUCCESS(Status)) { ERR("insert_cache_extent returned %08x\n", Status); - free_fcb(Vcb, c->cache); + reap_fcb(c->cache); c->cache = NULL; 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); if (!NT_SUCCESS(Status)) { ERR("flush_fcb returned %08x\n", Status); - free_fcb(Vcb, c->cache); + free_fcb(c->cache); c->cache = NULL; return Status; } @@ -1357,7 +1362,7 @@ NTSTATUS allocate_cache(device_extension* Vcb, BOOL* changed, PIRP Irp, LIST_ENT while (le != &Vcb->chunks) { chunk* c = CONTAINING_RECORD(le, chunk, list_entry);
- if (c->space_changed) { + if (c->space_changed && c->chunk_item->size >= 0x6400000) { // 100MB BOOL b;
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) { 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); Status = update_chunk_cache(Vcb, c, &now, &batchlist, Irp, rollback); release_chunk_lock(c, Vcb); diff --git a/drivers/filesystems/btrfs/fsctl.c b/drivers/filesystems/btrfs/fsctl.c index 3b13e89766..3845965ca1 100644 --- a/drivers/filesystems/btrfs/fsctl.c +++ b/drivers/filesystems/btrfs/fsctl.c @@ -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); if (!NT_SUCCESS(Status)) { ERR("open_fcb returned %08x\n", Status); - free_fileref(Vcb, fr); + free_fileref(fr); goto end; }
@@ -448,9 +448,9 @@ static NTSTATUS do_create_snapshot(device_extension* Vcb, PFILE_OBJECT parent, f fr->dc = dc; dc->fileref = fr;
- ExAcquireResourceExclusiveLite(&fileref->nonpaged->children_lock, TRUE); + ExAcquireResourceExclusiveLite(&fileref->fcb->nonpaged->dir_children_lock, TRUE); InsertTailList(&fileref->children, &fr->list_entry); - ExReleaseResourceLite(&fileref->nonpaged->children_lock); + ExReleaseResourceLite(&fileref->fcb->nonpaged->dir_children_lock);
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;
- free_fileref(Vcb, fr); + free_fileref(fr);
// change fcb's INODE_ITEM
@@ -641,11 +641,11 @@ static NTSTATUS create_snapshot(device_extension* Vcb, PFILE_OBJECT FileObject, if (NT_SUCCESS(Status)) { if (!fr2->deleted) { WARN("file already exists\n"); - free_fileref(Vcb, fr2); + free_fileref(fr2); Status = STATUS_OBJECT_NAME_COLLISION; goto end3; } else - free_fileref(Vcb, fr2); + free_fileref(fr2); } else if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND) { ERR("open_fileref returned %08x\n", Status); goto end3; @@ -726,7 +726,7 @@ static NTSTATUS create_snapshot(device_extension* Vcb, PFILE_OBJECT FileObject, Status = STATUS_SUCCESS; } else { 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 (!fr2->deleted) { WARN("file already exists\n"); - free_fileref(Vcb, fr2); + free_fileref(fr2); Status = STATUS_OBJECT_NAME_COLLISION; goto end; } else - free_fileref(Vcb, fr2); + free_fileref(fr2); } else if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND) { ERR("open_fileref returned %08x\n", Status); goto end; @@ -1005,6 +1005,7 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT FileObject, vo acquire_fcb_lock_exclusive(Vcb); InsertTailList(&r->fcbs, &rootfcb->list_entry); InsertTailList(&Vcb->all_fcbs, &rootfcb->list_entry_all); + r->fcbs_version++; release_fcb_lock(Vcb);
rootfcb->Header.IsFastIoPossible = fast_io_possible(rootfcb); @@ -1049,9 +1050,7 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT FileObject, vo if (!fr) { ERR("out of memory\n");
- acquire_fcb_lock_exclusive(Vcb); - free_fcb(Vcb, rootfcb); - release_fcb_lock(Vcb); + reap_fcb(rootfcb);
Status = STATUS_INSUFFICIENT_RESOURCES; 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); if (!fr->fcb->hash_ptrs) { ERR("out of memory\n"); - acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fr); - release_fcb_lock(Vcb); + free_fileref(fr); Status = STATUS_INSUFFICIENT_RESOURCES; 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); if (!fr->fcb->hash_ptrs_uc) { ERR("out of memory\n"); - acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fr); - release_fcb_lock(Vcb); + free_fileref(fr); Status = STATUS_INSUFFICIENT_RESOURCES; goto end; }
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); - ExReleaseResourceLite(&fileref->nonpaged->children_lock); + ExReleaseResourceLite(&fileref->fcb->nonpaged->dir_children_lock);
increase_fileref_refcount(fileref);
@@ -1154,11 +1149,8 @@ end: }
end2: - if (fr) { - acquire_fcb_lock_exclusive(Vcb); - free_fileref(Vcb, fr); - release_fcb_lock(Vcb); - } + if (fr) + free_fileref(fr);
return Status; } @@ -2233,15 +2225,15 @@ static NTSTATUS lock_volume(device_extension* Vcb, PIRP Irp) { if (Vcb->locked) 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))) { Status = STATUS_ACCESS_DENIED; - release_fcb_lock(Vcb); + ExReleaseResourceLite(&Vcb->fileref_lock); goto end; }
- release_fcb_lock(Vcb); + ExReleaseResourceLite(&Vcb->fileref_lock);
if (Vcb->balance.thread && KeReadStateEvent(&Vcb->balance.event)) { 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.Buffer = bmn->name;
- acquire_fcb_lock_exclusive(Vcb); - Status = find_file_in_dir(&name, parfcb, &subvol, &inode, &dc, TRUE); if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND) { 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; }
- 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); win_time_to_unix(time, &now);
@@ -3897,8 +3857,6 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
InterlockedIncrement(&parfcb->refcount); fcb->subvol = parfcb->subvol; - fcb->inode = inode; - fcb->type = bmn->type;
SeCaptureSubjectContext(&subjcont);
@@ -3907,7 +3865,7 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
if (!NT_SUCCESS(Status)) { ERR("SeAssignSecurityEx returned %08x\n", Status); - free_fcb(Vcb, fcb); + reap_fcb(fcb); goto end; }
@@ -3922,10 +3880,52 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
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); if (!fileref) { + release_fcb_lock(Vcb); + ExReleaseResourceLite(&Vcb->fileref_lock); + ERR("out of memory\n"); - free_fcb(Vcb, fcb); + reap_fcb(fcb); Status = STATUS_INSUFFICIENT_RESOURCES; goto end; } @@ -3933,16 +3933,16 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data fileref->fcb = fcb;
fcb->created = TRUE; - mark_fcb_dirty(fcb); - fileref->created = TRUE; - mark_fileref_dirty(fileref);
fcb->subvol->root_item.ctransid = Vcb->superblock.generation; fcb->subvol->root_item.ctime = now;
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); if (!NT_SUCCESS(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; dc->fileref = fileref;
- ExAcquireResourceExclusiveLite(&parfileref->nonpaged->children_lock, TRUE); + ExAcquireResourceExclusiveLite(&parfileref->fcb->nonpaged->dir_children_lock, TRUE); InsertTailList(&parfileref->children, &fileref->list_entry); - ExReleaseResourceLite(&parfileref->nonpaged->children_lock); + ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock);
increase_fileref_refcount(parfileref);
if (fcb->type == BTRFS_TYPE_DIRECTORY) { fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG); if (!fcb->hash_ptrs) { + release_fcb_lock(Vcb); + ExReleaseResourceLite(&Vcb->fileref_lock); + ERR("out of memory\n"); - free_fileref(Vcb, fileref); + free_fileref(fileref); Status = STATUS_INSUFFICIENT_RESOURCES; 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); if (!fcb->hash_ptrs_uc) { + release_fcb_lock(Vcb); + ExReleaseResourceLite(&Vcb->fileref_lock); + ERR("out of memory\n"); - free_fileref(Vcb, fileref); + free_fileref(fileref); Status = STATUS_INSUFFICIENT_RESOURCES; goto end; } @@ -3995,7 +4001,11 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data if (!parccb->user_set_write_time) parfcb->inode_item.st_mtime = now;
+ parfcb->subvol->fcbs_version++; + ExReleaseResourceLite(parfcb->Header.Resource); + release_fcb_lock(Vcb); + ExReleaseResourceLite(&Vcb->fileref_lock);
parfcb->inode_item_changed = TRUE; mark_fcb_dirty(parfcb); @@ -4008,7 +4018,6 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data Status = STATUS_SUCCESS;
end: - release_fcb_lock(Vcb);
ExFreePool(utf8.Buffer);
@@ -4458,11 +4467,11 @@ static NTSTATUS get_subvol_path(device_extension* Vcb, UINT64 id, WCHAR* out, UL 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); if (!NT_SUCCESS(Status)) { - release_fcb_lock(Vcb); + ExReleaseResourceLite(&Vcb->fileref_lock); ERR("open_fileref_by_inode returned %08x\n", Status); return Status; } @@ -4478,9 +4487,9 @@ static NTSTATUS get_subvol_path(device_extension* Vcb, UINT64 id, WCHAR* out, UL ... 590 lines suppressed ...