ircd::fs: Remove fs::iou.

This commit is contained in:
Jason Volk 2022-09-03 20:29:41 -07:00
parent ffac5de052
commit dcbeb3fd4a
8 changed files with 2 additions and 868 deletions

View File

@ -33,7 +33,6 @@ const char *recoverdb;
bool nojs;
bool nodirect;
bool noaio;
bool noiou;
bool no6;
bool yes6;
bool norun;
@ -70,7 +69,6 @@ lgetopt opts[]
{ "nojs", &nojs, lgetopt::BOOL, "Disable SpiderMonkey JS subsystem from initializing. (noop when not available)" },
{ "nodirect", &nodirect, lgetopt::BOOL, "Disable direct IO (O_DIRECT) for unsupporting filesystems" },
{ "noaio", &noaio, lgetopt::BOOL, "Disable the AIO interface in favor of traditional syscalls. " },
{ "noiou", &noiou, lgetopt::BOOL, "Disable the io_uring interface and fallback to AIO or system calls. " },
{ "no6", &no6, lgetopt::BOOL, "Disable IPv6 operations (default)" },
{ "6", &yes6, lgetopt::BOOL, "Enable IPv6 operations" },
{ "norun", &norun, lgetopt::BOOL, "[debug] Initialize but never run the event loop" },
@ -621,9 +619,6 @@ applyargs()
if(noaio)
ircd::fs::aio::enable.set("false");
if(noiou)
ircd::fs::iou::enable.set("false");
if(yes6)
ircd::net::enable_ipv6.set("true");
else if(no6)

View File

