Browse Source

feat: use RAII to manage dentry pointers

add std::unique_ptr
greatbridf 8 months ago
parent
commit
e6c6d8f1b7

+ 1 - 0
gblibstdc++/CMakeLists.txt

@@ -15,6 +15,7 @@ set(GBSTDLIBCPP_PUBLIC_HEADERS
     gblibstdc++/include/cstddef
     gblibstdc++/include/map
     gblibstdc++/include/bits
+    gblibstdc++/include/bits/compressed_pair
     gblibstdc++/include/bits/fwd_functional
     gblibstdc++/include/bits/rbtree
     gblibstdc++/include/bits/iter_ops

+ 70 - 0
gblibstdc++/include/bits/compressed_pair

@@ -0,0 +1,70 @@
+#ifndef __GBLIBCPP_BITS_COMPRESSED_PAIR__
+#define __GBLIBCPP_BITS_COMPRESSED_PAIR__
+
+#include <utility>
+
+namespace std::impl {
+
+struct default_construct_t { };
+
+template <typename T, int, bool is_empty = __is_empty(T)>
+struct compressed_pair_element
+{
+    constexpr compressed_pair_element() = default;
+    constexpr compressed_pair_element(const compressed_pair_element&) = default;
+    constexpr compressed_pair_element(compressed_pair_element&&) = default;
+    constexpr compressed_pair_element& operator=(const compressed_pair_element&) = default;
+    constexpr compressed_pair_element& operator=(compressed_pair_element&&) = default;
+
+    constexpr compressed_pair_element(default_construct_t): value{} { }
+    constexpr compressed_pair_element(const T& x): value{x} { }
+    constexpr compressed_pair_element(T&& x): value{std::move(x)} { }
+
+    constexpr T& get() noexcept { return value; }
+    constexpr const T& get() const noexcept { return value; }
+
+    T value;
+};
+
+template <typename T, int N>
+struct compressed_pair_element<T, N, true> : private T
+{
+    constexpr compressed_pair_element() = default;
+    constexpr compressed_pair_element(const compressed_pair_element&) = default;
+    constexpr compressed_pair_element(compressed_pair_element&&) = default;
+    constexpr compressed_pair_element& operator=(const compressed_pair_element&) = default;
+    constexpr compressed_pair_element& operator=(compressed_pair_element&&) = default;
+
+    constexpr compressed_pair_element(default_construct_t): T{} { }
+    constexpr compressed_pair_element(const T& x): T{x} { }
+    constexpr compressed_pair_element(T&& x): T{std::move(x)} { }
+
+    constexpr T& get() noexcept { return *this; }
+    constexpr const T& get() const noexcept { return *this; }
+};
+
+template <typename T1, typename T2>
+struct compressed_pair
+    : private compressed_pair_element<T1, 0>, private compressed_pair_element<T2, 1> {
+    using Base1 = compressed_pair_element<T1, 0>;
+    using Base2 = compressed_pair_element<T2, 1>;
+
+    constexpr compressed_pair() = default;
+    constexpr compressed_pair(const compressed_pair&) = default;
+    constexpr compressed_pair(compressed_pair&&) = default;
+    constexpr compressed_pair& operator=(const compressed_pair&) = default;
+    constexpr compressed_pair& operator=(compressed_pair&&) = default;
+
+    constexpr compressed_pair(default_construct_t): Base1{default_construct_t{}}, Base2{default_construct_t{}} { }
+    constexpr compressed_pair(const T1& x, const T2& y): Base1{x}, Base2{y} { }
+    constexpr compressed_pair(T1&& x, T2&& y): Base1{std::move(x)}, Base2{std::move(y)} { }
+
+    constexpr T1& first() noexcept { return Base1::get(); }
+    constexpr const T1& first() const noexcept { return Base1::get(); }
+    constexpr T2& second() noexcept { return Base2::get(); }
+    constexpr const T2& second() const noexcept { return Base2::get(); }
+};
+
+} // namespace std::impl
+
+#endif

+ 119 - 3
gblibstdc++/include/memory

@@ -1,10 +1,11 @@
 #ifndef __GBLIBCPP_MEMORY__
 #define __GBLIBCPP_MEMORY__
 
+#include <bits/compressed_pair>
 #include <cstddef>
+#include <new>
 #include <type_traits>
 #include <utility>
-#include <new>
 
 namespace std {
 
@@ -459,8 +460,8 @@ private:
     friend class shared_ptr;
 
 public:
-    constexpr shared_ptr() noexcept = default;
-    constexpr shared_ptr(std::nullptr_t) noexcept { }
+    __GBLIBCPP_CONSTEXPR shared_ptr() noexcept = default;
+    __GBLIBCPP_CONSTEXPR shared_ptr(std::nullptr_t) noexcept { }
 
     template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
     __GBLIBCPP_CONSTEXPR explicit shared_ptr(U* p) // TODO: array type
@@ -636,6 +637,103 @@ public:
     }
 };
 
