diff options
-rw-r--r-- | src/InodeCache.cpp | 45 | ||||
-rw-r--r-- | src/InodeCache.hpp | 6 |
2 files changed, 41 insertions, 10 deletions
diff --git a/src/InodeCache.cpp b/src/InodeCache.cpp index e6245fa6..17e92417 100644 --- a/src/InodeCache.cpp +++ b/src/InodeCache.cpp @@ -20,7 +20,6 @@ #include "Config.hpp" #include "Digest.hpp" -#include "Fd.hpp" #include "Finalizer.hpp" #include "Hash.hpp" #include "Logging.hpp" @@ -29,8 +28,6 @@ #include "Util.hpp" #include "fmtmacros.hpp" -#include <util/TimePoint.hpp> - #include <fcntl.h> #include <libgen.h> #include <sched.h> @@ -78,6 +75,14 @@ const uint32_t k_num_entries = 4; // Maximum time the spin lock loop will try before giving up. const auto k_max_lock_duration = util::Duration(5); +// The memory-mapped file may reside on a filesystem with compression. Memory +// accesses to the file risk crashing if such a filesystem gets full, so stop +// using the inode cache well before this happens. +const uint64_t k_min_fs_mib_left = 100; // 100 MiB + +// How long a filesystem space check is valid before we make a new one. +const util::Duration k_fs_space_check_valid_duration(1); + static_assert(Digest::size() == 20, "Increment version number if size of digest is changed."); static_assert(std::is_trivially_copyable<Digest>::value, @@ -229,17 +234,21 @@ InodeCache::mmap_file(const std::string& inode_cache_file) munmap(m_sr, sizeof(SharedRegion)); m_sr = nullptr; } - Fd fd(open(inode_cache_file.c_str(), O_RDWR)); - if (!fd) { + m_fd = Fd(open(inode_cache_file.c_str(), O_RDWR)); + if (!m_fd) { LOG("Failed to open inode cache {}: {}", inode_cache_file, strerror(errno)); return false; } - if (!fd_is_on_known_to_work_file_system(*fd)) { + if (!fd_is_on_known_to_work_file_system(*m_fd)) { return false; } - SharedRegion* sr = reinterpret_cast<SharedRegion*>(mmap( - nullptr, sizeof(SharedRegion), PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0)); - fd.close(); + SharedRegion* sr = + reinterpret_cast<SharedRegion*>(mmap(nullptr, + sizeof(SharedRegion), + PROT_READ | PROT_WRITE, + MAP_SHARED, + *m_fd, + 0)); if (sr == MMAP_FAILED) { LOG("Failed to mmap {}: {}", inode_cache_file, strerror(errno)); return false; @@ -387,6 +396,24 @@ InodeCache::initialize() return false; } + if (m_fd) { + auto now = util::TimePoint::now(); + if (now > m_last_fs_space_check + k_fs_space_check_valid_duration) { + m_last_fs_space_check = now; + + struct statfs buf; + if (fstatfs(*m_fd, &buf) != 0) { + LOG("fstatfs failed: {}", strerror(errno)); + return false; + } + if (buf.f_bavail * 512 < k_min_fs_mib_left * 1024 * 1024) { + LOG("Filesystem has less than {} MiB free space, not using inode cache", + k_min_fs_mib_left); + return false; + } + } + } + if (m_sr) { return true; } diff --git a/src/InodeCache.hpp b/src/InodeCache.hpp index c4e8c4ea..5819ed07 100644 --- a/src/InodeCache.hpp +++ b/src/InodeCache.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2022 Joel Rosdahl and other contributors +// Copyright (C) 2020-2023 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -18,7 +18,9 @@ #pragma once +#include <Fd.hpp> #include <util/Duration.hpp> +#include <util/TimePoint.hpp> #include <cstdint> #include <functional> @@ -130,7 +132,9 @@ private: const Config& m_config; util::Duration m_min_age; + Fd m_fd; struct SharedRegion* m_sr = nullptr; bool m_failed = false; const pid_t m_self_pid; + util::TimePoint m_last_fs_space_check; }; |