summaryrefslogtreecommitdiff
path: root/Kernel/FileSystem
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-05-31 15:22:52 +0200
committerAndreas Kling <awesomekling@gmail.com>2019-05-31 15:22:52 +0200
commit8adadf8a462e87a588ca5d987c72ac2b635b36c4 (patch)
tree010eac1dd46a925edb01bce7197b392575bebd8d /Kernel/FileSystem
parent3fbddcecd2e438eefdd894f6c7574961531e49d6 (diff)
downloadserenity-8adadf8a462e87a588ca5d987c72ac2b635b36c4.zip
FileSystem: Reuse existing custodies when possible, and keep them updated.
Walk the custody cache and try to reuse an existing one when possible. The VFS is responsible for updating them when something happens that would cause the described relationship to change. This is definitely not perfect but it does work for the basic scenarios like renaming and removing directory entries.
Diffstat (limited to 'Kernel/FileSystem')
-rw-r--r--Kernel/FileSystem/Custody.cpp45
-rw-r--r--Kernel/FileSystem/Custody.h18
-rw-r--r--Kernel/FileSystem/InodeIdentifier.h3
-rw-r--r--Kernel/FileSystem/VirtualFileSystem.cpp19
4 files changed, 78 insertions, 7 deletions
diff --git a/Kernel/FileSystem/Custody.cpp b/Kernel/FileSystem/Custody.cpp
index 70bcd8e315..f70d1a2719 100644
--- a/Kernel/FileSystem/Custody.cpp
+++ b/Kernel/FileSystem/Custody.cpp
@@ -12,6 +12,35 @@ static Lockable<HashTable<Custody*>>& all_custodies()
return *table;
}
+Custody* Custody::get_if_cached(Custody* parent, const String& name)
+{
+ LOCKER(all_custodies().lock());
+ for (auto& custody : all_custodies().resource()) {
+ if (custody->is_deleted())
+ continue;
+ if (custody->is_mounted_on())
+ continue;
+ if (custody->parent() == parent && custody->name() == name)
+ return custody;
+ }
+ return nullptr;
+}
+
+Retained<Custody> Custody::get_or_create(Custody* parent, const String& name, Inode& inode)
+{
+ if (RetainPtr<Custody> cached_custody = get_if_cached(parent, name)) {
+ if (&cached_custody->inode() != &inode) {
+ dbgprintf("WTF! cached custody for name '%s' has inode=%s, new inode=%s\n",
+ name.characters(),
+ cached_custody->inode().identifier().to_string().characters(),
+ inode.identifier().to_string().characters());
+ }
+ ASSERT(&cached_custody->inode() == &inode);
+ return *cached_custody;
+ }
+ return create(parent, name, inode);
+}
+
Custody::Custody(Custody* parent, const String& name, Inode& inode)
: m_parent(parent)
, m_name(name)
@@ -39,3 +68,19 @@ String Custody::absolute_path() const
}
return builder.to_string();
}
+
+void Custody::did_delete(Badge<VFS>)
+{
+ m_deleted = true;
+}
+
+void Custody::did_mount_on(Badge<VFS>)
+{
+ m_mounted_on = true;
+}
+
+void Custody::did_rename(Badge<VFS>, const String& name)
+{
+ m_name = name;
+}
+
diff --git a/Kernel/FileSystem/Custody.h b/Kernel/FileSystem/Custody.h
index a468e4cf98..9de3d93dd8 100644
--- a/Kernel/FileSystem/Custody.h
+++ b/Kernel/FileSystem/Custody.h
@@ -1,13 +1,19 @@
#pragma once
#include <AK/AKString.h>
+#include <AK/Badge.h>
#include <AK/RetainPtr.h>
#include <AK/Retainable.h>
class Inode;
+class VFS;
+
+// FIXME: Custody needs some locking.
class Custody : public Retainable<Custody> {
public:
+ static Custody* get_if_cached(Custody* parent, const String& name);
+ static Retained<Custody> get_or_create(Custody* parent, const String& name, Inode&);
static Retained<Custody> create(Custody* parent, const String& name, Inode& inode)
{
return adopt(*new Custody(parent, name, inode));
@@ -17,18 +23,24 @@ public:
Custody* parent() { return m_parent.ptr(); }
const Custody* parent() const { return m_parent.ptr(); }
-
Inode& inode() { return *m_inode; }
const Inode& inode() const { return *m_inode; }
-
const String& name() const { return m_name; }
-
String absolute_path() const;
+ bool is_deleted() const { return m_deleted; }
+ bool is_mounted_on() const { return m_mounted_on; }
+
+ void did_delete(Badge<VFS>);
+ void did_mount_on(Badge<VFS>);
+ void did_rename(Badge<VFS>, const String& name);
+
private:
Custody(Custody* parent, const String& name, Inode&);
RetainPtr<Custody> m_parent;
String m_name;
Retained<Inode> m_inode;
+ bool m_deleted { false };
+ bool m_mounted_on { false };
};
diff --git a/Kernel/FileSystem/InodeIdentifier.h b/Kernel/FileSystem/InodeIdentifier.h
index 95c1bc6226..d6d4c4e881 100644
--- a/Kernel/FileSystem/InodeIdentifier.h
+++ b/Kernel/FileSystem/InodeIdentifier.h
@@ -1,5 +1,6 @@
#pragma once
+#include <AK/AKString.h>
#include <AK/ByteBuffer.h>
#include <AK/Types.h>
@@ -35,6 +36,8 @@ public:
bool is_root_inode() const;
+ String to_string() const { return String::format("%u:%u", m_fsid, m_index); }
+
private:
dword m_fsid { 0 };
dword m_index { 0 };
diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp
index e5f6ad5116..c977c03932 100644
--- a/Kernel/FileSystem/VirtualFileSystem.cpp
+++ b/Kernel/FileSystem/VirtualFileSystem.cpp
@@ -48,6 +48,8 @@ bool VFS::mount(Retained<FS>&& file_system, StringView path)
// FIXME: check that this is not already a mount point
auto mount = make<Mount>(*result.value(), move(file_system));
m_mounts.append(move(mount));
+
+ result.value()->did_mount_on({});
return true;
}
@@ -368,6 +370,8 @@ KResult VFS::rename(StringView old_path, StringView new_path, Custody& base)
return KResult(-EACCES);
}
+ auto new_basename = FileSystemPath(new_path).basename();
+
if (!new_custody_or_error.is_error()) {
auto& new_custody = *new_custody_or_error.value();
auto& new_inode = new_custody.inode();
@@ -380,18 +384,20 @@ KResult VFS::rename(StringView old_path, StringView new_path, Custody& base)
}
if (new_inode.is_directory() && !old_inode.is_directory())
return KResult(-EISDIR);
- auto result = new_parent_inode.remove_child(FileSystemPath(new_path).basename());
+ auto result = new_parent_inode.remove_child(new_basename);
if (result.is_error())
return result;
+ new_custody.did_delete({});
}
- auto result = new_parent_inode.add_child(old_inode.identifier(), FileSystemPath(new_path).basename(), 0 /* FIXME: file type? */);
+ auto result = new_parent_inode.add_child(old_inode.identifier(), new_basename, 0 /* FIXME: file type? */);
if (result.is_error())
return result;
result = old_parent_inode.remove_child(FileSystemPath(old_path).basename());
if (result.is_error())
return result;
+ old_custody.did_rename({}, new_basename);
return KSuccess;
}
@@ -479,7 +485,12 @@ KResult VFS::unlink(StringView path, Custody& base)
return KResult(-EACCES);
}
- return parent_inode.remove_child(FileSystemPath(path).basename());
+ auto result = parent_inode.remove_child(FileSystemPath(path).basename());
+ if (result.is_error())
+ return result;
+
+ custody.did_delete({});
+ return KSuccess;
}
KResult VFS::symlink(StringView target, StringView linkpath, Custody& base)
@@ -662,7 +673,7 @@ KResultOr<Retained<Custody>> VFS::resolve_path_to_custody(StringView path, Custo
crumb_inode = get_inode(crumb_id);
ASSERT(crumb_inode);
- custody_chain.append(Custody::create(custody_chain.last().ptr(), part, *crumb_inode));
+ custody_chain.append(Custody::get_or_create(custody_chain.last().ptr(), part, *crumb_inode));
metadata = crumb_inode->metadata();
if (metadata.is_directory()) {