+template <typename T>
+struct default_delete {
+    __GBLIBCPP_CONSTEXPR default_delete() noexcept = default;
+
+    template <typename U, std::enable_if_t<std::is_convertible_v<U*, T*>, bool> = true>
+    __GBLIBCPP_CONSTEXPR default_delete(const default_delete<U>&) noexcept {}
+
+    __GBLIBCPP_CONSTEXPR void operator()(T* p) const
+    {
+        delete p;
+    }
+};
+
+template <typename T, typename Deleter = std::default_delete<T>>
+class unique_ptr {
+public:
+    using element_type = T;
+    using deleter_type = Deleter;
+    using pointer = element_type*;
+
+private:
+    impl::compressed_pair<pointer, deleter_type> data;
+
+public:
+    __GBLIBCPP_CONSTEXPR unique_ptr() noexcept: data{impl::default_construct_t{}} { }
+    __GBLIBCPP_CONSTEXPR unique_ptr(std::nullptr_t) noexcept: unique_ptr{} { }
+    __GBLIBCPP_CONSTEXPR unique_ptr(pointer p) noexcept: data{p, deleter_type{}} { }
+    __GBLIBCPP_CONSTEXPR unique_ptr(pointer p, const deleter_type& d) noexcept: data{p, d} { }
+    __GBLIBCPP_CONSTEXPR unique_ptr(pointer p, deleter_type&& d) noexcept: data{p, std::move(d)} { }
+    __GBLIBCPP_CONSTEXPR unique_ptr(const unique_ptr&) = delete;
+
+    __GBLIBCPP_CONSTEXPR unique_ptr(unique_ptr&& other) noexcept
+        : data{std::exchange(other.data.first(), nullptr), std::move(other.data.second())} { }
+
+    template <typename U, typename E, std::enable_if_t<
+        !std::is_array_v<U> && std::is_convertible_v<U*, T*>
+            && std::is_convertible_v<E, Deleter>, bool> = true>
+    __GBLIBCPP_CONSTEXPR unique_ptr(unique_ptr<U, E>&& other) noexcept
+        : data{std::exchange(other.data.first(), nullptr), std::move(other.data.second())} { }
+
+    __GBLIBCPP_CONSTEXPR ~unique_ptr() { reset(); }
+
+    __GBLIBCPP_CONSTEXPR unique_ptr& operator=(const unique_ptr&) = delete;
+    __GBLIBCPP_CONSTEXPR unique_ptr& operator=(std::nullptr_t) noexcept
+    {
+        reset();
+        return *this;
+    }
+
+    __GBLIBCPP_CONSTEXPR unique_ptr& operator=(unique_ptr&& other) noexcept
+    {
+        reset(other.release());
+        get_deleter() = std::move(other.get_deleter());
+        return *this;
+    }
+
+    template <typename U, typename E, std::enable_if_t<
+        !std::is_array_v<U> && std::is_convertible_v<U*, T*>
+            && std::is_assignable_v<Deleter&, E&&>, bool> = true>
+    __GBLIBCPP_CONSTEXPR unique_ptr& operator=(unique_ptr<U, E>&& other) noexcept
+    {
+        reset(other.release());
+        get_deleter() = std::move(other.get_deleter());
+        return *this;
+    }
+
+    __GBLIBCPP_CONSTEXPR void swap(unique_ptr& other) noexcept
+    {
+        std::swap(data, other.data);
+    }
+
+    __GBLIBCPP_CONSTEXPR pointer get() const noexcept { return data.first(); }
+    __GBLIBCPP_CONSTEXPR deleter_type& get_deleter() noexcept { return data.second(); }
+    __GBLIBCPP_CONSTEXPR const deleter_type& get_deleter() const noexcept { return data.second(); }
+
+    __GBLIBCPP_CONSTEXPR pointer release() noexcept
+    {
+        pointer ret = get();
+        data.first() = nullptr;
+        return ret;
+    }
+
+    __GBLIBCPP_CONSTEXPR void reset(pointer p = pointer{}) noexcept
+    {
+        pointer old = release();
+        data.first() = p;
+        if (old)
+            get_deleter()(old);
+    }
+
+    __GBLIBCPP_CONSTEXPR explicit operator bool() const noexcept { return get(); }
+    __GBLIBCPP_CONSTEXPR pointer operator->() const noexcept { return get(); }
+
+    __GBLIBCPP_CONSTEXPR std::add_lvalue_reference_t<T> operator*() const
+        noexcept(noexcept(*std::declval<pointer>())) { return *get(); }
+};
+
 // TODO: use only one allocation
 template <typename T, typename... Args>
 std::shared_ptr<T> make_shared(Args&&... args)
