fix(dwarfs): limit number of chunks in inodeinfo xattr

Highly fragmented files would have *megabytes* in `inodeinfo`, which
not only breaks the xattr interface, but can also dramatically slow
down tools like `eza` who like to read xattrs for no apparent reason.
This commit is contained in:
Marcus Holland-Moritz 2024-08-19 17:13:03 +02:00
parent e803efebe6
commit a8cf283d4e
5 changed files with 33 additions and 14 deletions

View File

@ -320,6 +320,10 @@ class filesystem_v2 {
return impl_->get_inode_info(entry);
}
nlohmann::json get_inode_info(inode_view entry, size_t max_chunks) const {
return impl_->get_inode_info(entry, max_chunks);
}
std::vector<std::string> get_all_block_categories() const {
return impl_->get_all_block_categories();
}
@ -426,6 +430,8 @@ class filesystem_v2 {
virtual bool has_symlinks() const = 0;
virtual history const& get_history() const = 0;
virtual nlohmann::json get_inode_info(inode_view entry) const = 0;
virtual nlohmann::json
get_inode_info(inode_view entry, size_t max_chunks) const = 0;
virtual std::vector<std::string> get_all_block_categories() const = 0;
virtual std::vector<file_stat::uid_type> get_all_uids() const = 0;
virtual std::vector<file_stat::gid_type> get_all_gids() const = 0;

View File

@ -151,8 +151,8 @@ class metadata_v2 {
bool has_symlinks() const { return impl_->has_symlinks(); }
nlohmann::json get_inode_info(inode_view iv) const {
return impl_->get_inode_info(iv);
nlohmann::json get_inode_info(inode_view iv, size_t max_chunks) const {
return impl_->get_inode_info(iv, max_chunks);
}
std::optional<std::string> get_block_category(size_t block_number) const {
@ -229,7 +229,8 @@ class metadata_v2 {
virtual bool has_symlinks() const = 0;
virtual nlohmann::json get_inode_info(inode_view iv) const = 0;
virtual nlohmann::json
get_inode_info(inode_view iv, size_t max_chunks) const = 0;
virtual std::optional<std::string>
get_block_category(size_t block_number) const = 0;

View File

@ -290,7 +290,11 @@ class filesystem_ final : public filesystem_v2::impl {
bool has_symlinks() const override { return meta_.has_symlinks(); }
history const& get_history() const override { return history_; }
nlohmann::json get_inode_info(inode_view entry) const override {
return meta_.get_inode_info(entry);
return meta_.get_inode_info(entry, std::numeric_limits<size_t>::max());
}
nlohmann::json
get_inode_info(inode_view entry, size_t max_chunks) const override {
return meta_.get_inode_info(entry, max_chunks);
}
std::vector<std::string> get_all_block_categories() const override {
return meta_.get_all_block_categories();

View File

@ -529,7 +529,8 @@ class metadata_ final : public metadata_v2::impl {
bool has_symlinks() const override { return !meta_.symlink_table().empty(); }
nlohmann::json get_inode_info(inode_view iv) const override;
nlohmann::json
get_inode_info(inode_view iv, size_t max_chunks) const override;
std::optional<std::string>
get_block_category(size_t block_number) const override;
@ -1844,7 +1845,9 @@ metadata_<LoggerPolicy>::get_chunks(int inode, std::error_code& ec) const {
}
template <typename LoggerPolicy>
nlohmann::json metadata_<LoggerPolicy>::get_inode_info(inode_view iv) const {
nlohmann::json
metadata_<LoggerPolicy>::get_inode_info(inode_view iv,
size_t max_chunks) const {
nlohmann::json obj;
if (iv.is_regular_file()) {
@ -1854,16 +1857,20 @@ nlohmann::json metadata_<LoggerPolicy>::get_inode_info(inode_view iv) const {
DWARFS_CHECK(!ec, fmt::format("get_chunk_range({}): {}", iv.inode_num(),
ec.message()));
for (auto const& chunk : chunk_range) {
nlohmann::json& chk = obj["chunks"].emplace_back();
if (chunk_range.size() <= max_chunks) {
for (auto const& chunk : chunk_range) {
nlohmann::json& chk = obj["chunks"].emplace_back();
chk["block"] = chunk.block();
chk["offset"] = chunk.offset();
chk["size"] = chunk.size();
chk["block"] = chunk.block();
chk["offset"] = chunk.offset();
chk["size"] = chunk.size();
if (auto catname = get_block_category(chunk.block())) {
chk["category"] = catname.value();
if (auto catname = get_block_category(chunk.block())) {
chk["category"] = catname.value();
}
}
} else {
obj["chunks"] = fmt::format("too many chunks ({})", chunk_range.size());
}
}

View File

@ -149,6 +149,7 @@ namespace {
constexpr size_t const kDefaultBlockSize{static_cast<size_t>(512) << 10};
constexpr size_t const kDefaultSeqDetectorThreshold{4};
constexpr size_t const kMaxInodeInfoChunks{8};
struct options {
// std::string isn't standard-layout on MSVC
@ -952,7 +953,7 @@ int op_getxattr_common(LogProxy& log_, dwarfs_userdata& userdata,
}
if (name == inodeinfo_xattr) {
oss << userdata.fs.get_inode_info(*entry) << "\n";
oss << userdata.fs.get_inode_info(*entry, kMaxInodeInfoChunks) << "\n";
}
value = oss.str();