From 900fab1e79ef6e158254803d859a44400d178536 Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Sat, 20 Apr 2019 18:23:52 -0700 Subject: [PATCH] ircd::fs: Propagate EAGAIN without exception for !opts.blocking operations. --- ircd/fs.cc | 86 ++++++++++++++++++++++++++++++++++++++------------ ircd/fs_aio.cc | 7 +++- 2 files changed, 71 insertions(+), 22 deletions(-) diff --git a/ircd/fs.cc b/ircd/fs.cc index 0ad9b78ef..e5a854fcc 100644 --- a/ircd/fs.cc +++ b/ircd/fs.cc @@ -702,14 +702,23 @@ ircd::fs::_read(const fd &fd, flags(opts) }; - const auto ret + ssize_t ret; do { - opts.interruptible? - syscall(::preadv2, fd, iov.data(), iov.size(), opts.offset, flags_): - syscall_nointr(::preadv2, fd, iov.data(), iov.size(), opts.offset, flags_) - }; + ret = ::preadv2(int(fd), iov.data(), iov.size(), opts.offset, flags_); + } + while(!opts.interruptible && unlikely(ret == -1 && errno == EINTR)); - return size_t(ret); + static_assert(EAGAIN == EWOULDBLOCK); + if(!opts.blocking && ret == -1 && errno == EAGAIN) + return 0UL; + + if(unlikely(ret == -1)) + throw std::system_error + { + errno, std::system_category() + }; + + return ret; } #else size_t @@ -717,14 +726,23 @@ ircd::fs::_read(const fd &fd, const const_iovec_view &iov, const read_opts &opts) { - const auto ret + ssize_t ret; do { - opts.interruptible? - syscall(::preadv, fd, iov.data(), iov.size(), opts.offset): - syscall_nointr(::preadv, fd, iov.data(), iov.size(), opts.offset) - }; + ret = ::preadv(int(fd), iov.data(), iov.size(), opts.offset); + } + while(!opts.interruptible && unlikely(ret == -1 && errno == EINTR)); - return size_t(ret); + static_assert(EAGAIN == EWOULDBLOCK); + if(unlikely(!opts.blocking && ret == -1 && errno == EAGAIN)) + return 0UL; + + if(unlikely(ret == -1)) + throw std::system_error + { + errno, std::system_category() + }; + + return ret; } #endif // HAVE_PREADV2 @@ -1050,7 +1068,7 @@ ircd::fs::write(const fd &fd, while(opts.all && opts_.offset >= 0 && off < buffers::size(bufs)); assert(opts.offset >= opts_.offset); assert(ssize_t(off) == opts.offset - opts_.offset); - assert(!opts.all || off == buffers::size(bufs)); + assert(!opts.all || !opts.blocking || off == buffers::size(bufs)); return off; } #pragma GCC diagnostic pop @@ -1099,10 +1117,23 @@ ircd::fs::_write__pwritev1(const fd &fd, const const_iovec_view &iov, const write_opts &opts) { - return - opts.interruptible? - syscall(::pwritev, fd, iov.data(), iov.size(), opts.offset): - syscall_nointr(::pwritev, fd, iov.data(), iov.size(), opts.offset); + ssize_t ret; do + { + ret = ::pwritev(int(fd), iov.data(), iov.size(), opts.offset); + } + while(!opts.interruptible && unlikely(ret == -1 && errno == EINTR)); + + static_assert(EAGAIN == EWOULDBLOCK); + if(unlikely(!opts.blocking && ret == -1 && errno == EAGAIN)) + return 0UL; + + if(unlikely(ret == -1)) + throw std::system_error + { + errno, std::system_category() + }; + + return ret; } #ifdef HAVE_PWRITEV2 @@ -1124,10 +1155,23 @@ ircd::fs::_write__pwritev2(const fd &fd, flags(opts) }; - return - opts.interruptible? - syscall(::pwritev2, fd, iov.data(), iov.size(), offset, flags_): - syscall_nointr(::pwritev2, fd, iov.data(), iov.size(), offset, flags_); + ssize_t ret; do + { + ret = ::pwritev2(int(fd), iov.data(), iov.size(), opts.offset, flags_); + } + while(!opts.interruptible && unlikely(ret == -1 && errno == EINTR)); + + static_assert(EAGAIN == EWOULDBLOCK); + if(!opts.blocking && ret == -1 && errno == EAGAIN) + return 0UL; + + if(unlikely(ret == -1)) + throw std::system_error + { + errno, std::system_category() + }; + + return ret; } #else size_t diff --git a/ircd/fs_aio.cc b/ircd/fs_aio.cc index 6a4a59bd6..27eea980c 100644 --- a/ircd/fs_aio.cc +++ b/ircd/fs_aio.cc @@ -279,7 +279,7 @@ ircd::fs::aio::write(const fd &fd, }; // Does linux ever not complete all bytes for an AIO? - assert(bytes == req_bytes); + assert(!opts.blocking || bytes == req_bytes); stats.bytes_write += bytes; stats.writes++; @@ -411,6 +411,11 @@ ircd::fs::aio::request::operator()() if(likely(retval != -1)) return size_t(retval); + assert(opts); + static_assert(EAGAIN == EWOULDBLOCK); + if(!opts->blocking && retval == -1 && errcode == EAGAIN) + return 0UL; + stats.errors++; stats.bytes_errors += submitted_bytes; thread_local char errbuf[512]; fmt::sprintf