@@ -643,6 +741,24 @@ std::shared_ptr<T> make_shared(Args&&... args)
     return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
 }
 
+template <typename T, typename... Args>
+__GBLIBCPP_CONSTEXPR std::unique_ptr<T> make_unique(Args&&... args)
+{
+    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+template <typename T>
+__GBLIBCPP_CONSTEXPR void swap(std::shared_ptr<T>& lhs, std::shared_ptr<T>& rhs) noexcept
+{
+    lhs.swap(rhs);
+}
+
+template <typename T, typename D>
+__GBLIBCPP_CONSTEXPR void swap(std::unique_ptr<T, D>& lhs, std::unique_ptr<T, D>& rhs) noexcept
+{
+    lhs.swap(rhs);
+}
+
 } // namespace std
 
 #endif

+ 2 - 1
include/kernel/process.hpp

@@ -30,6 +30,7 @@
 #include <kernel/tty.hpp>
 #include <kernel/user/thread_local.hpp>
 #include <kernel/vfs.hpp>
+#include <kernel/vfs/dentry.hpp>
 #include <kernel/vfs/filearr.hpp>
 
 class process;
@@ -61,7 +62,7 @@ public:
 
     process_attr attr {};
     fs::filearray files;
-    fs::dentry* cwd {};
+    fs::dentry_pointer cwd {};
     mode_t umask { 0022 };
 
     pid_t pid {};

+ 6 - 5
include/kernel/vfs.hpp

@@ -5,6 +5,8 @@
 #include <kernel/vfs/inode.hpp>
 #include <kernel/vfs/vfs.hpp>
 
+#include <memory>
+
 #include <stdint.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -61,7 +63,7 @@ struct PACKED user_dirent64 {
 };
 
 struct fs_context {
-    dentry* root;
+    dentry_pointer root;
 };
 
 struct mount_data {
@@ -111,10 +113,9 @@ size_t write(struct inode* file, const char* buf, size_t offset, size_t n);
 int mount(dentry* mnt, const char* source, const char* mount_point,
         const char* fstype, unsigned long flags, const void *data);
 
-std::pair<dentry*, int> open(const fs_context& context, dentry* cwd, types::path_iterator path,
-        bool follow_symlinks = true, int recurs_no = 0);
-
-std::pair<dentry*, int> current_open(dentry* cwd, types::path_iterator path, bool follow_symlinks = true);
+#define current_open(...) fs::open(current_process->fs_context, current_process->cwd.get(), __VA_ARGS__)
+std::pair<dentry_pointer, int> open(const fs_context& context, dentry* cwd,
+        types::path_iterator path, bool follow_symlinks = true, int recurs_no = 0);
 
 } // namespace fs
 

