Skip to content

Commit

Permalink
file: add file_system_space
Browse files Browse the repository at this point in the history
Return space_info for the filesystem identified
by the given file name.

space_info provides simpler and standard space information
about the filesystem, in contrast to the posix statvfs
which requires knowledge about the how to convert
f_block to bytes by multiplying by f_frsize.

Signed-off-by: Benny Halevy <[email protected]>
  • Loading branch information
bhalevy committed Dec 23, 2024
1 parent 613d8b3 commit c59710c
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 0 deletions.
13 changes: 13 additions & 0 deletions include/seastar/core/file-types.hh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#pragma once

#ifndef SEASTAR_MODULE
#include <cstdint>
#include <fcntl.h>
#include <sys/stat.h>
#include <type_traits>
Expand Down Expand Up @@ -158,6 +159,18 @@ inline constexpr file_permissions operator&(file_permissions a, file_permissions
return file_permissions(std::underlying_type_t<file_permissions>(a) & std::underlying_type_t<file_permissions>(b));
}

/// seastar::space_info is equivalent to std::filesystem::space_info
/// with renamed members, to prevent a conflict with future::available()
struct space_info {
std::uintmax_t capacity;
std::uintmax_t free_space;
std::uintmax_t available_space;

bool operator==(const space_info& o) const noexcept {
return capacity == o.capacity && free_space == o.free_space && available_space == o.available_space;
}
};

/// @}

SEASTAR_MODULE_EXPORT_END
Expand Down
1 change: 1 addition & 0 deletions include/seastar/core/reactor.hh
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ public:
return file_accessible(pathname, access_flags::exists);
}
future<fs_type> file_system_at(std::string_view pathname) noexcept;
future<space_info> file_system_space(std::string_view pathname) noexcept;
future<struct statvfs> 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;
Expand Down
5 changes: 5 additions & 0 deletions include/seastar/core/seastar.hh
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,11 @@ future<uint64_t> fs_avail(std::string_view name) noexcept;
future<uint64_t> fs_free(std::string_view name) noexcept;
/// @}

/// Return filesystem-wide stat where a file is located.
///
/// \param name name of the file to inspect
future<space_info> file_system_space(std::string_view name) noexcept;

namespace experimental {
/// \defgroup interprocess-module Interprocess Communication
///
Expand Down
20 changes: 20 additions & 0 deletions src/core/reactor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2263,6 +2263,26 @@ reactor::fstatfs(int fd) noexcept {
});
}

future<space_info>
reactor::file_system_space(std::string_view pathname) noexcept {
// Allocating memory for a filesystem::path can throw, hence the futurize_invoke
return futurize_invoke([this, pathname] {
return _thread_pool->submit<syscall_result_extra<std::filesystem::space_info>>([path = std::filesystem::path(pathname)] {
std::error_code ec;
auto si = std::filesystem::space(path, ec);
return wrap_syscall(ec.value(), si);
}).then([pathname = sstring(pathname)] (syscall_result_extra<std::filesystem::space_info> sr) {
sr.throw_fs_exception_if_error("file_system_space failed", pathname);
auto& fs_si = sr.extra;
return space_info{
.capacity = fs_si.capacity,
.free_space = fs_si.free,
.available_space = fs_si.available
};
});
});
}

future<struct statvfs>
reactor::statvfs(std::string_view pathname) noexcept {
// Allocating memory for a sstring can throw, hence the futurize_invoke
Expand Down
4 changes: 4 additions & 0 deletions src/util/file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ future<uint64_t> fs_free(std::string_view name) noexcept {
});
}

future<space_info> file_system_space(std::string_view name) noexcept {
return engine().file_system_space(name);
}

future<stat_data> file_stat(std::string_view name, follow_symlink follow) noexcept {
return engine().file_stat(name, follow);
}
Expand Down
20 changes: 20 additions & 0 deletions tests/unit/file_io_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@
* Copyright (C) 2014-2015 Cloudius Systems, Ltd.
*/

#include <filesystem>

#include <seastar/testing/random.hh>
#include <seastar/testing/test_case.hh>
#include <seastar/testing/thread_test_case.hh>
#include <seastar/testing/test_runner.hh>

#include <seastar/core/reactor.hh>
#include <seastar/core/seastar.hh>
#include <seastar/core/semaphore.hh>
#include <seastar/core/condition-variable.hh>
Expand Down Expand Up @@ -947,3 +950,20 @@ 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();
struct statvfs st;
space_info si, si1;
do {
si = file_system_space(name).get();
st = engine().statvfs(name).get();
si1 = file_system_space(name).get();
} while (si1 != si);

BOOST_REQUIRE_EQUAL(st.f_blocks * st.f_frsize, si.capacity);
BOOST_REQUIRE_EQUAL(st.f_bfree * st.f_frsize, si.free_space);
BOOST_REQUIRE_EQUAL(st.f_bavail * st.f_frsize, si.available_space);
});
}

0 comments on commit c59710c

Please sign in to comment.