From deb2f52a3566d9d068b6c0b3e74709c1c6d4bb11 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 19 May 2026 00:06:01 +0300 Subject: [PATCH] Kernel: Add support for named pipes These only copy inodes stat when created, if you fchmod/fchown a named pipe, the change will not be visible on the filesystem --- kernel/include/kernel/FS/Pipe.h | 16 ++- kernel/kernel/FS/Pipe.cpp | 127 ++++++++++++++++++++---- kernel/kernel/OpenFileDescriptorSet.cpp | 5 +- 3 files changed, 124 insertions(+), 24 deletions(-) diff --git a/kernel/include/kernel/FS/Pipe.h b/kernel/include/kernel/FS/Pipe.h index 2ee840c5..3ebdc2b0 100644 --- a/kernel/include/kernel/FS/Pipe.h +++ b/kernel/include/kernel/FS/Pipe.h @@ -5,13 +5,17 @@ #include #include +#include + namespace Kernel { - class Pipe : public Inode + class Pipe : public Inode, public BAN::Weakable { public: - static BAN::ErrorOr> create(const Credentials&); + static BAN::ErrorOr> open(BAN::RefPtr, int status_flags); + static BAN::ErrorOr> create(uid_t, gid_t); + ~Pipe(); void on_close(int status_flags) override; void on_clone(int status_flags) override; @@ -31,7 +35,7 @@ namespace Kernel virtual BAN::ErrorOr ioctl_impl(int, void*) override; private: - Pipe(const Credentials&); + Pipe(const struct stat&); private: Mutex m_mutex; @@ -39,8 +43,10 @@ namespace Kernel BAN::UniqPtr m_buffer; - BAN::Atomic m_writing_count { 1 }; - BAN::Atomic m_reading_count { 1 }; + BAN::Atomic m_writing_count { 0 }; + BAN::Atomic m_reading_count { 0 }; + + BAN::RefPtr m_named_inode; }; } diff --git a/kernel/kernel/FS/Pipe.cpp b/kernel/kernel/FS/Pipe.cpp index 1bacf307..9576e6b7 100644 --- a/kernel/kernel/FS/Pipe.cpp +++ b/kernel/kernel/FS/Pipe.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -12,34 +13,124 @@ namespace Kernel static constexpr size_t s_pipe_buffer_size = 0x10000; - BAN::ErrorOr> Pipe::create(const Credentials& credentials) + static Mutex s_named_pipe_mutex; + static BAN::HashMap, BAN::WeakPtr> s_named_pipes; + + BAN::ErrorOr> Pipe::open(BAN::RefPtr inode, int status_flags) { - auto* pipe_ptr = new Pipe(credentials); + BAN::RefPtr pipe; + + { + LockGuard _(s_named_pipe_mutex); + + auto it = s_named_pipes.find(inode); + if (it == s_named_pipes.end()) + it = TRY(s_named_pipes.insert(inode, {})); + + if (!(pipe = it->value.lock())) + { + // FIXME: these should probably reference the underlying inode(?) + const struct stat st { + .st_dev = inode->dev(), + .st_ino = inode->ino(), + .st_mode = inode->mode().mode, + .st_nlink = inode->nlink(), + .st_uid = inode->uid(), + .st_gid = inode->gid(), + .st_rdev = inode->rdev(), + .st_size = inode->size(), + .st_atim = inode->atime(), + .st_mtim = inode->mtime(), + .st_ctim = inode->ctime(), + .st_blksize = inode->blksize(), + .st_blocks = inode->blocks(), + }; + + auto* pipe_ptr = new Pipe(st); + if (pipe_ptr == nullptr) + return BAN::Error::from_errno(ENOMEM); + pipe = BAN::RefPtr::adopt(pipe_ptr); + pipe->m_buffer = TRY(ByteRingBuffer::create(s_pipe_buffer_size)); + pipe->m_named_inode = inode; + + it->value = TRY(pipe->get_weak_ptr()); + } + } + + LockGuard _(pipe->m_mutex); + + if (status_flags & O_RDONLY) + pipe->m_reading_count++; + if (status_flags & O_WRONLY) + pipe->m_writing_count++; + + if (status_flags & O_NONBLOCK) + { + if ((status_flags & O_WRONLY) && pipe->m_writing_count == 0) + return BAN::Error::from_errno(ENXIO); + return BAN::RefPtr(pipe); + } + + auto& block_value = (status_flags & O_WRONLY) ? pipe->m_reading_count : pipe->m_writing_count; + while (block_value == 0) + TRY(Thread::current().block_or_eintr_indefinite(pipe->m_thread_blocker, &pipe->m_mutex)); + return BAN::RefPtr(pipe); + } + + BAN::ErrorOr> Pipe::create(uid_t uid, gid_t gid) + { + const timespec current_time = SystemTimer::get().real_time(); + const struct stat st { + .st_dev = 0, // FIXME + .st_ino = 0, // FIXME + .st_mode = Mode::IFIFO | Mode::IRUSR | Mode::IWUSR, + .st_nlink = 0, + .st_uid = uid, + .st_gid = gid, + .st_rdev = 0, // FIXME + .st_size = 0, + .st_atim = current_time, + .st_mtim = current_time, + .st_ctim = current_time, + .st_blksize = PAGE_SIZE, + .st_blocks = 0, + }; + + auto* pipe_ptr = new Pipe(st); if (pipe_ptr == nullptr) return BAN::Error::from_errno(ENOMEM); auto pipe = BAN::RefPtr::adopt(pipe_ptr); pipe->m_buffer = TRY(ByteRingBuffer::create(s_pipe_buffer_size)); + pipe->m_reading_count++; + pipe->m_writing_count++; return BAN::RefPtr(pipe); } - Pipe::Pipe(const Credentials& credentials) + Pipe::Pipe(const struct stat& st) { - timespec current_time = SystemTimer::get().real_time(); - m_atime = current_time; - m_mtime = current_time; - m_ctime = current_time; - m_uid = credentials.euid(); - m_gid = credentials.egid(); + m_ino = st.st_ino; + m_mode = st.st_mode; + m_nlink = st.st_nlink; + m_uid = st.st_uid; + m_gid = st.st_gid; + m_size = st.st_size; + m_atime = st.st_atim; + m_mtime = st.st_mtim; + m_ctime = st.st_ctim; + m_blksize = st.st_blksize; + m_blocks = st.st_blocks; + m_dev = st.st_dev; + m_rdev = st.st_rdev; - m_ino = 0; // FIXME - m_mode = { Mode::IFIFO | Mode::IRUSR | Mode::IWUSR }; - m_nlink = 1; - m_size = 0; - m_blksize = 4096; - m_blocks = 0; - m_dev = 0; // FIXME - m_rdev = 0; // FIXME - m_kind = InodeKind::PIPE; + m_kind |= InodeKind::PIPE; + } + + Pipe::~Pipe() + { + if (!m_named_inode) + return; + LockGuard _(s_named_pipe_mutex); + s_named_pipes.remove(m_named_inode); } void Pipe::on_clone(int status_flags) diff --git a/kernel/kernel/OpenFileDescriptorSet.cpp b/kernel/kernel/OpenFileDescriptorSet.cpp index ec57d051..df04424c 100644 --- a/kernel/kernel/OpenFileDescriptorSet.cpp +++ b/kernel/kernel/OpenFileDescriptorSet.cpp @@ -85,6 +85,9 @@ namespace Kernel constexpr int status_mask = O_APPEND | O_DSYNC | O_NONBLOCK | O_RSYNC | O_SYNC | O_ACCMODE; + if (file.inode->mode().ififo()) + file.inode = TRY(Pipe::open(file.inode, flags & status_mask)); + LockGuard _(m_mutex); const int fd = TRY(get_free_fd()); @@ -214,7 +217,7 @@ namespace Kernel TRY(get_free_fd_pair(fds)); - auto pipe = TRY(Pipe::create(m_credentials)); + auto pipe = TRY(Pipe::create(m_credentials.euid(), m_credentials.egid())); m_open_files[fds[0]] = TRY(BAN::RefPtr::create(VirtualFileSystem::File(pipe, ""_sv), 0, O_RDONLY)); m_open_files[fds[1]] = TRY(BAN::RefPtr::create(VirtualFileSystem::File(pipe, ""_sv), 0, O_WRONLY));