1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 23:17:45 +00:00

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.
This commit is contained in:
Andreas Kling 2019-05-31 15:22:52 +02:00
parent 3fbddcecd2
commit 8adadf8a46
4 changed files with 78 additions and 7 deletions

View file

@ -12,6 +12,35 @@ static Lockable<HashTable<Custody*>>& all_custodies()
return *table; 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) Custody::Custody(Custody* parent, const String& name, Inode& inode)
: m_parent(parent) : m_parent(parent)
, m_name(name) , m_name(name)
@ -39,3 +68,19 @@ String Custody::absolute_path() const
} }
return builder.to_string(); 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;
}

View file

@ -1,13 +1,19 @@
#pragma once #pragma once
#include <AK/AKString.h> #include <AK/AKString.h>
#include <AK/Badge.h>
#include <AK/RetainPtr.h> #include <AK/RetainPtr.h>
#include <AK/Retainable.h> #include <AK/Retainable.h>
class Inode; class Inode;
class VFS;
// FIXME: Custody needs some locking.
class Custody : public Retainable<Custody> { class Custody : public Retainable<Custody> {
public: 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) static Retained<Custody> create(Custody* parent, const String& name, Inode& inode)
{ {
return adopt(*new Custody(parent, name, inode)); return adopt(*new Custody(parent, name, inode));
@ -17,18 +23,24 @@ public:
Custody* parent() { return m_parent.ptr(); } Custody* parent() { return m_parent.ptr(); }
const Custody* parent() const { return m_parent.ptr(); } const Custody* parent() const { return m_parent.ptr(); }
Inode& inode() { return *m_inode; } Inode& inode() { return *m_inode; }
const Inode& inode() const { return *m_inode; } const Inode& inode() const { return *m_inode; }
const String& name() const { return m_name; } const String& name() const { return m_name; }
String absolute_path() const; 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: private:
Custody(Custody* parent, const String& name, Inode&); Custody(Custody* parent, const String& name, Inode&);
RetainPtr<Custody> m_parent; RetainPtr<Custody> m_parent;
String m_name; String m_name;
Retained<Inode> m_inode; Retained<Inode> m_inode;
bool m_deleted { false };
bool m_mounted_on { false };
}; };

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <AK/AKString.h>
#include <AK/ByteBuffer.h> #include <AK/ByteBuffer.h>
#include <AK/Types.h> #include <AK/Types.h>
@ -35,6 +36,8 @@ public:
bool is_root_inode() const; bool is_root_inode() const;
String to_string() const { return String::format("%u:%u", m_fsid, m_index); }
private: private:
dword m_fsid { 0 }; dword m_fsid { 0 };
dword m_index { 0 }; dword m_index { 0 };

View file

@ -48,6 +48,8 @@ bool VFS::mount(Retained<FS>&& file_system, StringView path)
// FIXME: check that this is not already a mount point // FIXME: check that this is not already a mount point
auto mount = make<Mount>(*result.value(), move(file_system)); auto mount = make<Mount>(*result.value(), move(file_system));
m_mounts.append(move(mount)); m_mounts.append(move(mount));
result.value()->did_mount_on({});
return true; return true;
} }
@ -368,6 +370,8 @@ KResult VFS::rename(StringView old_path, StringView new_path, Custody& base)
return KResult(-EACCES); return KResult(-EACCES);
} }
auto new_basename = FileSystemPath(new_path).basename();
if (!new_custody_or_error.is_error()) { if (!new_custody_or_error.is_error()) {
auto& new_custody = *new_custody_or_error.value(); auto& new_custody = *new_custody_or_error.value();
auto& new_inode = new_custody.inode(); 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()) if (new_inode.is_directory() && !old_inode.is_directory())
return KResult(-EISDIR); 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()) if (result.is_error())
return result; 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()) if (result.is_error())
return result; return result;
result = old_parent_inode.remove_child(FileSystemPath(old_path).basename()); result = old_parent_inode.remove_child(FileSystemPath(old_path).basename());
if (result.is_error()) if (result.is_error())
return result; return result;
old_custody.did_rename({}, new_basename);
return KSuccess; return KSuccess;
} }
@ -479,7 +485,12 @@ KResult VFS::unlink(StringView path, Custody& base)
return KResult(-EACCES); 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) 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); crumb_inode = get_inode(crumb_id);
ASSERT(crumb_inode); 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(); metadata = crumb_inode->metadata();
if (metadata.is_directory()) { if (metadata.is_directory()) {