diff --git a/include/seastar/core/reactor.hh b/include/seastar/core/reactor.hh index 4d3d992eaa..8d63b8b3f2 100644 --- a/include/seastar/core/reactor.hh +++ b/include/seastar/core/reactor.hh @@ -487,6 +487,7 @@ public: return file_accessible(pathname, access_flags::exists); } future file_system_at(std::string_view pathname) noexcept; + future file_system_space(std::string_view pathname) noexcept; future statvfs(std::string_view pathname) noexcept; future<> remove_file(std::string_view pathname) noexcept; future<> rename_file(std::string_view old_pathname, std::string_view new_pathname) noexcept; diff --git a/include/seastar/core/seastar.hh b/include/seastar/core/seastar.hh index e5431de841..73d32a8cd3 100644 --- a/include/seastar/core/seastar.hh +++ b/include/seastar/core/seastar.hh @@ -445,6 +445,11 @@ future fs_avail(std::string_view name) noexcept; future fs_free(std::string_view name) noexcept; /// @} +/// Return filesystem-wide space_info where a file is located. +/// +/// \param name name of the file in the filesystem to inspect +future file_system_space(std::string_view name) noexcept; + namespace experimental { /// \defgroup interprocess-module Interprocess Communication /// diff --git a/src/core/reactor.cc b/src/core/reactor.cc index ac33906b6d..d8e189c756 100644 --- a/src/core/reactor.cc +++ b/src/core/reactor.cc @@ -2263,6 +2263,17 @@ reactor::fstatfs(int fd) noexcept { }); } +future +reactor::file_system_space(std::string_view pathname) noexcept { + auto sr = co_await _thread_pool->submit>([path = std::filesystem::path(pathname)] { + std::error_code ec; + auto si = std::filesystem::space(path, ec); + return wrap_syscall(ec.value(), si); + }); + sr.throw_fs_exception_if_error("std::filesystem::space failed", sstring(pathname)); + co_return sr.extra; +} + future reactor::statvfs(std::string_view pathname) noexcept { // Allocating memory for a sstring can throw, hence the futurize_invoke diff --git a/src/util/file.cc b/src/util/file.cc index 58d62428aa..d280860ad7 100644 --- a/src/util/file.cc +++ b/src/util/file.cc @@ -128,6 +128,10 @@ future fs_free(std::string_view name) noexcept { }); } +future file_system_space(std::string_view name) noexcept { + return engine().file_system_space(name); +} + future file_stat(std::string_view name, follow_symlink follow) noexcept { return engine().file_stat(name, follow); } diff --git a/tests/unit/file_io_test.cc b/tests/unit/file_io_test.cc index 29be2a670a..3bce589bf3 100644 --- a/tests/unit/file_io_test.cc +++ b/tests/unit/file_io_test.cc @@ -19,11 +19,14 @@ * Copyright (C) 2014-2015 Cloudius Systems, Ltd. */ +#include + #include #include #include #include +#include #include #include #include @@ -947,3 +950,16 @@ SEASTAR_TEST_CASE(test_oversized_io_works) { BOOST_REQUIRE((size_t)std::count_if(buf.get(), buf.get() + buf_size, [](auto x) { return x == 'a'; }) == buf_size); }); } + +SEASTAR_TEST_CASE(test_file_system_space) { + return tmp_dir::do_with_thread([] (tmp_dir& t) { + const auto& name = t.get_path().native(); + auto st = engine().statvfs(name).get(); + auto si = file_system_space(name).get(); + + BOOST_REQUIRE_EQUAL(st.f_blocks * st.f_frsize, si.capacity); + BOOST_REQUIRE_LT(si.free, si.capacity); + BOOST_REQUIRE_LT(si.available, si.capacity); + BOOST_REQUIRE_LE(si.available, si.free); + }); +}