https://git.reactos.org/?p=reactos.git;a=commitdiff;h=883b1f31ac8b4b30e2114…
commit 883b1f31ac8b4b30e21144053b9ada0383ad17d3
Author: Pierre Schweitzer <pierre(a)reactos.org>
AuthorDate: Sat May 11 11:20:02 2019 +0200
Commit: Pierre Schweitzer <pierre(a)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 ...