Selaa lähdekoodia

Kernel: Convert process file descriptor table to a SpinlockProtected

Instead of manually locking in the various member functions of
Process::OpenFileDescriptions, simply wrap it in a SpinlockProtected.
Andreas Kling 3 vuotta sitten
vanhempi
commit
8ebec2938c

+ 1 - 1
Kernel/GlobalProcessExposed.cpp

@@ -490,7 +490,7 @@ private:
             process_object.add("uid", process.uid().value());
             process_object.add("gid", process.gid().value());
             process_object.add("ppid", process.ppid().value());
-            process_object.add("nfds", process.fds().open_count());
+            process_object.add("nfds", process.fds().with([](auto& fds) { return fds.open_count(); }));
             process_object.add("name", process.name());
             process_object.add("executable", process.executable() ? TRY(process.executable()->try_serialize_absolute_path())->view() : ""sv);
             process_object.add("tty", process.tty() ? process.tty()->tty_name().view() : "notty"sv);

+ 16 - 19
Kernel/Process.cpp

@@ -139,17 +139,21 @@ ErrorOr<NonnullRefPtr<Process>> Process::try_create_user_process(RefPtr<Thread>&
     auto name = TRY(KString::try_create(parts.last()));
     auto process = TRY(Process::try_create(first_thread, move(name), uid, gid, ProcessID(0), false, VirtualFileSystem::the().root_custody(), nullptr, tty));
 
-    TRY(process->m_fds.try_resize(Process::OpenFileDescriptions::max_open()));
+    TRY(process->m_fds.with([&](auto& fds) -> ErrorOr<void> {
+        TRY(fds.try_resize(Process::OpenFileDescriptions::max_open()));
+
+        auto& device_to_use_as_tty = tty ? (CharacterDevice&)*tty : DeviceManagement::the().null_device();
+        auto description = TRY(device_to_use_as_tty.open(O_RDWR));
+        auto setup_description = [&](int fd) {
+            fds.m_fds_metadatas[fd].allocate();
+            fds[fd].set(*description);
+        };
+        setup_description(0);
+        setup_description(1);
+        setup_description(2);
 
-    auto& device_to_use_as_tty = tty ? (CharacterDevice&)*tty : DeviceManagement::the().null_device();
-    auto description = TRY(device_to_use_as_tty.open(O_RDWR));
-    auto setup_description = [&process, &description](int fd) {
-        process->m_fds.m_fds_metadatas[fd].allocate();
-        process->m_fds[fd].set(*description);
-    };
-    setup_description(0);
-    setup_description(1);
-    setup_description(2);
+        return {};
+    }));
 
     Thread* new_main_thread = nullptr;
     u32 prev_flags = 0;
@@ -387,7 +391,6 @@ RefPtr<Process> Process::from_pid(ProcessID pid)
 
 const Process::OpenFileDescriptionAndFlags* Process::OpenFileDescriptions::get_if_valid(size_t i) const
 {
-    SpinlockLocker lock(m_fds_lock);
     if (m_fds_metadatas.size() <= i)
         return nullptr;
 
@@ -398,7 +401,6 @@ const Process::OpenFileDescriptionAndFlags* Process::OpenFileDescriptions::get_i
 }
 Process::OpenFileDescriptionAndFlags* Process::OpenFileDescriptions::get_if_valid(size_t i)
 {
-    SpinlockLocker lock(m_fds_lock);
     if (m_fds_metadatas.size() <= i)
         return nullptr;
 
@@ -410,20 +412,18 @@ Process::OpenFileDescriptionAndFlags* Process::OpenFileDescriptions::get_if_vali
 
 const Process::OpenFileDescriptionAndFlags& Process::OpenFileDescriptions::at(size_t i) const
 {
-    SpinlockLocker lock(m_fds_lock);
     VERIFY(m_fds_metadatas[i].is_allocated());
     return m_fds_metadatas[i];
 }
+
 Process::OpenFileDescriptionAndFlags& Process::OpenFileDescriptions::at(size_t i)
 {
-    SpinlockLocker lock(m_fds_lock);
     VERIFY(m_fds_metadatas[i].is_allocated());
     return m_fds_metadatas[i];
 }
 
 ErrorOr<NonnullRefPtr<OpenFileDescription>> Process::OpenFileDescriptions::open_file_description(int fd) const
 {
-    SpinlockLocker lock(m_fds_lock);
     if (fd < 0)
         return EBADF;
     if (static_cast<size_t>(fd) >= m_fds_metadatas.size())
@@ -436,7 +436,6 @@ ErrorOr<NonnullRefPtr<OpenFileDescription>> Process::OpenFileDescriptions::open_
 
 void Process::OpenFileDescriptions::enumerate(Function<void(const OpenFileDescriptionAndFlags&)> callback) const
 {
-    SpinlockLocker lock(m_fds_lock);
     for (auto const& file_description_metadata : m_fds_metadatas) {
         callback(file_description_metadata);
     }
@@ -444,7 +443,6 @@ void Process::OpenFileDescriptions::enumerate(Function<void(const OpenFileDescri
 
 void Process::OpenFileDescriptions::change_each(Function<void(OpenFileDescriptionAndFlags&)> callback)
 {
-    SpinlockLocker lock(m_fds_lock);
     for (auto& file_description_metadata : m_fds_metadatas) {
         callback(file_description_metadata);
     }
@@ -462,7 +460,6 @@ size_t Process::OpenFileDescriptions::open_count() const
 
 ErrorOr<Process::ScopedDescriptionAllocation> Process::OpenFileDescriptions::allocate(int first_candidate_fd)
 {
-    SpinlockLocker lock(m_fds_lock);
     for (size_t i = first_candidate_fd; i < max_open(); ++i) {
         if (!m_fds_metadatas[i].is_allocated()) {
             m_fds_metadatas[i].allocate();
@@ -592,7 +589,7 @@ void Process::finalize()
 
     if (m_alarm_timer)
         TimerQueue::the().cancel_timer(m_alarm_timer.release_nonnull());
-    m_fds.clear();
+    m_fds.with([](auto& fds) { fds.clear(); });
     m_tty = nullptr;
     m_executable = nullptr;
     m_cwd = nullptr;

+ 30 - 10
Kernel/Process.h

@@ -552,8 +552,6 @@ private:
 
     void clear_futex_queues_on_exec();
 
-    void setup_socket_fd(int fd, NonnullRefPtr<OpenFileDescription> description, int type);
-
     ErrorOr<void> remap_range_as_stack(FlatPtr address, size_t size);
 
 public:
@@ -633,15 +631,16 @@ public:
     class ScopedDescriptionAllocation;
     class OpenFileDescriptions {
         AK_MAKE_NONCOPYABLE(OpenFileDescriptions);
+        AK_MAKE_NONMOVABLE(OpenFileDescriptions);
         friend class Process;
 
     public:
+        OpenFileDescriptions() { }
         ALWAYS_INLINE const OpenFileDescriptionAndFlags& operator[](size_t i) const { return at(i); }
         ALWAYS_INLINE OpenFileDescriptionAndFlags& operator[](size_t i) { return at(i); }
 
         ErrorOr<void> try_clone(const Kernel::Process::OpenFileDescriptions& other)
         {
-            SpinlockLocker lock_other(other.m_fds_lock);
             TRY(try_resize(other.m_fds_metadatas.size()));
 
             for (size_t i = 0; i < other.m_fds_metadatas.size(); ++i) {
@@ -671,16 +670,13 @@ public:
 
         void clear()
         {
-            SpinlockLocker lock(m_fds_lock);
             m_fds_metadatas.clear();
         }
 
         ErrorOr<NonnullRefPtr<OpenFileDescription>> open_file_description(int fd) const;
 
     private:
-        OpenFileDescriptions() = default;
         static constexpr size_t s_max_open_file_descriptors { FD_SETSIZE };
-        mutable Spinlock m_fds_lock;
         Vector<OpenFileDescriptionAndFlags> m_fds_metadatas;
     };
 
@@ -702,6 +698,15 @@ public:
             swap(m_description, other.m_description);
         }
 
+        ScopedDescriptionAllocation& operator=(ScopedDescriptionAllocation&& other)
+        {
+            if (this != &other) {
+                m_description = exchange(other.m_description, nullptr);
+                fd = exchange(other.fd, -1);
+            }
+            return *this;
+        }
+
         ~ScopedDescriptionAllocation()
         {
             if (m_description && m_description->is_allocated() && !m_description->is_valid()) {
@@ -709,7 +714,7 @@ public:
             }
         }
 
-        const int fd { -1 };
+        int fd { -1 };
 
     private:
         OpenFileDescriptionAndFlags* m_description { nullptr };
@@ -741,8 +746,23 @@ public:
         WeakPtr<Process> m_process;
     };
 
-    OpenFileDescriptions& fds() { return m_fds; }
-    const OpenFileDescriptions& fds() const { return m_fds; }
+    SpinlockProtected<OpenFileDescriptions>& fds() { return m_fds; }
+    SpinlockProtected<OpenFileDescriptions> const& fds() const { return m_fds; }
+
+    ErrorOr<NonnullRefPtr<OpenFileDescription>> open_file_description(int fd)
+    {
+        return m_fds.with([fd](auto& fds) { return fds.open_file_description(fd); });
+    }
+
+    ErrorOr<NonnullRefPtr<OpenFileDescription>> open_file_description(int fd) const
+    {
+        return m_fds.with([fd](auto& fds) { return fds.open_file_description(fd); });
+    }
+
+    ErrorOr<ScopedDescriptionAllocation> allocate_fd()
+    {
+        return m_fds.with([](auto& fds) { return fds.allocate(); });
+    }
 
 private:
     SpinlockProtected<Thread::ListInProcess>& thread_list() { return m_thread_list; }
@@ -750,7 +770,7 @@ private:
 
     SpinlockProtected<Thread::ListInProcess> m_thread_list;
 
-    OpenFileDescriptions m_fds;
+    SpinlockProtected<OpenFileDescriptions> m_fds;
 
     const bool m_is_kernel_process;
     Atomic<State> m_state { State::Running };

+ 50 - 45
Kernel/ProcessSpecificExposed.cpp

@@ -83,7 +83,7 @@ ErrorOr<NonnullRefPtr<Inode>> Process::lookup_stacks_directory(const ProcFS& pro
 
 ErrorOr<size_t> Process::procfs_get_file_description_link(unsigned fd, KBufferBuilder& builder) const
 {
-    auto file_description = TRY(m_fds.open_file_description(fd));
+    auto file_description = TRY(open_file_description(fd));
     // Note: These links are not guaranteed to point to actual VFS paths, just like in other kernels.
     auto data = TRY(file_description->pseudo_path());
     TRY(builder.append(data->view()));
@@ -95,16 +95,18 @@ ErrorOr<void> Process::traverse_file_descriptions_directory(FileSystemID fsid, F
     TRY(callback({ ".", { fsid, m_procfs_traits->component_index() }, 0 }));
     TRY(callback({ "..", { fsid, m_procfs_traits->component_index() }, 0 }));
     size_t count = 0;
-    fds().enumerate([&](auto& file_description_metadata) {
-        if (!file_description_metadata.is_valid()) {
+    fds().with([&](auto& fds) {
+        fds.enumerate([&](auto& file_description_metadata) {
+            if (!file_description_metadata.is_valid()) {
+                count++;
+                return;
+            }
+            StringBuilder builder;
+            builder.appendff("{}", count);
+            // FIXME: Propagate errors from callback.
+            (void)callback({ builder.string_view(), { fsid, SegmentedProcFSIndex::build_segmented_index_for_file_description(pid(), count) }, DT_LNK });
             count++;
-            return;
-        }
-        StringBuilder builder;
-        builder.appendff("{}", count);
-        // FIXME: Propagate errors from callback.
-        (void)callback({ builder.string_view(), { fsid, SegmentedProcFSIndex::build_segmented_index_for_file_description(pid(), count) }, DT_LNK });
-        count++;
+        });
     });
     return {};
 }
@@ -115,7 +117,7 @@ ErrorOr<NonnullRefPtr<Inode>> Process::lookup_file_descriptions_directory(const
     if (!maybe_index.has_value())
         return ENOENT;
 
-    if (!fds().get_if_valid(*maybe_index))
+    if (!fds().with([&](auto& fds) { return fds.get_if_valid(*maybe_index); }))
         return ENOENT;
 
     return TRY(ProcFSProcessPropertyInode::try_create_for_file_description_link(procfs, *maybe_index, pid()));
@@ -178,43 +180,46 @@ ErrorOr<void> Process::procfs_get_perf_events(KBufferBuilder& builder) const
 ErrorOr<void> Process::procfs_get_fds_stats(KBufferBuilder& builder) const
 {
     JsonArraySerializer array { builder };
-    if (fds().open_count() == 0) {
-        array.finish();
-        return {};
-    }
 
-    size_t count = 0;
-    fds().enumerate([&](auto& file_description_metadata) {
-        if (!file_description_metadata.is_valid()) {
-            count++;
-            return;
+    return fds().with([&](auto& fds) -> ErrorOr<void> {
+        if (fds.open_count() == 0) {
+            array.finish();
+            return {};
         }
-        bool cloexec = file_description_metadata.flags() & FD_CLOEXEC;
-        RefPtr<OpenFileDescription> description = file_description_metadata.description();
-        auto description_object = array.add_object();
-        description_object.add("fd", count);
-        // TODO: Better OOM handling.
-        auto pseudo_path_or_error = description->pseudo_path();
-        description_object.add("absolute_path", pseudo_path_or_error.is_error() ? "???"sv : pseudo_path_or_error.value()->view());
-        description_object.add("seekable", description->file().is_seekable());
-        description_object.add("class", description->file().class_name());
-        description_object.add("offset", description->offset());
-        description_object.add("cloexec", cloexec);
-        description_object.add("blocking", description->is_blocking());
-        description_object.add("can_read", description->can_read());
-        description_object.add("can_write", description->can_write());
-        Inode* inode = description->inode();
-        if (inode != nullptr) {
-            auto inode_object = description_object.add_object("inode");
-            inode_object.add("fsid", inode->fsid().value());
-            inode_object.add("index", inode->index().value());
-            inode_object.finish();
-        }
-        count++;
-    });
 
-    array.finish();
-    return {};
+        size_t count = 0;
+        fds.enumerate([&](auto& file_description_metadata) {
+            if (!file_description_metadata.is_valid()) {
+                count++;
+                return;
+            }
+            bool cloexec = file_description_metadata.flags() & FD_CLOEXEC;
+            RefPtr<OpenFileDescription> description = file_description_metadata.description();
+            auto description_object = array.add_object();
+            description_object.add("fd", count);
+            // TODO: Better OOM handling.
+            auto pseudo_path_or_error = description->pseudo_path();
+            description_object.add("absolute_path", pseudo_path_or_error.is_error() ? "???"sv : pseudo_path_or_error.value()->view());
+            description_object.add("seekable", description->file().is_seekable());
+            description_object.add("class", description->file().class_name());
+            description_object.add("offset", description->offset());
+            description_object.add("cloexec", cloexec);
+            description_object.add("blocking", description->is_blocking());
+            description_object.add("can_read", description->can_read());
+            description_object.add("can_write", description->can_write());
+            Inode* inode = description->inode();
+            if (inode != nullptr) {
+                auto inode_object = description_object.add_object("inode");
+                inode_object.add("fsid", inode->fsid().value());
+                inode_object.add("index", inode->index().value());
+                inode_object.finish();
+            }
+            count++;
+        });
+
+        array.finish();
+        return {};
+    });
 }
 
 ErrorOr<void> Process::procfs_get_virtual_memory_stats(KBufferBuilder& builder) const

+ 2 - 2
Kernel/Syscalls/anon_create.cpp

@@ -25,7 +25,7 @@ ErrorOr<FlatPtr> Process::sys$anon_create(size_t size, int options)
     if (size > NumericLimits<ssize_t>::max())
         return EINVAL;
 
-    auto new_fd = TRY(m_fds.allocate());
+    auto new_fd = TRY(allocate_fd());
     auto vmobject = TRY(Memory::AnonymousVMObject::try_create_purgeable_with_size(size, AllocationStrategy::Reserve));
     auto anon_file = TRY(AnonymousFile::try_create(move(vmobject)));
     auto description = TRY(OpenFileDescription::try_create(move(anon_file)));
@@ -37,7 +37,7 @@ ErrorOr<FlatPtr> Process::sys$anon_create(size_t size, int options)
     if (options & O_CLOEXEC)
         fd_flags |= FD_CLOEXEC;
 
-    m_fds[new_fd.fd].set(move(description), fd_flags);
+    m_fds.with([&](auto& fds) { fds[new_fd.fd].set(move(description), fd_flags); });
     return new_fd.fd;
 }
 

+ 1 - 1
Kernel/Syscalls/chdir.cpp

@@ -23,7 +23,7 @@ ErrorOr<FlatPtr> Process::sys$fchdir(int fd)
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
     TRY(require_promise(Pledge::stdio));
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     if (!description->is_directory())
         return ENOTDIR;
     if (!description->metadata().may_execute(*this))

+ 2 - 2
Kernel/Syscalls/chmod.cpp

@@ -22,7 +22,7 @@ ErrorOr<FlatPtr> Process::sys$chmod(Userspace<Syscall::SC_chmod_params const*> u
     if (params.dirfd == AT_FDCWD) {
         base = current_directory();
     } else {
-        auto base_description = TRY(fds().open_file_description(params.dirfd));
+        auto base_description = TRY(open_file_description(params.dirfd));
         if (!base_description->custody())
             return EINVAL;
         base = base_description->custody();
@@ -36,7 +36,7 @@ ErrorOr<FlatPtr> Process::sys$fchmod(int fd, mode_t mode)
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
     TRY(require_promise(Pledge::fattr));
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     TRY(description->chmod(mode));
     return 0;
 }

+ 2 - 2
Kernel/Syscalls/chown.cpp

@@ -15,7 +15,7 @@ ErrorOr<FlatPtr> Process::sys$fchown(int fd, UserID uid, GroupID gid)
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
     TRY(require_promise(Pledge::chown));
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     TRY(description->chown(uid, gid));
     return 0;
 }
@@ -31,7 +31,7 @@ ErrorOr<FlatPtr> Process::sys$chown(Userspace<const Syscall::SC_chown_params*> u
     if (params.dirfd == AT_FDCWD) {
         base = current_directory();
     } else {
-        auto base_description = TRY(fds().open_file_description(params.dirfd));
+        auto base_description = TRY(open_file_description(params.dirfd));
         if (!base_description->custody())
             return EINVAL;
         base = base_description->custody();

+ 10 - 8
Kernel/Syscalls/dup2.cpp

@@ -13,15 +13,17 @@ ErrorOr<FlatPtr> Process::sys$dup2(int old_fd, int new_fd)
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
     TRY(require_promise(Pledge::stdio));
-    auto description = TRY(fds().open_file_description(old_fd));
-    if (old_fd == new_fd)
+    return m_fds.with([&](auto& fds) -> ErrorOr<FlatPtr> {
+        auto description = TRY(fds.open_file_description(old_fd));
+        if (old_fd == new_fd)
+            return new_fd;
+        if (new_fd < 0 || static_cast<size_t>(new_fd) >= OpenFileDescriptions::max_open())
+            return EINVAL;
+        if (!fds.m_fds_metadatas[new_fd].is_allocated())
+            fds.m_fds_metadatas[new_fd].allocate();
+        fds[new_fd].set(move(description));
         return new_fd;
-    if (new_fd < 0 || static_cast<size_t>(new_fd) >= OpenFileDescriptions::max_open())
-        return EINVAL;
-    if (!m_fds.m_fds_metadatas[new_fd].is_allocated())
-        m_fds.m_fds_metadatas[new_fd].allocate();
-    m_fds[new_fd].set(move(description));
-    return new_fd;
+    });
 }
 
 }

+ 7 - 5
Kernel/Syscalls/execve.cpp

@@ -481,7 +481,7 @@ ErrorOr<void> Process::do_exec(NonnullRefPtr<OpenFileDescription> main_program_d
     // (For dynamically linked executable) Allocate an FD for passing the main executable to the dynamic loader.
     Optional<ScopedDescriptionAllocation> main_program_fd_allocation;
     if (has_interpreter)
-        main_program_fd_allocation = TRY(m_fds.allocate());
+        main_program_fd_allocation = TRY(allocate_fd());
 
     // We commit to the new executable at this point. There is no turning back!
 
@@ -536,14 +536,16 @@ ErrorOr<void> Process::do_exec(NonnullRefPtr<OpenFileDescription> main_program_d
 
     clear_futex_queues_on_exec();
 
-    fds().change_each([&](auto& file_description_metadata) {
-        if (file_description_metadata.is_valid() && file_description_metadata.flags() & FD_CLOEXEC)
-            file_description_metadata = {};
+    m_fds.with([&](auto& fds) {
+        fds.change_each([&](auto& file_description_metadata) {
+            if (file_description_metadata.is_valid() && file_description_metadata.flags() & FD_CLOEXEC)
+                file_description_metadata = {};
+        });
     });
 
     if (main_program_fd_allocation.has_value()) {
         main_program_description->set_readable(true);
-        m_fds[main_program_fd_allocation->fd].set(move(main_program_description), FD_CLOEXEC);
+        m_fds.with([&](auto& fds) { fds[main_program_fd_allocation->fd].set(move(main_program_description), FD_CLOEXEC); });
     }
 
     new_main_thread = nullptr;

+ 8 - 6
Kernel/Syscalls/fcntl.cpp

@@ -15,7 +15,7 @@ ErrorOr<FlatPtr> Process::sys$fcntl(int fd, int cmd, u32 arg)
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
     TRY(require_promise(Pledge::stdio));
     dbgln_if(IO_DEBUG, "sys$fcntl: fd={}, cmd={}, arg={}", fd, cmd, arg);
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     // NOTE: The FD flags are not shared between OpenFileDescription objects.
     //       This means that dup() doesn't copy the FD_CLOEXEC flag!
     switch (cmd) {
@@ -23,14 +23,16 @@ ErrorOr<FlatPtr> Process::sys$fcntl(int fd, int cmd, u32 arg)
         int arg_fd = (int)arg;
         if (arg_fd < 0)
             return EINVAL;
-        auto fd_allocation = TRY(m_fds.allocate(arg_fd));
-        m_fds[fd_allocation.fd].set(*description);
-        return fd_allocation.fd;
+        return m_fds.with([&](auto& fds) -> ErrorOr<FlatPtr> {
+            auto fd_allocation = TRY(fds.allocate(arg_fd));
+            fds[fd_allocation.fd].set(*description);
+            return fd_allocation.fd;
+        });
     }
     case F_GETFD:
-        return m_fds[fd].flags();
+        return m_fds.with([fd](auto& fds) { return fds[fd].flags(); });
     case F_SETFD:
-        m_fds[fd].set_flags(arg);
+        m_fds.with([fd, arg](auto& fds) { fds[fd].set_flags(arg); });
         break;
     case F_GETFL:
         return description->file_flags();

+ 5 - 1
Kernel/Syscalls/fork.cpp

@@ -23,7 +23,11 @@ ErrorOr<FlatPtr> Process::sys$fork(RegisterState& regs)
     child->m_veil_state = m_veil_state;
     child->m_unveiled_paths = m_unveiled_paths.deep_copy();
 
-    TRY(child->m_fds.try_clone(m_fds));
+    TRY(child->m_fds.with([&](auto& child_fds) {
+        return m_fds.with([&](auto& parent_fds) {
+            return child_fds.try_clone(parent_fds);
+        });
+    }));
 
     child->m_pg = m_pg;
 

+ 1 - 1
Kernel/Syscalls/fsync.cpp

@@ -12,7 +12,7 @@ ErrorOr<FlatPtr> Process::sys$fsync(int fd)
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
     TRY(require_promise(Pledge::stdio));
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     TRY(description->sync());
     return 0;
 }

+ 1 - 1
Kernel/Syscalls/ftruncate.cpp

@@ -18,7 +18,7 @@ ErrorOr<FlatPtr> Process::sys$ftruncate(int fd, Userspace<off_t const*> userspac
     auto length = TRY(copy_typed_from_user(userspace_length));
     if (length < 0)
         return EINVAL;
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     if (!description->is_writable())
         return EBADF;
     TRY(description->truncate(static_cast<u64>(length)));

+ 1 - 1
Kernel/Syscalls/get_dir_entries.cpp

@@ -15,7 +15,7 @@ ErrorOr<FlatPtr> Process::sys$get_dir_entries(int fd, Userspace<void*> user_buff
     TRY(require_promise(Pledge::stdio));
     if (user_size > NumericLimits<ssize_t>::max())
         return EINVAL;
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     auto buffer = TRY(UserOrKernelBuffer::for_user_buffer(user_buffer, static_cast<size_t>(user_size)));
     auto count = TRY(description->get_dir_entries(buffer, user_size));
     return count;

+ 9 - 7
Kernel/Syscalls/inode_watcher.cpp

@@ -18,7 +18,7 @@ ErrorOr<FlatPtr> Process::sys$create_inode_watcher(u32 flags)
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
     TRY(require_promise(Pledge::rpath));
 
-    auto fd_allocation = TRY(m_fds.allocate());
+    auto fd_allocation = TRY(allocate_fd());
     auto watcher = TRY(InodeWatcher::try_create());
     auto description = TRY(OpenFileDescription::try_create(move(watcher)));
 
@@ -26,12 +26,14 @@ ErrorOr<FlatPtr> Process::sys$create_inode_watcher(u32 flags)
     if (flags & static_cast<unsigned>(InodeWatcherFlags::Nonblock))
         description->set_blocking(false);
 
-    m_fds[fd_allocation.fd].set(move(description));
+    return m_fds.with([&](auto& fds) -> ErrorOr<FlatPtr> {
+        fds[fd_allocation.fd].set(move(description));
 
-    if (flags & static_cast<unsigned>(InodeWatcherFlags::CloseOnExec))
-        m_fds[fd_allocation.fd].set_flags(m_fds[fd_allocation.fd].flags() | FD_CLOEXEC);
+        if (flags & static_cast<unsigned>(InodeWatcherFlags::CloseOnExec))
+            fds[fd_allocation.fd].set_flags(fds[fd_allocation.fd].flags() | FD_CLOEXEC);
 
-    return fd_allocation.fd;
+        return fd_allocation.fd;
+    });
 }
 
 ErrorOr<FlatPtr> Process::sys$inode_watcher_add_watch(Userspace<const Syscall::SC_inode_watcher_add_watch_params*> user_params)
@@ -40,7 +42,7 @@ ErrorOr<FlatPtr> Process::sys$inode_watcher_add_watch(Userspace<const Syscall::S
     TRY(require_promise(Pledge::rpath));
     auto params = TRY(copy_typed_from_user(user_params));
 
-    auto description = TRY(fds().open_file_description(params.fd));
+    auto description = TRY(open_file_description(params.fd));
     if (!description->is_inode_watcher())
         return EBADF;
     auto* inode_watcher = description->inode_watcher();
@@ -55,7 +57,7 @@ ErrorOr<FlatPtr> Process::sys$inode_watcher_add_watch(Userspace<const Syscall::S
 ErrorOr<FlatPtr> Process::sys$inode_watcher_remove_watch(int fd, int wd)
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     if (!description->is_inode_watcher())
         return EBADF;
     TRY(description->inode_watcher()->unregister_by_wd(wd));

+ 1 - 1
Kernel/Syscalls/ioctl.cpp

@@ -14,7 +14,7 @@ namespace Kernel {
 ErrorOr<FlatPtr> Process::sys$ioctl(int fd, unsigned request, FlatPtr arg)
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     if (request == FIONBIO) {
         description->set_blocking(TRY(copy_typed_from_user(Userspace<int const*>(arg))) == 0);
         return 0;

+ 1 - 1
Kernel/Syscalls/lseek.cpp

@@ -13,7 +13,7 @@ ErrorOr<FlatPtr> Process::sys$lseek(int fd, Userspace<off_t*> userspace_offset,
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
     TRY(require_promise(Pledge::stdio));
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     off_t offset;
     TRY(copy_from_user(&offset, userspace_offset));
     auto seek_result = TRY(description->seek(offset, whence));

+ 1 - 1
Kernel/Syscalls/mmap.cpp

@@ -217,7 +217,7 @@ ErrorOr<FlatPtr> Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> use
             return EINVAL;
         if (static_cast<size_t>(offset) & ~PAGE_MASK)
             return EINVAL;
-        auto description = TRY(fds().open_file_description(fd));
+        auto description = TRY(open_file_description(fd));
         if (description->is_directory())
             return ENODEV;
         // Require read access even when read protection is not requested.

+ 1 - 1
Kernel/Syscalls/mount.cpp

@@ -32,7 +32,7 @@ ErrorOr<FlatPtr> Process::sys$mount(Userspace<const Syscall::SC_mount_params*> u
     auto fs_type_string = TRY(try_copy_kstring_from_user(params.fs_type));
     auto fs_type = fs_type_string->view();
 
-    auto description_or_error = fds().open_file_description(source_fd);
+    auto description_or_error = open_file_description(source_fd);
     if (!description_or_error.is_error())
         dbgln("mount {}: source fd {} @ {}", fs_type, source_fd, target);
     else

+ 9 - 7
Kernel/Syscalls/open.cpp

@@ -41,12 +41,12 @@ ErrorOr<FlatPtr> Process::sys$open(Userspace<const Syscall::SC_open_params*> use
 
     dbgln_if(IO_DEBUG, "sys$open(dirfd={}, path='{}', options={}, mode={})", dirfd, path->view(), options, mode);
 
-    auto fd_allocation = TRY(m_fds.allocate());
+    auto fd_allocation = TRY(allocate_fd());
     RefPtr<Custody> base;
     if (dirfd == AT_FDCWD) {
         base = current_directory();
     } else {
-        auto base_description = TRY(fds().open_file_description(dirfd));
+        auto base_description = TRY(open_file_description(dirfd));
         if (!base_description->is_directory())
             return ENOTDIR;
         if (!base_description->custody())
@@ -59,18 +59,20 @@ ErrorOr<FlatPtr> Process::sys$open(Userspace<const Syscall::SC_open_params*> use
     if (description->inode() && description->inode()->socket())
         return ENXIO;
 
-    u32 fd_flags = (options & O_CLOEXEC) ? FD_CLOEXEC : 0;
-    m_fds[fd_allocation.fd].set(move(description), fd_flags);
-    return fd_allocation.fd;
+    return m_fds.with([&](auto& fds) -> ErrorOr<FlatPtr> {
+        u32 fd_flags = (options & O_CLOEXEC) ? FD_CLOEXEC : 0;
+        fds[fd_allocation.fd].set(move(description), fd_flags);
+        return fd_allocation.fd;
+    });
 }
 
 ErrorOr<FlatPtr> Process::sys$close(int fd)
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
     TRY(require_promise(Pledge::stdio));
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     auto result = description->close();
-    m_fds[fd] = {};
+    m_fds.with([fd](auto& fds) { fds[fd] = {}; });
     if (result.is_error())
         return result.release_error();
     return 0;

+ 15 - 5
Kernel/Syscalls/pipe.cpp

@@ -13,7 +13,8 @@ ErrorOr<FlatPtr> Process::sys$pipe(int pipefd[2], int flags)
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
     TRY(require_promise(Pledge::stdio));
-    if (fds().open_count() + 2 > OpenFileDescriptions::max_open())
+    auto open_count = fds().with([](auto& fds) { return fds.open_count(); });
+    if (open_count + 2 > OpenFileDescriptions::max_open())
         return EMFILE;
     // Reject flags other than O_CLOEXEC, O_NONBLOCK
     if ((flags & (O_CLOEXEC | O_NONBLOCK)) != flags)
@@ -22,8 +23,14 @@ ErrorOr<FlatPtr> Process::sys$pipe(int pipefd[2], int flags)
     u32 fd_flags = (flags & O_CLOEXEC) ? FD_CLOEXEC : 0;
     auto fifo = TRY(FIFO::try_create(uid()));
 
-    auto reader_fd_allocation = TRY(m_fds.allocate());
-    auto writer_fd_allocation = TRY(m_fds.allocate());
+    ScopedDescriptionAllocation reader_fd_allocation;
+    ScopedDescriptionAllocation writer_fd_allocation;
+
+    TRY(m_fds.with([&](auto& fds) -> ErrorOr<void> {
+        reader_fd_allocation = TRY(fds.allocate());
+        writer_fd_allocation = TRY(fds.allocate());
+        return {};
+    }));
 
     auto reader_description = TRY(fifo->open_direction(FIFO::Direction::Reader));
     auto writer_description = TRY(fifo->open_direction(FIFO::Direction::Writer));
@@ -35,8 +42,11 @@ ErrorOr<FlatPtr> Process::sys$pipe(int pipefd[2], int flags)
         writer_description->set_blocking(false);
     }
 
-    m_fds[reader_fd_allocation.fd].set(move(reader_description), fd_flags);
-    m_fds[writer_fd_allocation.fd].set(move(writer_description), fd_flags);
+    TRY(m_fds.with([&](auto& fds) -> ErrorOr<void> {
+        fds[reader_fd_allocation.fd].set(move(reader_description), fd_flags);
+        fds[writer_fd_allocation.fd].set(move(writer_description), fd_flags);
+        return {};
+    }));
 
     TRY(copy_to_user(&pipefd[0], &reader_fd_allocation.fd));
     TRY(copy_to_user(&pipefd[1], &writer_fd_allocation.fd));

+ 1 - 1
Kernel/Syscalls/poll.cpp

@@ -49,7 +49,7 @@ ErrorOr<FlatPtr> Process::sys$poll(Userspace<const Syscall::SC_poll_params*> use
 
     for (size_t i = 0; i < params.nfds; i++) {
         auto& pfd = fds_copy[i];
-        auto description = TRY(fds().open_file_description(pfd.fd));
+        auto description = TRY(m_fds.with([&](auto& fds) { return fds.open_file_description(pfd.fd); }));
         BlockFlags block_flags = BlockFlags::Exception; // always want POLLERR, POLLHUP, POLLNVAL
         if (pfd.events & POLLIN)
             block_flags |= BlockFlags::Read;

+ 2 - 2
Kernel/Syscalls/read.cpp

@@ -12,9 +12,9 @@ namespace Kernel {
 
 using BlockFlags = Thread::FileBlocker::BlockFlags;
 
-static ErrorOr<NonnullRefPtr<OpenFileDescription>> open_readable_file_description(Process::OpenFileDescriptions const& fds, int fd)
+static ErrorOr<NonnullRefPtr<OpenFileDescription>> open_readable_file_description(auto& fds, int fd)
 {
-    auto description = TRY(fds.open_file_description(fd));
+    auto description = TRY(fds.with([&](auto& fds) { return fds.open_file_description(fd); }));
     if (!description->is_readable())
         return EBADF;
     if (description->is_directory())

+ 5 - 5
Kernel/Syscalls/sendfd.cpp

@@ -14,7 +14,7 @@ ErrorOr<FlatPtr> Process::sys$sendfd(int sockfd, int fd)
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
     TRY(require_promise(Pledge::sendfd));
-    auto socket_description = TRY(fds().open_file_description(sockfd));
+    auto socket_description = TRY(open_file_description(sockfd));
     if (!socket_description->is_socket())
         return ENOTSOCK;
     auto& socket = *socket_description->socket();
@@ -23,7 +23,7 @@ ErrorOr<FlatPtr> Process::sys$sendfd(int sockfd, int fd)
     if (!socket.is_connected())
         return ENOTCONN;
 
-    auto passing_description = TRY(fds().open_file_description(fd));
+    auto passing_description = TRY(open_file_description(fd));
     auto& local_socket = static_cast<LocalSocket&>(socket);
     TRY(local_socket.sendfd(*socket_description, move(passing_description)));
     return 0;
@@ -33,14 +33,14 @@ ErrorOr<FlatPtr> Process::sys$recvfd(int sockfd, int options)
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
     TRY(require_promise(Pledge::recvfd));
-    auto socket_description = TRY(fds().open_file_description(sockfd));
+    auto socket_description = TRY(open_file_description(sockfd));
     if (!socket_description->is_socket())
         return ENOTSOCK;
     auto& socket = *socket_description->socket();
     if (!socket.is_local())
         return EAFNOSUPPORT;
 
-    auto fd_allocation = TRY(m_fds.allocate());
+    auto fd_allocation = TRY(m_fds.with([](auto& fds) { return fds.allocate(); }));
 
     auto& local_socket = static_cast<LocalSocket&>(socket);
     auto received_description = TRY(local_socket.recvfd(*socket_description));
@@ -49,7 +49,7 @@ ErrorOr<FlatPtr> Process::sys$recvfd(int sockfd, int options)
     if (options & O_CLOEXEC)
         fd_flags |= FD_CLOEXEC;
 
-    m_fds[fd_allocation.fd].set(move(received_description), fd_flags);
+    m_fds.with([&](auto& fds) { fds[fd_allocation.fd].set(move(received_description), fd_flags); });
     return fd_allocation.fd;
 }
 

+ 70 - 49
Kernel/Syscalls/socket.cpp

@@ -19,7 +19,7 @@ namespace Kernel {
             TRY(require_promise(Pledge::unix));   \
     } while (0)
 
-void Process::setup_socket_fd(int fd, NonnullRefPtr<OpenFileDescription> description, int type)
+static void setup_socket_fd(Process::OpenFileDescriptions& fds, int fd, NonnullRefPtr<OpenFileDescription> description, int type)
 {
     description->set_readable(true);
     description->set_writable(true);
@@ -28,7 +28,7 @@ void Process::setup_socket_fd(int fd, NonnullRefPtr<OpenFileDescription> descrip
         flags |= FD_CLOEXEC;
     if (type & SOCK_NONBLOCK)
         description->set_blocking(false);
-    m_fds[fd].set(*description, flags);
+    fds[fd].set(*description, flags);
 }
 
 ErrorOr<FlatPtr> Process::sys$socket(int domain, int type, int protocol)
@@ -38,23 +38,28 @@ ErrorOr<FlatPtr> Process::sys$socket(int domain, int type, int protocol)
 
     if ((type & SOCK_TYPE_MASK) == SOCK_RAW && !is_superuser())
         return EACCES;
-    auto fd_allocation = TRY(m_fds.allocate());
-    auto socket = TRY(Socket::create(domain, type, protocol));
-    auto description = TRY(OpenFileDescription::try_create(socket));
-    setup_socket_fd(fd_allocation.fd, move(description), type);
-    return fd_allocation.fd;
+
+    return m_fds.with([&](auto& fds) -> ErrorOr<FlatPtr> {
+        auto fd_allocation = TRY(fds.allocate());
+        auto socket = TRY(Socket::create(domain, type, protocol));
+        auto description = TRY(OpenFileDescription::try_create(socket));
+        setup_socket_fd(fds, fd_allocation.fd, move(description), type);
+        return fd_allocation.fd;
+    });
 }
 
 ErrorOr<FlatPtr> Process::sys$bind(int sockfd, Userspace<const sockaddr*> address, socklen_t address_length)
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
-    auto description = TRY(fds().open_file_description(sockfd));
-    if (!description->is_socket())
-        return ENOTSOCK;
-    auto& socket = *description->socket();
-    REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
-    TRY(socket.bind(address, address_length));
-    return 0;
+    return m_fds.with([&](auto& fds) -> ErrorOr<FlatPtr> {
+        auto description = TRY(fds.open_file_description(sockfd));
+        if (!description->is_socket())
+            return ENOTSOCK;
+        auto& socket = *description->socket();
+        REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
+        TRY(socket.bind(address, address_length));
+        return 0;
+    });
 }
 
 ErrorOr<FlatPtr> Process::sys$listen(int sockfd, int backlog)
@@ -62,15 +67,17 @@ ErrorOr<FlatPtr> Process::sys$listen(int sockfd, int backlog)
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
     if (backlog < 0)
         return EINVAL;
-    auto description = TRY(fds().open_file_description(sockfd));
-    if (!description->is_socket())
-        return ENOTSOCK;
-    auto& socket = *description->socket();
-    REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
-    if (socket.is_connected())
-        return EINVAL;
-    TRY(socket.listen(backlog));
-    return 0;
+    return m_fds.with([&](auto& fds) -> ErrorOr<FlatPtr> {
+        auto description = TRY(fds.open_file_description(sockfd));
+        if (!description->is_socket())
+            return ENOTSOCK;
+        auto& socket = *description->socket();
+        REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
+        if (socket.is_connected())
+            return EINVAL;
+        TRY(socket.listen(backlog));
+        return 0;
+    });
 }
 
 ErrorOr<FlatPtr> Process::sys$accept4(Userspace<const Syscall::SC_accept4_params*> user_params)
@@ -89,8 +96,14 @@ ErrorOr<FlatPtr> Process::sys$accept4(Userspace<const Syscall::SC_accept4_params
         TRY(copy_from_user(&address_size, static_ptr_cast<const socklen_t*>(user_address_size)));
     }
 
-    auto fd_allocation = TRY(m_fds.allocate());
-    auto accepting_socket_description = TRY(fds().open_file_description(accepting_socket_fd));
+    ScopedDescriptionAllocation fd_allocation;
+    RefPtr<OpenFileDescription> accepting_socket_description;
+
+    TRY(m_fds.with([&](auto& fds) -> ErrorOr<void> {
+        fd_allocation = TRY(fds.allocate());
+        accepting_socket_description = TRY(fds.open_file_description(accepting_socket_fd));
+        return {};
+    }));
     if (!accepting_socket_description->is_socket())
         return ENOTSOCK;
     auto& socket = *accepting_socket_description->socket();
@@ -124,7 +137,11 @@ ErrorOr<FlatPtr> Process::sys$accept4(Userspace<const Syscall::SC_accept4_params
     int fd_flags = 0;
     if (flags & SOCK_CLOEXEC)
         fd_flags |= FD_CLOEXEC;
-    m_fds[fd_allocation.fd].set(move(accepted_socket_description), fd_flags);
+
+    TRY(m_fds.with([&](auto& fds) -> ErrorOr<void> {
+        fds[fd_allocation.fd].set(move(accepted_socket_description), fd_flags);
+        return {};
+    }));
 
     // NOTE: Moving this state to Completed is what causes connect() to unblock on the client side.
     accepted_socket->set_setup_state(Socket::SetupState::Completed);
@@ -134,7 +151,8 @@ ErrorOr<FlatPtr> Process::sys$accept4(Userspace<const Syscall::SC_accept4_params
 ErrorOr<FlatPtr> Process::sys$connect(int sockfd, Userspace<const sockaddr*> user_address, socklen_t user_address_size)
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
-    auto description = TRY(fds().open_file_description(sockfd));
+
+    auto description = TRY(open_file_description(sockfd));
     if (!description->is_socket())
         return ENOTSOCK;
     auto& socket = *description->socket();
@@ -149,7 +167,7 @@ ErrorOr<FlatPtr> Process::sys$shutdown(int sockfd, int how)
     TRY(require_promise(Pledge::stdio));
     if (how & ~SHUT_RDWR)
         return EINVAL;
-    auto description = TRY(fds().open_file_description(sockfd));
+    auto description = TRY(open_file_description(sockfd));
     if (!description->is_socket())
         return ENOTSOCK;
     auto& socket = *description->socket();
@@ -175,7 +193,7 @@ ErrorOr<FlatPtr> Process::sys$sendmsg(int sockfd, Userspace<const struct msghdr*
     Userspace<const sockaddr*> user_addr((FlatPtr)msg.msg_name);
     socklen_t addr_length = msg.msg_namelen;
 
-    auto description = TRY(fds().open_file_description(sockfd));
+    auto description = TRY(open_file_description(sockfd));
     if (!description->is_socket())
         return ENOTSOCK;
     auto& socket = *description->socket();
@@ -203,7 +221,7 @@ ErrorOr<FlatPtr> Process::sys$recvmsg(int sockfd, Userspace<struct msghdr*> user
     Userspace<sockaddr*> user_addr((FlatPtr)msg.msg_name);
     Userspace<socklen_t*> user_addr_length(msg.msg_name ? (FlatPtr)&user_msg.unsafe_userspace_ptr()->msg_namelen : 0);
 
-    auto description = TRY(fds().open_file_description(sockfd));
+    auto description = TRY(open_file_description(sockfd));
     if (!description->is_socket())
         return ENOTSOCK;
     auto& socket = *description->socket();
@@ -259,7 +277,7 @@ ErrorOr<void> Process::get_sock_or_peer_name(const Params& params)
     if (addrlen_value <= 0)
         return EINVAL;
 
-    auto description = TRY(fds().open_file_description(params.sockfd));
+    auto description = TRY(open_file_description(params.sockfd));
     if (!description->is_socket())
         return ENOTSOCK;
 
@@ -306,7 +324,7 @@ ErrorOr<FlatPtr> Process::sys$getsockopt(Userspace<const Syscall::SC_getsockopt_
     socklen_t value_size;
     TRY(copy_from_user(&value_size, params.value_size, sizeof(socklen_t)));
 
-    auto description = TRY(fds().open_file_description(sockfd));
+    auto description = TRY(open_file_description(sockfd));
     if (!description->is_socket())
         return ENOTSOCK;
     auto& socket = *description->socket();
@@ -321,7 +339,7 @@ ErrorOr<FlatPtr> Process::sys$setsockopt(Userspace<const Syscall::SC_setsockopt_
     auto params = TRY(copy_typed_from_user(user_params));
 
     Userspace<const void*> user_value((FlatPtr)params.value);
-    auto description = TRY(fds().open_file_description(params.sockfd));
+    auto description = TRY(open_file_description(params.sockfd));
     if (!description->is_socket())
         return ENOTSOCK;
     auto& socket = *description->socket();
@@ -343,21 +361,24 @@ ErrorOr<FlatPtr> Process::sys$socketpair(Userspace<const Syscall::SC_socketpair_
 
     auto pair = TRY(LocalSocket::try_create_connected_pair(params.type & SOCK_TYPE_MASK));
 
-    auto fd_allocation0 = TRY(m_fds.allocate());
-    auto fd_allocation1 = TRY(m_fds.allocate());
-
-    int fds[2];
-    fds[0] = fd_allocation0.fd;
-    fds[1] = fd_allocation1.fd;
-    setup_socket_fd(fds[0], pair.description0, params.type);
-    setup_socket_fd(fds[1], pair.description1, params.type);
-
-    if (copy_to_user(params.sv, fds, sizeof(fds)).is_error()) {
-        // Avoid leaking both file descriptors on error.
-        m_fds[fds[0]] = {};
-        m_fds[fds[1]] = {};
-        return EFAULT;
-    }
-    return 0;
+    return m_fds.with([&](auto& fds) -> ErrorOr<FlatPtr> {
+        auto fd_allocation0 = TRY(fds.allocate());
+        auto fd_allocation1 = TRY(fds.allocate());
+
+        int allocated_fds[2];
+        allocated_fds[0] = fd_allocation0.fd;
+        allocated_fds[1] = fd_allocation1.fd;
+        setup_socket_fd(fds, allocated_fds[0], pair.description0, params.type);
+        setup_socket_fd(fds, allocated_fds[1], pair.description1, params.type);
+
+        if (copy_to_user(params.sv, allocated_fds, sizeof(allocated_fds)).is_error()) {
+            // Avoid leaking both file descriptors on error.
+            fds[allocated_fds[0]] = {};
+            fds[allocated_fds[1]] = {};
+            return EFAULT;
+        }
+        return 0;
+    });
 }
+
 }

+ 2 - 2
Kernel/Syscalls/stat.cpp

@@ -15,7 +15,7 @@ ErrorOr<FlatPtr> Process::sys$fstat(int fd, Userspace<stat*> user_statbuf)
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
     TRY(require_promise(Pledge::stdio));
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     auto buffer = TRY(description->stat());
     TRY(copy_to_user(user_statbuf, &buffer));
     return 0;
@@ -33,7 +33,7 @@ ErrorOr<FlatPtr> Process::sys$stat(Userspace<const Syscall::SC_stat_params*> use
     if (params.dirfd == AT_FDCWD) {
         base = current_directory();
     } else {
-        auto base_description = TRY(fds().open_file_description(params.dirfd));
+        auto base_description = TRY(open_file_description(params.dirfd));
         if (!base_description->is_directory())
             return ENOTDIR;
         if (!base_description->custody())

+ 1 - 1
Kernel/Syscalls/statvfs.cpp

@@ -57,7 +57,7 @@ ErrorOr<FlatPtr> Process::sys$fstatvfs(int fd, statvfs* buf)
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
     TRY(require_promise(Pledge::stdio));
 
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     auto const* inode = description->inode();
     if (inode == nullptr)
         return ENOENT;

+ 2 - 2
Kernel/Syscalls/ttyname.cpp

@@ -15,7 +15,7 @@ ErrorOr<FlatPtr> Process::sys$ttyname(int fd, Userspace<char*> buffer, size_t si
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
     TRY(require_promise(Pledge::tty));
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     if (!description->is_tty())
         return ENOTTY;
     auto const& tty_name = description->tty()->tty_name();
@@ -29,7 +29,7 @@ ErrorOr<FlatPtr> Process::sys$ptsname(int fd, Userspace<char*> buffer, size_t si
 {
     VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
     TRY(require_promise(Pledge::tty));
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     auto* master_pty = description->master_pty();
     if (!master_pty)
         return ENOTTY;

+ 2 - 2
Kernel/Syscalls/write.cpp

@@ -32,7 +32,7 @@ ErrorOr<FlatPtr> Process::sys$writev(int fd, Userspace<const struct iovec*> iov,
             return EINVAL;
     }
 
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     if (!description->is_writable())
         return EBADF;
 
@@ -97,7 +97,7 @@ ErrorOr<FlatPtr> Process::sys$write(int fd, Userspace<const u8*> data, size_t si
         return EINVAL;
 
     dbgln_if(IO_DEBUG, "sys$write({}, {}, {})", fd, data.ptr(), size);
-    auto description = TRY(fds().open_file_description(fd));
+    auto description = TRY(open_file_description(fd));
     if (!description->is_writable())
         return EBADF;