+ 7 - 0
include/kernel/vfs/dentry.hpp

@@ -35,6 +35,12 @@ struct dentry {
     std::string name;
 };
 
+struct dentry_deleter {
+    void operator()(struct dentry* dentry) const;
+};
+
+using dentry_pointer = std::unique_ptr<struct dentry, dentry_deleter>;
+
 struct dcache {
     struct dentry** arr;
     int hash_bits;
@@ -45,6 +51,7 @@ struct dcache {
 std::pair<struct dentry*, int> d_find(struct dentry* parent, types::string_view name);
 std::string d_path(const struct dentry* dentry, const struct dentry* root);
 
+dentry_pointer d_get(const dentry_pointer& dp);
 struct dentry* d_get(struct dentry* dentry);
 struct dentry* d_put(struct dentry* dentry);
 

+ 21 - 16
src/kernel/process.cpp

@@ -27,13 +27,15 @@
 #include <kernel/vfs/dentry.hpp>
 
 process::process(const process& parent, pid_t pid)
-    : mms { parent.mms }, attr { parent.attr } , files { parent.files.copy() }
-    , cwd { parent.cwd }, umask { parent.umask }, pid { pid }
-    , ppid { parent.pid }, pgid { parent.pgid } , sid { parent.sid }
-    , control_tty { parent.control_tty }, fs_context { parent.fs_context }
+    : mms{parent.mms}, attr{parent.attr}, files{parent.files.copy()}, umask{parent.umask}
+    , pid{pid}, ppid{parent.pid}, pgid{parent.pgid}, sid{parent.sid}
+    , control_tty{parent.control_tty}
 {
-    fs::d_get(cwd);
-    fs::d_get(fs_context.root);
+    if (parent.cwd)
+        cwd = fs::d_get(parent.cwd);
+
+    if (parent.fs_context.root)
+        fs_context.root = fs::d_get(parent.fs_context.root);
 }
 
 process::process(pid_t pid, pid_t ppid)
@@ -145,6 +147,10 @@ void proclist::kill(pid_t pid, int exit_code)
     // unmap all user memory areas
     proc.mms.clear();
 
+    // free cwd and fs_context dentry
+    proc.cwd.reset();
+    proc.fs_context.root.reset();
+
     // make child processes orphans (children of init)
     this->make_children_orphans(pid);
 
@@ -218,8 +224,8 @@ void NORETURN _kernel_init(kernel::mem::paging::pfn_t kernel_stack_pfn)
                 "tmpfs", MS_NOATIME, nullptr);
         assert(ret == 0);
     }
-    current_process->fs_context.root = rootfs->root();
-    current_process->cwd = rootfs->root();
+    current_process->fs_context.root = d_get(rootfs->root());
+    current_process->cwd = d_get(rootfs->root());
 
     // ------------------------------------------
     // interrupt enabled
@@ -242,17 +248,15 @@ void NORETURN _kernel_init(kernel::mem::paging::pfn_t kernel_stack_pfn)
     // mount fat32 /mnt directory
     // TODO: parse kernel parameters
     if (1) {
-        auto [ mnt, status ] = fs::open(context, context.root, "/mnt");
+        auto [ mnt, status ] = fs::open(context, context.root.get(), "/mnt");
         assert(mnt && status == -ENOENT);
 
-        if (int ret = fs::mkdir(mnt, 0755); 1)
+        if (int ret = fs::mkdir(mnt.get(), 0755); 1)
             assert(ret == 0 && mnt->flags & fs::D_PRESENT);
 
-        int ret = rootfs->mount(mnt, "/dev/sda", "/mnt",
+        int ret = rootfs->mount(mnt.get(), "/dev/sda", "/mnt",
                 "fat32", MS_RDONLY | MS_NOATIME | MS_NODEV | MS_NOSUID, "ro,nodev");
         assert(ret == 0);
-
-        fs::d_put(mnt);
     }
 
     current_process->attr.system = 0;
@@ -265,15 +269,16 @@ void NORETURN _kernel_init(kernel::mem::paging::pfn_t kernel_stack_pfn)
         .ip{}, .sp{}
     };
 