@ -45,7 +45,6 @@ namespace ircd::fs
#include "write.h"
#include "sync.h"
#include "aio.h"
#include "iou.h"
#include "select.h"
#include "stdin.h"
#include "support.h"
@ -73,7 +72,6 @@ namespace ircd::fs
struct [[gnu::visibility("hidden")]]
ircd::fs::init
{
iou::init _iou_;
aio::init _aio_;
init();

View File

@ -1,97 +0,0 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_IRCD_FS_IOU_H
// Public and unconditional interface for io_uring. This file is part of the
// standard include stack and available whether or not this platform is Linux
// with io_uring (>= 5.1), and whether or not it's enabled, etc. If it is not
// most of this stuff does nothing and will have null values.
extern "C"
{
struct io_uring_sqe;
}
/// Input/Output Userspace Ring buffering.
///
/// Note that fs::aio and fs::iou are never used simultaneously. If io_uring
/// is supported by both the compilation and the kernel at runtime then it
/// will be selected over AIO.
namespace ircd::fs::iou
{
struct init;
struct system;
struct request;
enum state :uint8_t;
// a priori
extern const bool support;
extern const size_t MAX_EVENTS;
// configuration
extern conf::item<bool> enable;
extern conf::item<size_t> max_events;
extern conf::item<size_t> max_submit;
// runtime state
extern struct aio::stats &stats;
extern struct system *system;
// util
string_view reflect(const state &);
const_iovec_view iovec(const request &);
const struct ::io_uring_sqe &sqe(const request &);
struct ::io_uring_sqe &sqe(request &);
// iterate requests
static bool for_each(const state &, const std::function<bool (const request &)> &);
static bool for_each(const std::function<bool (const request &)> &);
// count requests
static size_t count(const state &, const op &);
static size_t count(const state &);
static size_t count(const op &);
}
struct ircd::fs::iou::request
{
const fs::opts *opts {nullptr};
fs::op op {fs::op::NOOP};
std::error_code ec;
int32_t res {-1};
int32_t id {-1};
request() = default;
request(const fd &, const const_iovec_view &, const fs::opts *const &);
~request() noexcept;
};
/// Enumeration of states for a request.
enum ircd::fs::iou::state
:uint8_t
{
INVALID,
QUEUED,
SUBMITTED,
COMPLETED,
_NUM
};
/// Internal use; this is simply declared here for when internal headers are
/// not available for this build so a weak no-op definition can be defined.
struct [[gnu::visibility("hidden")]]
ircd::fs::iou::init
{
init();
~init() noexcept;
};

View File

@ -204,9 +204,6 @@ libircd_la_SOURCES += fs_dev.cc
if AIO
libircd_la_SOURCES += fs_aio.cc
endif
if IOU
libircd_la_SOURCES += fs_iou.cc
endif
libircd_la_SOURCES += sys.cc
libircd_la_SOURCES += mods.cc
if LINUX
@ -320,9 +317,6 @@ fs_path.lo: AM_CPPFLAGS := ${AM_CPPFLAGS} ${ASIO_UNIT_CPPFLAGS}
if AIO
fs_aio.lo: AM_CPPFLAGS := ${AM_CPPFLAGS} ${ASIO_UNIT_CPPFLAGS}
endif
if IOU
fs_iou.lo: AM_CPPFLAGS := ${AM_CPPFLAGS} ${ASIO_UNIT_CPPFLAGS}
endif
gpt_cpu.lo: AM_CXXFLAGS := ${AM_CXXFLAGS} ${GPT_FP_CXXFLAGS}
http.lo: AM_CPPFLAGS := ${AM_CPPFLAGS} ${SPIRIT_UNIT_CPPFLAGS}
http.lo: AM_CXXFLAGS := ${AM_CXXFLAGS} ${SPIRIT_UNIT_CXXFLAGS}

View File

@ -18,14 +18,6 @@
#include "fs_aio.h"
#endif
#if IRCD_USE_IOU > 0
#include "fs_iou.h"
#endif
// TODO: prevents use until io_uring support implemented
#undef IRCD_USE_IOU
#define IRCD_USE_IOU 0
namespace ircd::fs
{
extern conf::item<ulong> rlimit_nofile;
@ -71,7 +63,7 @@ ircd::fs::init_dump_info()
{
const bool support_async
{
false || iou::system || aio::system
false || aio::system
};
if(!support_async)
@ -236,7 +228,7 @@ ircd::fs::support::aio
void
ircd::fs::support::dump_info()
{
#if IRCD_USE_AIO || IRCD_USE_IOU
#if IRCD_USE_AIO
const bool support_async {true};
#else
const bool support_async {false};
@ -730,10 +722,6 @@ ircd::fs::flush(const fd &fd,
{
assert(opts.op == op::SYNC);
if constexpr(IRCD_USE_IOU)
if(iou::system && opts.aio)
return void(iou::fsync(fd, opts));
if constexpr(IRCD_USE_AIO)
if(aio::system && opts.aio)
{
@ -989,10 +977,6 @@ ircd::fs::_read(const fd &fd,
{
assert(opts.op == op::READ);
if constexpr(IRCD_USE_IOU)
if(likely(iou::system && opts.aio))
return iou::read(fd, iov, opts);
if constexpr(IRCD_USE_AIO)
if(likely(aio::system && opts.aio))
return aio::read(fd, iov, opts);
@ -1368,10 +1352,6 @@ ircd::fs::_write(const fd &fd,
{
assert(opts.op == op::WRITE);
if constexpr(IRCD_USE_IOU)
if(likely(iou::system && opts.aio))
return iou::write(fd, iov, opts);
if constexpr(IRCD_USE_AIO)
if(likely(aio::system && opts.aio))
return aio::write(fd, iov, opts);
@ -1822,60 +1802,6 @@ ircd::fs::aio::stats::stats()
assert(items <= (sizeof(value) / sizeof(value[0])));
}
///////////////////////////////////////////////////////////////////////////////
//
// fs/iou.h
//
decltype(ircd::fs::iou::support)
ircd::fs::iou::support
{
IRCD_USE_IOU &&
(info::kernel_version[0] > 5 ||
(info::kernel_version[0] >= 5 && info::kernel_version[1] >= 1))
};
/// Conf item to control whether iou is enabled or bypassed.
decltype(ircd::fs::iou::enable)
ircd::fs::iou::enable
{
{ "name", "ircd.fs.iou.enable" },
{ "default", false },
{ "persist", false },
};
/// Global stats structure
decltype(ircd::fs::iou::stats)
ircd::fs::iou::stats
{
fs::aio::stats
};
/// Non-null when iou is available for use
decltype(ircd::fs::iou::system)
ircd::fs::iou::system;
//
// init
//
#if IRCD_USE_IOU == 0
[[gnu::weak]]
ircd::fs::iou::init::init()
{
assert(!system);
}
#endif
#if IRCD_USE_IOU == 0
[[gnu::weak]]
ircd::fs::iou::init::~init()
noexcept
{
assert(!system);
}
#endif
///////////////////////////////////////////////////////////////////////////////
//
// fs/map.h
@ -2666,15 +2592,6 @@ ircd::fs::aio::translate(const int &val)
}
#endif
#if IRCD_USE_IOU == 0
[[gnu::weak]]
ircd::fs::op
ircd::fs::iou::translate(const int &val)
{
return op::NOOP;
}
#endif
///////////////////////////////////////////////////////////////////////////////
//
// fs/iov.h

View File

@ -82,13 +82,6 @@ ircd::fs::aio::submit_coalesce
ircd::fs::aio::init::init()
{
// Don't init AIO if the io_uring is established. If it is, that means it
// was supported by the build, this kernel, and didn't encounter an error
// to construct. In all other cases AIO can serve as a fallback.
if constexpr(IRCD_USE_IOU)
if(iou::system)
return;
assert(!system);
if(!aio::enable)
return;

View File

@ -1,604 +0,0 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#include <sys/syscall.h>
#include <sys/eventfd.h>
#include "fs_iou.h"
decltype(ircd::fs::iou::MAX_EVENTS)
ircd::fs::iou::MAX_EVENTS
{
128L //TODO: get this info
};
decltype(ircd::fs::iou::max_events)
ircd::fs::iou::max_events
{
{ "name", "ircd.fs.iou.max_events" },
{ "default", long(iou::MAX_EVENTS) },
{ "persist", false },
};
decltype(ircd::fs::iou::max_submit)
ircd::fs::iou::max_submit
{
{ "name", "ircd.fs.iou.max_submit" },
{ "default", 0L },
{ "persist", false },
};
//
// init
//
ircd::fs::iou::init::init()
{
assert(!system);
if(!iou::enable)
return;
system = new struct iou::system
(
size_t(max_events),
size_t(max_submit)
);
}
[[gnu::cold]]
ircd::fs::iou::init::~init()
noexcept
{
delete system;
system = nullptr;
}
///////////////////////////////////////////////////////////////////////////////
//
// ircd/fs/op.h
//
// The contents of this section override weak symbols in ircd/fs.cc when this
// unit is conditionally compiled and linked on IOU-supporting platforms.
ircd::fs::op
ircd::fs::iou::translate(const int &val)
{
switch(val)
{
case IORING_OP_NOP: return op::NOOP;
case IORING_OP_READV: return op::READ;
case IORING_OP_WRITEV: return op::WRITE;
case IORING_OP_FSYNC: return op::SYNC;
case IORING_OP_READ_FIXED: return op::READ;
case IORING_OP_WRITE_FIXED: return op::WRITE;
case IORING_OP_POLL_ADD: return op::NOOP;
case IORING_OP_POLL_REMOVE: return op::NOOP;
case IORING_OP_SYNC_FILE_RANGE: return op::SYNC;
}
return op::NOOP;
}
///////////////////////////////////////////////////////////////////////////////
//
// fs/iou.h
//
size_t
ircd::fs::iou::count(const op &op)
{
return 0;
}
size_t
ircd::fs::iou::count(const state &state)
{
return 0;
}
size_t
ircd::fs::iou::count(const state &state,
const op &op)
{
return 0;
}
bool
ircd::fs::iou::for_each(const state &state,
const std::function<bool (const request &)> &closure)
{
assert(system);
return true;
}
bool
ircd::fs::iou::for_each(const std::function<bool (const request &)> &closure)
{
assert(system);
return true;
}
struct ::io_uring_sqe &
ircd::fs::iou::sqe(request &request)
{
assert(system);
::io_uring_sqe *const ret
{
nullptr
};
if(request.id < 0)
throw std::out_of_range
{
"request has no entry on the submit queue."
};
assert(ret);
return *ret;
}
const struct ::io_uring_sqe &
ircd::fs::iou::sqe(const request &request)
{
assert(system);
const ::io_uring_sqe *const ret
{
nullptr
};
if(request.id < 0)
throw std::out_of_range
{
"request has no entry on the submit queue."
};
assert(ret);
return *ret;
}
ircd::string_view
ircd::fs::iou::reflect(const state &s)
{
switch(s)
{
case state::INVALID: return "INVALID";
case state::QUEUED: return "QUEUED";
case state::SUBMITTED: return "SUBMITTED";
case state::COMPLETED: return "COMPLETED";
case state::_NUM: break;
}
return "?????";
}
ircd::fs::const_iovec_view
ircd::fs::iou::iovec(const request &request)
{
return
{
//reinterpret_cast<const ::iovec *>(iou_buf), iou_nbytes
};
}
//
// request::request
//
ircd::fs::iou::request::request(const fs::fd &fd,
const const_iovec_view &iov,
const fs::opts *const &opts)
:opts
{
opts
}
,op
{
fs::op::NOOP
}
{
}
ircd::fs::iou::request::~request()
noexcept
{
}
//
// system::system
//
ircd::fs::iou::system::system(const size_t &max_events,
const size_t &max_submit)
try
:p
{
0
}
,fd
{
int(syscall<__NR_io_uring_setup>(max_events, &p))
}
,sq_len
{
p.sq_off.array + p.sq_entries * sizeof(uint32_t)
}
,cq_len
{
p.cq_off.cqes + p.cq_entries * sizeof(::io_uring_cqe)
}
,sqe_len
{
p.sq_entries * sizeof(::io_uring_sqe)
}
,sq_p
{
[this]
{
static const auto prot(PROT_READ | PROT_WRITE);
static const auto flags(MAP_SHARED | MAP_POPULATE);
void *const &map
{
::mmap(NULL, sq_len, prot, flags, fd, IORING_OFF_SQ_RING)
};
if(unlikely(map == MAP_FAILED))
{
throw_system_error(errno);
__builtin_unreachable();
}
return reinterpret_cast<uint8_t *>(map);
}(),
[this](uint8_t *const ptr)
{
syscall(::munmap, ptr, sq_len);
}
}
,cq_p
{
[this]
{
static const auto prot(PROT_READ | PROT_WRITE);
static const auto flags(MAP_SHARED | MAP_POPULATE);
void *const &map
{
::mmap(NULL, cq_len, prot, flags, fd, IORING_OFF_CQ_RING)
};
if(unlikely(map == MAP_FAILED))
{
throw_system_error(errno);
__builtin_unreachable();
}
return reinterpret_cast<uint8_t *>(map);
}(),
[this](uint8_t *const ptr)
{
syscall(::munmap, ptr, cq_len);
}
}
,sqe_p
{
[this]
{
static const auto prot(PROT_READ | PROT_WRITE);
static const auto flags(MAP_SHARED | MAP_POPULATE);
void *const &map
{
::mmap(NULL, sqe_len, prot, flags, fd, IORING_OFF_SQES)
};
if(unlikely(map == MAP_FAILED))
{
throw_system_error(errno);
__builtin_unreachable();
}
return reinterpret_cast<uint8_t *>(map);
}(),
[this](uint8_t *const ptr)
{
syscall(::munmap, ptr, sqe_len);
}
}
,head
{
reinterpret_cast<uint32_t *>(sq_p.get() + p.sq_off.head),
reinterpret_cast<uint32_t *>(cq_p.get() + p.cq_off.head),
}
,tail
{
reinterpret_cast<uint32_t *>(sq_p.get() + p.sq_off.tail),
reinterpret_cast<uint32_t *>(cq_p.get() + p.cq_off.tail),
}
,ring_mask
{
reinterpret_cast<uint32_t *>(sq_p.get() + p.sq_off.ring_mask),
reinterpret_cast<uint32_t *>(cq_p.get() + p.cq_off.ring_mask),
}
,ring_entries
{
reinterpret_cast<uint32_t *>(sq_p.get() + p.sq_off.ring_entries),
reinterpret_cast<uint32_t *>(cq_p.get() + p.cq_off.ring_entries),
}
,flags
{
reinterpret_cast<uint32_t *>(sq_p.get() + p.sq_off.flags),
nullptr
}
,dropped
{
reinterpret_cast<uint32_t *>(sq_p.get() + p.sq_off.dropped),
nullptr
}
,overflow
{
nullptr,
reinterpret_cast<uint32_t *>(cq_p.get() + p.cq_off.overflow),
}
,sq
{
reinterpret_cast<uint32_t *>(sq_p.get() + p.sq_off.array)
}
,sqe
{
reinterpret_cast<::io_uring_sqe *>(sqe_p.get())
}
,cqe
{
reinterpret_cast<::io_uring_cqe *>(cq_p.get() + p.cq_off.cqes)
}
,ev_count
{
0
}
,ev_fd
{
ios::get(), int(syscall(::eventfd, ev_count, EFD_CLOEXEC | EFD_NONBLOCK))
}
,handle_set
{
false
}
,handle_size
{
0
}
{
log::debug
{
log, "io_uring sq_entries:%u cq_entries:%u flags:%u sq_thread_cpu:%u sq_thread_idle:%u",
p.sq_entries,
p.cq_entries,
p.flags,
p.sq_thread_cpu,
p.sq_thread_idle,
};
log::debug
{
log, "io_uring maps sq:%p len:%zu sqe:%p len:%zu cq:%p len:%zu",
sq_p.get(),
sq_len,
sqe_p.get(),
sqe_len,
cq_p.get(),
cq_len,
};
log::debug
{
log, "io_sqring head:%u tail:%u ring_mask:%u ring_entries:%u flags:%u dropped:%u array:%u map:%p len:%zu",
p.sq_off.head,
p.sq_off.tail,
p.sq_off.ring_mask,
p.sq_off.ring_entries,
p.sq_off.flags,
p.sq_off.dropped,
p.sq_off.array,
sq_p.get(),
sq_len,
};
log::debug
{
log, "io_cqring head:%u tail:%u ring_mask:%u ring_entries:%u overflow:%u cqes:%u map:%p len:%zu",
p.cq_off.head,
p.cq_off.tail,
p.cq_off.ring_mask,
p.cq_off.ring_entries,
p.cq_off.overflow,
p.cq_off.cqes,
cq_p.get(),
cq_len,
};
assert(0);
}
catch(const std::exception &e)
{
log::error
{
log, "Error starting iou context %p :%s",
(const void *)this,
e.what()
};
}
ircd::fs::iou::system::~system()
noexcept try
{
const ctx::uninterruptible::nothrow ui;
interrupt();
wait();
boost::system::error_code ec;
ev_fd.close(ec);
}
catch(const std::exception &e)
{
log::critical
{
log, "Error shutting down iou context %p :%s",
(const void *)this,
e.what()
};
}
bool
ircd::fs::iou::system::interrupt()
{
if(!ev_fd.is_open())
return false;
if(handle_set)
ev_fd.cancel();
else
ev_count = -1;
return true;
}
bool
ircd::fs::iou::system::wait()
{
if(!ev_fd.is_open())
return false;
log::debug
{
log, "Waiting for iou context %p", this
};
dock.wait([this]() noexcept
{
return ev_count == uint64_t(-1);
});
return true;
}
void
ircd::fs::iou::system::set_handle()
try
{
assert(!handle_set);
handle_set = true;
ev_count = 0;
const asio::mutable_buffers_1 bufs
{
&ev_count, sizeof(ev_count)
};
auto handler
{
std::bind(&system::handle, this, ph::_1, ph::_2)
};
ev_fd.async_read_some(bufs, ios::handle(handle_descriptor, std::move(handler)));
}
catch(...)
{
handle_set = false;
throw;
}
[[clang::always_destroy]]
decltype(ircd::fs::iou::system::handle_descriptor)
ircd::fs::iou::system::handle_descriptor
{
"ircd.fs.iou.sigfd",
// allocator; custom allocation strategy because this handler
// appears to excessively allocate and deallocate 120 bytes; this
// is a simple asynchronous operation, we can do better (and perhaps
// even better than this below).
[](ios::handler &handler, const size_t &size) -> void *
{
assert(ircd::fs::iou::system);
auto &system(*ircd::fs::iou::system);
if(unlikely(!system.handle_data))
{
system.handle_size = size;
system.handle_data = std::make_unique<uint8_t[]>(size);
}
assert(system.handle_size == size);
return system.handle_data.get();
},
// no deallocation; satisfied by class member unique_ptr
[](ios::handler &handler, void *const &ptr, const size_t &size) -> void {}
};
/// Handle notifications that requests are complete.
void
ircd::fs::iou::system::handle(const boost::system::error_code &ec,
const size_t bytes)
noexcept try
{
namespace errc = boost::system::errc;
assert((bytes == 8 && !ec && ev_count >= 1) || (bytes == 0 && ec));
assert(!ec || ec.category() == asio::error::get_system_category());
assert(handle_set);
handle_set = false;
switch(ec.value())
{
case errc::success:
handle_events();
break;
case errc::interrupted:
break;
case errc::operation_canceled:
throw ctx::interrupted();
__builtin_unreachable();
default:
throw_system_error(ec);
__builtin_unreachable();
}
set_handle();
}
catch(const ctx::interrupted &)
{
log::debug
{
log, "iou context %p interrupted", this
};
ev_count = -1;
dock.notify_all();
}
void
ircd::fs::iou::system::handle_events()
noexcept try
{
assert(!ctx::current);
}
catch(const std::exception &e)
{
log::error
{
log, "iou(%p) handle_events: %s",
this,
e.what()
};
}

View File

@ -1,62 +0,0 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_FS_IOU_H
#include <linux/io_uring.h>
#pragma GCC visibility push(hidden)
namespace ircd::fs::iou
{
size_t write(const fd &, const const_iovec_view &, const write_opts &);
size_t read(const fd &, const const_iovec_view &, const read_opts &);
void fsync(const fd &, const sync_opts &);
}
#pragma GCC visibility pop
struct [[gnu::visibility("hidden")]]
ircd::fs::iou::system
{
ctx::dock dock;
::io_uring_params p;
fs::fd fd;
size_t sq_len, cq_len, sqe_len;
custom_ptr<uint8_t> sq_p, cq_p, sqe_p;
uint32_t *head[2];
uint32_t *tail[2];
uint32_t *ring_mask[2];
uint32_t *ring_entries[2];
uint32_t *flags[2];
uint32_t *dropped[2];
uint32_t *overflow[2];
uint32_t *sq;
::io_uring_sqe *sqe;
::io_uring_cqe *cqe;
size_t ev_count;
asio::posix::stream_descriptor ev_fd;
bool handle_set;
size_t handle_size;
std::unique_ptr<uint8_t[]> handle_data;
static ios::descriptor handle_descriptor;
void handle_events() noexcept;
void handle(const boost::system::error_code &ec, const size_t bytes) noexcept;
void set_handle();
bool interrupt();
bool wait();
system(const size_t &max_events,
const size_t &max_submit);
~system() noexcept;
};