From f6475a290600ef07c4dcbd48ed8351a1cce51dff Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Mon, 24 Aug 2020 08:49:41 -0700 Subject: [PATCH] ircd::fs: Add interface to mmap fd. --- include/ircd/fs/fs.h | 1 + include/ircd/fs/map.h | 57 +++++++++++++++++++ ircd/fs.cc | 126 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 include/ircd/fs/map.h diff --git a/include/ircd/fs/fs.h b/include/ircd/fs/fs.h index c45da294d..eaba1f1f0 100644 --- a/include/ircd/fs/fs.h +++ b/include/ircd/fs/fs.h @@ -47,6 +47,7 @@ namespace ircd::fs #include "opts.h" #include "dev.h" #include "fd.h" +#include "map.h" #include "wait.h" #include "read.h" #include "write.h" diff --git a/include/ircd/fs/map.h b/include/ircd/fs/map.h new file mode 100644 index 000000000..cfa0a3a13 --- /dev/null +++ b/include/ircd/fs/map.h @@ -0,0 +1,57 @@ +// The Construct +// +// Copyright (C) The Construct Developers, Authors & Contributors +// Copyright (C) 2016-2020 Jason Volk +// +// 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_MAP_H + +namespace ircd::fs +{ + struct map; +} + +/// Interface to map file into memory. +/// +/// Note that this was created specifically for file maps and not intended to +/// be a generic mmap(2) interface, at least for now. +struct ircd::fs::map +:mutable_buffer +{ + struct opts; + + map() = default; + map(const fd &, const opts &opts, const size_t &size = 0UL); + map(map &&) noexcept; + map(const map &) = delete; + map &operator=(map &&) noexcept; + map &operator=(const map &) = delete; + ~map() noexcept; +}; + +/// Descriptor options (open options) +struct ircd::fs::map::opts +:fd::opts +{ + bool execute {false}; + bool shared {false}; + bool reserve {false}; + bool populate {false}; + + opts(const fd::opts &opts = {std::ios::in}) + :fd::opts(opts) + {} +}; + +inline +ircd::fs::map::map(map &&other) +noexcept +:mutable_buffer{other} +{ + static_cast(other) = {}; +} diff --git a/ircd/fs.cc b/ircd/fs.cc index a05d38b45..b2af08b9a 100644 --- a/ircd/fs.cc +++ b/ircd/fs.cc @@ -1730,6 +1730,132 @@ noexcept } #endif +/////////////////////////////////////////////////////////////////////////////// +// +// fs/map.h +// + +namespace ircd::fs +{ + static uint flags(const map::opts &); + static uint prot(const map::opts &); +} + +ircd::fs::map::map(const fd &fd, + const opts &opts, + const size_t &size) +{ + const auto map_size + { + size?: fs::size(fd) + }; + + void *const &ptr + { + ::mmap(nullptr, map_size, prot(opts), flags(opts), int(fd), opts.offset) + }; + + if(unlikely(ptr == MAP_FAILED)) + throw_system_error(errno); + + static_cast(*this) = mutable_buffer + { + reinterpret_cast(ptr), + map_size + }; +} + +ircd::fs::map::~map() +noexcept try +{ + if(mutable_buffer::null()) + return; + + syscall(::munmap, data(*this), size(*this)); +} +catch(const std::exception &e) +{ + log::critical + { + log, "munmap(%p, %zu) :%s", + data(static_cast(*this)), + size(static_cast(*this)), + e.what(), + }; +} + +ircd::fs::map & +ircd::fs::map::operator=(map &&other) +noexcept +{ + auto &ours + { + static_cast(*this) + }; + + auto &theirs + { + static_cast(other) + }; + + this->~map(); + ours = theirs; + theirs = {}; + return *this; +} + +uint +ircd::fs::prot(const map::opts &opts) +{ + uint ret + { + PROT_NONE + }; + + if(opts.mode & std::ios::in) + ret |= PROT_READ; + + if(opts.mode & std::ios::out) + ret |= PROT_WRITE; + + assert(!opts.execute); + if((false) && opts.execute) + ret |= PROT_EXEC; + + return ret; +} + +uint +ircd::fs::flags(const map::opts &opts) +{ + uint ret + { + 0 + }; + + if(opts.shared) + ret |= MAP_SHARED; + else + ret |= MAP_PRIVATE; + + #if defined(MAP_NONBLOCK) + if(!opts.blocking) + ret |= MAP_NONBLOCK; + #endif + + #if defined(MAP_POPULATE) + if(opts.populate) + ret |= MAP_POPULATE; + #endif + + #if defined(MAP_NORESERVE) + if(!opts.reserve) + ret |= MAP_NORESERVE; + #endif + + return ret; +} + /////////////////////////////////////////////////////////////////////////////// // // fs/fd.h