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
This commit is contained in:
@@ -5,13 +5,17 @@
|
|||||||
#include <kernel/Memory/ByteRingBuffer.h>
|
#include <kernel/Memory/ByteRingBuffer.h>
|
||||||
#include <kernel/ThreadBlocker.h>
|
#include <kernel/ThreadBlocker.h>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
class Pipe : public Inode
|
class Pipe : public Inode, public BAN::Weakable<Pipe>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<BAN::RefPtr<Inode>> create(const Credentials&);
|
static BAN::ErrorOr<BAN::RefPtr<Inode>> open(BAN::RefPtr<Inode>, int status_flags);
|
||||||
|
static BAN::ErrorOr<BAN::RefPtr<Inode>> create(uid_t, gid_t);
|
||||||
|
~Pipe();
|
||||||
|
|
||||||
void on_close(int status_flags) override;
|
void on_close(int status_flags) override;
|
||||||
void on_clone(int status_flags) override;
|
void on_clone(int status_flags) override;
|
||||||
@@ -31,7 +35,7 @@ namespace Kernel
|
|||||||
virtual BAN::ErrorOr<long> ioctl_impl(int, void*) override;
|
virtual BAN::ErrorOr<long> ioctl_impl(int, void*) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Pipe(const Credentials&);
|
Pipe(const struct stat&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Mutex m_mutex;
|
Mutex m_mutex;
|
||||||
@@ -39,8 +43,10 @@ namespace Kernel
|
|||||||
|
|
||||||
BAN::UniqPtr<ByteRingBuffer> m_buffer;
|
BAN::UniqPtr<ByteRingBuffer> m_buffer;
|
||||||
|
|
||||||
BAN::Atomic<uint32_t> m_writing_count { 1 };
|
BAN::Atomic<uint32_t> m_writing_count { 0 };
|
||||||
BAN::Atomic<uint32_t> m_reading_count { 1 };
|
BAN::Atomic<uint32_t> m_reading_count { 0 };
|
||||||
|
|
||||||
|
BAN::RefPtr<Inode> m_named_inode;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <BAN/HashMap.h>
|
||||||
#include <kernel/FS/Pipe.h>
|
#include <kernel/FS/Pipe.h>
|
||||||
#include <kernel/Lock/LockGuard.h>
|
#include <kernel/Lock/LockGuard.h>
|
||||||
#include <kernel/Thread.h>
|
#include <kernel/Thread.h>
|
||||||
@@ -12,34 +13,124 @@ namespace Kernel
|
|||||||
|
|
||||||
static constexpr size_t s_pipe_buffer_size = 0x10000;
|
static constexpr size_t s_pipe_buffer_size = 0x10000;
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::RefPtr<Inode>> Pipe::create(const Credentials& credentials)
|
static Mutex s_named_pipe_mutex;
|
||||||
|
static BAN::HashMap<BAN::RefPtr<Inode>, BAN::WeakPtr<Pipe>> s_named_pipes;
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::RefPtr<Inode>> Pipe::open(BAN::RefPtr<Inode> inode, int status_flags)
|
||||||
{
|
{
|
||||||
auto* pipe_ptr = new Pipe(credentials);
|
BAN::RefPtr<Pipe> 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<Pipe>::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<Inode>(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<Inode>(pipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::RefPtr<Inode>> 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)
|
if (pipe_ptr == nullptr)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
auto pipe = BAN::RefPtr<Pipe>::adopt(pipe_ptr);
|
auto pipe = BAN::RefPtr<Pipe>::adopt(pipe_ptr);
|
||||||
pipe->m_buffer = TRY(ByteRingBuffer::create(s_pipe_buffer_size));
|
pipe->m_buffer = TRY(ByteRingBuffer::create(s_pipe_buffer_size));
|
||||||
|
pipe->m_reading_count++;
|
||||||
|
pipe->m_writing_count++;
|
||||||
return BAN::RefPtr<Inode>(pipe);
|
return BAN::RefPtr<Inode>(pipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pipe::Pipe(const Credentials& credentials)
|
Pipe::Pipe(const struct stat& st)
|
||||||
{
|
{
|
||||||
timespec current_time = SystemTimer::get().real_time();
|
m_ino = st.st_ino;
|
||||||
m_atime = current_time;
|
m_mode = st.st_mode;
|
||||||
m_mtime = current_time;
|
m_nlink = st.st_nlink;
|
||||||
m_ctime = current_time;
|
m_uid = st.st_uid;
|
||||||
m_uid = credentials.euid();
|
m_gid = st.st_gid;
|
||||||
m_gid = credentials.egid();
|
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_kind |= InodeKind::PIPE;
|
||||||
m_mode = { Mode::IFIFO | Mode::IRUSR | Mode::IWUSR };
|
}
|
||||||
m_nlink = 1;
|
|
||||||
m_size = 0;
|
Pipe::~Pipe()
|
||||||
m_blksize = 4096;
|
{
|
||||||
m_blocks = 0;
|
if (!m_named_inode)
|
||||||
m_dev = 0; // FIXME
|
return;
|
||||||
m_rdev = 0; // FIXME
|
LockGuard _(s_named_pipe_mutex);
|
||||||
m_kind = InodeKind::PIPE;
|
s_named_pipes.remove(m_named_inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pipe::on_clone(int status_flags)
|
void Pipe::on_clone(int status_flags)
|
||||||
|
|||||||
@@ -85,6 +85,9 @@ namespace Kernel
|
|||||||
|
|
||||||
constexpr int status_mask = O_APPEND | O_DSYNC | O_NONBLOCK | O_RSYNC | O_SYNC | O_ACCMODE;
|
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);
|
LockGuard _(m_mutex);
|
||||||
|
|
||||||
const int fd = TRY(get_free_fd());
|
const int fd = TRY(get_free_fd());
|
||||||
@@ -214,7 +217,7 @@ namespace Kernel
|
|||||||
|
|
||||||
TRY(get_free_fd_pair(fds));
|
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<OpenFileDescription>::create(VirtualFileSystem::File(pipe, "<pipe rd>"_sv), 0, O_RDONLY));
|
m_open_files[fds[0]] = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(pipe, "<pipe rd>"_sv), 0, O_RDONLY));
|
||||||
m_open_files[fds[1]] = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(pipe, "<pipe wr>"_sv), 0, O_WRONLY));
|
m_open_files[fds[1]] = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(pipe, "<pipe wr>"_sv), 0, O_WRONLY));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user