-    int ret;
-    std::tie(d.exec_dent, ret) = fs::open(context, context.root, d.argv[0]);
-    if (!d.exec_dent || ret) {
+    auto [exec, ret] = fs::open(context, context.root.get(), d.argv[0]);
+    if (!exec || ret) {
         kmsg("kernel panic: init not found!");
         freeze();
     }
 
+    d.exec_dent = exec.get();
     if (int ret = types::elf::elf32_load(d); 1)
         assert(ret == 0);
+    exec.reset();
 
     int ds = 0x33, cs = 0x2b;
 

+ 13 - 15
src/kernel/syscall/fileops.cc

@@ -84,23 +84,23 @@ int kernel::syscall::do_open(const char __user* path, int flags, mode_t mode)
     mode &= ~current_process->umask;
 
     // TODO: use copy_from_user
-    return current_process->files.open(current_process->cwd, path, flags, mode);
+    return current_process->files.open(current_process->cwd.get(), path, flags, mode);
 }
 
 int kernel::syscall::do_symlink(const char __user* target, const char __user* linkpath)
 {
     // TODO: use copy_from_user
-    auto [ dent, status ] = fs::current_open(current_process->cwd, linkpath);
+    auto [ dent, status ] = current_open(linkpath);
     if (!dent || status != -ENOENT)
         return status;
 
-    return fs::symlink(dent, target);
+    return fs::symlink(dent.get(), target);
 }
 
 int kernel::syscall::do_readlink(const char __user* pathname, char __user* buf, size_t buf_size)
 {
     // TODO: use copy_from_user
-    auto [ dent, status ] = fs::current_open(current_process->cwd, pathname, false);
+    auto [ dent, status ] = current_open(pathname, false);
 
     if (!dent || status)
         return status;
@@ -368,8 +368,7 @@ int kernel::syscall::do_statx(int dirfd, const char __user* path,
         return -EINVAL;
     }
 
-    auto [ dent, status ] = fs::current_open(
-            current_process->cwd, path, !(flags & AT_SYMLINK_NOFOLLOW));
+    auto [ dent, status ] = current_open(path, !(flags & AT_SYMLINK_NOFOLLOW));
     if (!dent || status)
         return status;
 
@@ -401,16 +400,16 @@ int kernel::syscall::do_mkdir(const char __user* pathname, mode_t mode)
     mode &= (~current_process->umask & 0777);
 
     // TODO: use copy_from_user
-    auto [ dent, status ] = fs::current_open(current_process->cwd, pathname);
+    auto [ dent, status ] = current_open(pathname);
     if (!dent || status != -ENOENT)
         return status;
 
-    return fs::mkdir(dent, mode);
+    return fs::mkdir(dent.get(), mode);
 }
 
 int kernel::syscall::do_truncate(const char __user* pathname, long length)
 {
-    auto [ dent, status ] = fs::current_open(current_process->cwd, pathname);
+    auto [ dent, status ] = current_open(pathname);
     if (!dent || status)
         return status;
 
@@ -422,8 +421,7 @@ int kernel::syscall::do_truncate(const char __user* pathname, long length)
 
 int kernel::syscall::do_unlink(const char __user* pathname)
 {
-    auto [ dent, status ] = fs::current_open(
-            current_process->cwd, pathname, false);
+    auto [ dent, status ] = current_open(pathname, false);
 
     if (!dent || status)
         return status;
@@ -431,12 +429,12 @@ int kernel::syscall::do_unlink(const char __user* pathname)
     if (S_ISDIR(dent->inode->mode))
         return -EISDIR;
 
-    return fs::unlink(dent);
+    return fs::unlink(dent.get());
 }
 
 int kernel::syscall::do_access(const char __user* pathname, int mode)
 {
-    auto [ dent, status ] = fs::current_open(current_process->cwd, pathname);
+    auto [ dent, status ] = current_open(pathname);
     if (!dent || status)
         return status;
 
@@ -456,11 +454,11 @@ int kernel::syscall::do_access(const char __user* pathname, int mode)
 int kernel::syscall::do_mknod(const char __user* pathname, mode_t mode, dev_t dev)
 {
     mode &= S_IFMT | (~current_process->umask & 0777);
-    auto [ dent, status ] = fs::current_open(current_process->cwd, pathname);
+    auto [ dent, status ] = current_open(pathname);
     if (!dent || status != -ENOENT)
         return status;
 
-    return fs::mknod(dent, mode, dev);
+    return fs::mknod(dent.get(), mode, dev);
 }
 
 int kernel::syscall::do_poll(pollfd __user* fds, nfds_t nfds, int timeout)

+ 2 - 2
src/kernel/syscall/mount.cc

@@ -17,9 +17,9 @@ int kernel::syscall::do_mount(
         return -EINVAL;
 
     // TODO: use copy_from_user
-    auto [ mountpoint, status ] = fs::current_open(current_process->cwd, target);
+    auto [ mountpoint, status ] = current_open(target);
     if (!mountpoint || status)
         return status;
 
-    return fs::mount(mountpoint, source, target, fstype, flags, _fsdata);
+    return fs::mount(mountpoint.get(), source, target, fstype, flags, _fsdata);
 }

+ 10 - 5
src/kernel/syscall/procops.cc

@@ -29,14 +29,14 @@ static inline void not_implemented(const char* pos, int line)
 int kernel::syscall::do_chdir(const char __user* path)
 {
     // TODO: use copy_from_user
-    auto [dir, ret] = fs::current_open(current_process->cwd, path);
+    auto [dir, ret] = current_open(path);
     if (!dir || ret)
         return ret;
 
     if (!(dir->flags & fs::D_DIRECTORY))
         return -ENOTDIR;
 
-    current_process->cwd = dir;
+    current_process->cwd = std::move(dir);
     return 0;
 }
 
@@ -52,12 +52,15 @@ execve_retval kernel::syscall::do_execve(
         .ip{}, .sp{},
     };
 
+    fs::dentry_pointer dent;
     if (1) {
         int ret;
-        std::tie(d.exec_dent, ret) = fs::current_open(current_process->cwd, exec);
+        std::tie(dent, ret) = current_open(exec);
 
-        if (!d.exec_dent || ret)
+        if (!dent || ret)
             return { 0, 0, ret };
+
+        d.exec_dent = dent.get();
     }
 
     current_process->files.onexec();
@@ -66,7 +69,9 @@ execve_retval kernel::syscall::do_execve(
 
     // TODO: set cs and ss to compatibility mode
     if (int ret = types::elf::elf32_load(d); ret != 0) {
+        dent.reset();
         async::preempt_enable();
+
         if (ret == types::elf::ELF_LOAD_FAIL_NORETURN)
             kill_current(SIGSEGV);
 
@@ -142,7 +147,7 @@ int kernel::syscall::do_waitpid(pid_t waitpid, int __user* arg1, int options)
 
 int kernel::syscall::do_getcwd(char __user* buf, size_t buf_size)
 {
-    auto path = fs::d_path(current_process->cwd, current_process->fs_context.root);
+    auto path = fs::d_path(current_process->cwd.get(), current_process->fs_context.root.get());
 
     int len = std::min(buf_size-1, path.size());
 

+ 15 - 21
src/kernel/vfs.cpp

@@ -260,12 +260,7 @@ size_t fs::write(struct fs::inode* file, const char* buf, size_t offset, size_t
     return -1U;
 }
 
-std::pair<dentry*, int> fs::current_open(dentry* cwd, types::path_iterator path, bool follow_symlinks)
-{
-    return fs::open(current_process->fs_context, cwd, path, follow_symlinks);
-}
-
-std::pair<dentry*, int> fs::open(const fs_context& context, dentry* cwd,
+std::pair<fs::dentry_pointer, int> fs::open(const fs_context& context, dentry* _cwd,
     types::path_iterator path, bool follow, int recurs_no)
 {
     // too many recursive search layers will cause stack overflow
@@ -273,8 +268,7 @@ std::pair<dentry*, int> fs::open(const fs_context& context, dentry* cwd,
     if (recurs_no >= 16)
         return {nullptr, -ELOOP};
 
-    if (path.is_absolute())
-        cwd = context.root;
+    dentry_pointer cwd{path.is_absolute() ? d_get(context.root) : d_get(_cwd)};
 
     for ( ; path; ++path) {
         auto item = *path;
@@ -292,31 +286,31 @@ std::pair<dentry*, int> fs::open(const fs_context& context, dentry* cwd,
                 return {nullptr, ret};
             linkpath[ret] = 0;
 
-            std::tie(cwd, ret) = fs::open(context, cwd, linkpath, true, recurs_no + 1);
-
-            if (!cwd || (cwd->flags & D_PRESENT))
+            std::tie(cwd, ret) = fs::open(context, cwd->parent, linkpath, true, recurs_no + 1);
+            if (!cwd || ret)
                 return {nullptr, ret};
         }
 
-        int ret;
-        std::tie(cwd, ret) = d_find(cwd, item);
-        if (!cwd)
-            return {nullptr, ret};
+        if (1) {
+            int status;
+            std::tie(cwd, status) = d_find(cwd.get(), item);
+            if (!cwd)
+                return {nullptr, status};
+        }
 
         if (cwd->flags & D_MOUNTPOINT) {
-            auto iter = mounts.find(cwd);
+            auto iter = mounts.find(cwd.get());
             assert(iter);
 
             auto* fs = iter->second.fs;
             assert(fs);
 
-            cwd = fs->root();
-            assert(cwd);
+            cwd = d_get(fs->root());
         }
     }
 
     if (!(cwd->flags & D_PRESENT))
-        return {cwd, -ENOENT};
+        return {std::move(cwd), -ENOENT};
 
     if (follow && S_ISLNK(cwd->inode->mode)) {
         char linkpath[256];
@@ -325,10 +319,10 @@ std::pair<dentry*, int> fs::open(const fs_context& context, dentry* cwd,
             return {nullptr, ret};
         linkpath[ret] = 0;
 
-        return fs::open(context, cwd, linkpath, true, recurs_no+1);
+        return fs::open(context, cwd->parent, linkpath, true, recurs_no+1);
     }
 
-    return {cwd, 0};
+    return {std::move(cwd), 0};
 }
 
 int fs::statx(struct inode* inode, struct statx* stat, unsigned int mask)

+ 20 - 11
src/kernel/vfs/dentry.cc

@@ -54,12 +54,14 @@ static inline struct dentry*& __d_first(struct dcache* cache, hash_t hash)
 
 static inline void __d_add(struct dentry* parent, struct dentry* dentry)
 {
-    assert(parent == dentry->parent);
+    assert(!dentry->parent);
+    assert(parent->refcount && dentry->refcount);
 
+    dentry->parent = d_get(parent);
     dentry->prev = nullptr;
     dentry->next = __d_first(parent->cache, dentry->hash);
 
-    __d_first(parent->cache, dentry->hash) = dentry;
+    __d_first(parent->cache, dentry->hash) = d_get(dentry);
     parent->cache->size++;
 }
 
@@ -73,7 +75,7 @@ static inline struct dentry* __d_find_fast(struct dentry* parent, types::string_
         if (!__d_equal(dentry, parent, name))
             continue;
 
-        return dentry;
+        return d_get(dentry);
     }
 
     return nullptr;
@@ -101,10 +103,7 @@ static inline int __d_load(struct dentry* parent)
                 struct dentry* dentry = dcache_alloc(parent->cache);
 
                 dentry->fs = inode->fs;
-
                 dentry->inode = inode;
-                dentry->parent = parent;
-
                 dentry->name = fn;
 
                 if (S_ISDIR(mode))
@@ -116,6 +115,7 @@ static inline int __d_load(struct dentry* parent)
 
                 __d_add(parent, dentry);
 
+                d_put(dentry);
                 return 0;
             });
 
@@ -154,16 +154,15 @@ std::pair<struct dentry*, int> fs::d_find(struct dentry* parent, types::string_v
         auto* dentry = dcache_alloc(parent->cache);
         dentry->fs = parent->fs;
 
-        dentry->parent = parent;
         dentry->name.assign(name.data(), name.size());
         dentry->hash = __d_hash(parent, dentry->name);
 
         __d_add(parent, dentry);
 
-        return {d_get(dentry), -ENOENT};
+        return {dentry, -ENOENT};
     }
 
-    return {d_get(ret), 0};
+    return {ret, 0};
 }
 
 std::string fs::d_path(const struct dentry* dentry, const struct dentry* root)
@@ -187,6 +186,11 @@ std::string fs::d_path(const struct dentry* dentry, const struct dentry* root)
     return ret;
 }
 
+dentry_pointer fs::d_get(const dentry_pointer& dentry)
+{
+    return d_get(dentry.get());
+}
+
 struct dentry* fs::d_get(struct dentry* dentry)
 {
     assert(dentry);
@@ -203,6 +207,11 @@ struct dentry* fs::d_put(struct dentry* dentry)
     return dentry;;
 }
 
+void dentry_deleter::operator()(struct dentry* dentry) const
+{
+    fs::d_put(dentry);
+}
+
 void fs::dcache_init(struct dcache* cache, int hash_bits)
 {
     cache->hash_bits = hash_bits;
@@ -221,7 +230,7 @@ struct dentry* fs::dcache_alloc(struct dcache* cache)
     struct dentry* dentry = new struct dentry();
     dentry->cache = cache;
 
-    return dentry;
+    return d_get(dentry);
 }
 
 void fs::dcache_init_root(struct dcache* cache, struct dentry* root)
@@ -229,7 +238,7 @@ void fs::dcache_init_root(struct dcache* cache, struct dentry* root)
     assert(cache->size == 0);
 
     root->prev = root->next = nullptr;
-    __d_first(cache, root->hash) = root;
+    __d_first(cache, root->hash) = d_get(root);
 
     cache->size++;
 }

+ 7 - 4
src/kernel/vfs/filearr.cc

@@ -4,6 +4,7 @@
 
 #include <kernel/async/lock.hpp>
 #include <kernel/vfs.hpp>
+#include <kernel/vfs/dentry.hpp>
 #include <kernel/vfs/filearr.hpp>
 
 using namespace fs;
@@ -175,7 +176,7 @@ int filearray::close(int fd)
     return 0;
 }
 
-static inline std::pair<dentry*, int>
+static inline std::pair<dentry_pointer, int>
 _open_file(const fs_context& context, dentry* cwd, types::path_iterator filepath, int flags, mode_t mode)
 {
     auto [ dent, ret ] = fs::open(context, cwd, filepath);
@@ -185,17 +186,17 @@ _open_file(const fs_context& context, dentry* cwd, types::path_iterator filepath
     if (dent->flags & D_PRESENT) {
         if ((flags & O_CREAT) && (flags & O_EXCL))
             return {nullptr, -EEXIST};
-        return {dent, 0};
+        return {std::move(dent), 0};
     }
 
     if (!(flags & O_CREAT))
         return {nullptr, -ENOENT};
 
     // create file
-    if (int ret = fs::creat(dent, mode); ret != 0)
+    if (int ret = fs::creat(dent.get(), mode); ret != 0)
         return {nullptr, ret};
 
-    return {dent, 0};
+    return {std::move(dent), 0};
 }
 
 // TODO: file opening permissions check
@@ -204,6 +205,8 @@ int filearray::open(dentry* cwd, types::path_iterator filepath, int flags, mode_
     lock_guard lck{pimpl->mtx};
 
     auto [dent, ret] = _open_file(*pimpl->context, cwd, filepath, flags, mode);
+
+    assert(dent || ret != 0);
     if (ret != 0)
         return ret;
 

+ 1 - 1
src/kernel/vfs/vfs.cc

@@ -90,7 +90,7 @@ int vfs::mount(dentry* mnt, const char* source, const char* mount_point,
     if (ret != 0)
         return ret;
 
-    mounts.emplace(mnt, mount_data {
+    mounts.emplace(d_get(mnt), mount_data {
                             .fs = new_fs,
                             .source = source,
                             .mount_point = mount_point,