mirror of
https://github.com/Zygo/bees.git
synced 2025-05-17 21:35:45 +02:00
fs: support LOGICAL_INO_V2
Automatically fall back to LOGICAL_INO if LOGICAL_INO_V2 fails and no _V2 flags are used. Add methods to set the flags argument with build portability to older headers. Use thread_local storage for the somewhat large buffers used by LOGICAL_INO_V2 (and other users of BtrfsDataContainer like INO_PATHS). Signed-off-by: Zygo Blaxell <bees@furryterror.org>
This commit is contained in:
parent
c2762740ef
commit
8cbd6fc67a
@ -202,4 +202,9 @@
|
|||||||
struct btrfs_ioctl_search_args_v2)
|
struct btrfs_ioctl_search_args_v2)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef BTRFS_IOC_LOGICAL_INO_V2
|
||||||
|
#define BTRFS_IOC_LOGICAL_INO_V2 _IOWR(BTRFS_IOCTL_MAGIC, 59, struct btrfs_ioctl_logical_ino_args)
|
||||||
|
#define BTRFS_LOGICAL_INO_ARGS_IGNORE_OFFSET (1ULL << 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // CRUCIBLE_BTRFS_H
|
#endif // CRUCIBLE_BTRFS_H
|
||||||
|
@ -58,7 +58,7 @@ namespace crucible {
|
|||||||
|
|
||||||
struct BtrfsDataContainer : public btrfs_data_container {
|
struct BtrfsDataContainer : public btrfs_data_container {
|
||||||
BtrfsDataContainer(size_t size = 64 * 1024);
|
BtrfsDataContainer(size_t size = 64 * 1024);
|
||||||
void *prepare();
|
void *prepare(size_t size);
|
||||||
|
|
||||||
size_t get_size() const;
|
size_t get_size() const;
|
||||||
decltype(bytes_left) get_bytes_left() const;
|
decltype(bytes_left) get_bytes_left() const;
|
||||||
@ -70,12 +70,31 @@ namespace crucible {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct BtrfsIoctlLogicalInoArgs : public btrfs_ioctl_logical_ino_args {
|
struct BtrfsIoctlLogicalInoArgs : public btrfs_ioctl_logical_ino_args {
|
||||||
BtrfsIoctlLogicalInoArgs(uint64_t logical, size_t buf_size = 64 * 1024);
|
BtrfsIoctlLogicalInoArgs(uint64_t logical, size_t buf_size = 16 * 1024 * 1024);
|
||||||
|
|
||||||
|
uint64_t get_flags() const;
|
||||||
|
void set_flags(uint64_t new_flags);
|
||||||
|
|
||||||
virtual void do_ioctl(int fd);
|
virtual void do_ioctl(int fd);
|
||||||
virtual bool do_ioctl_nothrow(int fd);
|
virtual bool do_ioctl_nothrow(int fd);
|
||||||
|
|
||||||
BtrfsDataContainer m_container;
|
size_t m_container_size;
|
||||||
vector<BtrfsInodeOffsetRoot> m_iors;
|
struct BtrfsInodeOffsetRootSpan {
|
||||||
|
using iterator = BtrfsInodeOffsetRoot*;
|
||||||
|
using const_iterator = const BtrfsInodeOffsetRoot*;
|
||||||
|
size_t size() const;
|
||||||
|
iterator begin() const;
|
||||||
|
iterator end() const;
|
||||||
|
const_iterator cbegin() const;
|
||||||
|
const_iterator cend() const;
|
||||||
|
iterator data() const;
|
||||||
|
void clear();
|
||||||
|
operator vector<BtrfsInodeOffsetRoot>() const;
|
||||||
|
private:
|
||||||
|
iterator m_begin = nullptr;
|
||||||
|
iterator m_end = nullptr;
|
||||||
|
friend struct BtrfsIoctlLogicalInoArgs;
|
||||||
|
} m_iors;
|
||||||
};
|
};
|
||||||
|
|
||||||
ostream & operator<<(ostream &os, const BtrfsIoctlLogicalInoArgs &p);
|
ostream & operator<<(ostream &os, const BtrfsIoctlLogicalInoArgs &p);
|
||||||
@ -85,7 +104,7 @@ namespace crucible {
|
|||||||
virtual void do_ioctl(int fd);
|
virtual void do_ioctl(int fd);
|
||||||
virtual bool do_ioctl_nothrow(int fd);
|
virtual bool do_ioctl_nothrow(int fd);
|
||||||
|
|
||||||
BtrfsDataContainer m_container;
|
size_t m_container_size;
|
||||||
vector<string> m_paths;
|
vector<string> m_paths;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
129
lib/fs.cc
129
lib/fs.cc
@ -238,11 +238,13 @@ namespace crucible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
BtrfsDataContainer::prepare()
|
BtrfsDataContainer::prepare(size_t container_size)
|
||||||
{
|
{
|
||||||
|
if (m_data.size() < container_size) {
|
||||||
|
m_data.resize(container_size);
|
||||||
|
}
|
||||||
btrfs_data_container *p = reinterpret_cast<btrfs_data_container *>(m_data.data());
|
btrfs_data_container *p = reinterpret_cast<btrfs_data_container *>(m_data.data());
|
||||||
size_t min_size = offsetof(btrfs_data_container, val);
|
const size_t min_size = offsetof(btrfs_data_container, val);
|
||||||
size_t container_size = m_data.size();
|
|
||||||
if (container_size < min_size) {
|
if (container_size < min_size) {
|
||||||
THROW_ERROR(out_of_range, "container size " << container_size << " smaller than minimum " << min_size);
|
THROW_ERROR(out_of_range, "container size " << container_size << " smaller than minimum " << min_size);
|
||||||
}
|
}
|
||||||
@ -301,33 +303,123 @@ namespace crucible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BtrfsIoctlLogicalInoArgs::BtrfsIoctlLogicalInoArgs(uint64_t new_logical, size_t new_size) :
|
BtrfsIoctlLogicalInoArgs::BtrfsIoctlLogicalInoArgs(uint64_t new_logical, size_t new_size) :
|
||||||
m_container(new_size)
|
m_container_size(new_size)
|
||||||
{
|
{
|
||||||
memset_zero<btrfs_ioctl_logical_ino_args>(this);
|
memset_zero<btrfs_ioctl_logical_ino_args>(this);
|
||||||
logical = new_logical;
|
logical = new_logical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
BtrfsIoctlLogicalInoArgs::BtrfsInodeOffsetRootSpan::size() const
|
||||||
|
{
|
||||||
|
return m_end - m_begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
BtrfsIoctlLogicalInoArgs::BtrfsInodeOffsetRootSpan::const_iterator
|
||||||
|
BtrfsIoctlLogicalInoArgs::BtrfsInodeOffsetRootSpan::cbegin() const
|
||||||
|
{
|
||||||
|
return m_begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
BtrfsIoctlLogicalInoArgs::BtrfsInodeOffsetRootSpan::const_iterator
|
||||||
|
BtrfsIoctlLogicalInoArgs::BtrfsInodeOffsetRootSpan::cend() const
|
||||||
|
{
|
||||||
|
return m_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
BtrfsIoctlLogicalInoArgs::BtrfsInodeOffsetRootSpan::iterator
|
||||||
|
BtrfsIoctlLogicalInoArgs::BtrfsInodeOffsetRootSpan::begin() const
|
||||||
|
{
|
||||||
|
return m_begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
BtrfsIoctlLogicalInoArgs::BtrfsInodeOffsetRootSpan::iterator
|
||||||
|
BtrfsIoctlLogicalInoArgs::BtrfsInodeOffsetRootSpan::end() const
|
||||||
|
{
|
||||||
|
return m_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
BtrfsIoctlLogicalInoArgs::BtrfsInodeOffsetRootSpan::iterator
|
||||||
|
BtrfsIoctlLogicalInoArgs::BtrfsInodeOffsetRootSpan::data() const
|
||||||
|
{
|
||||||
|
return m_begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
BtrfsIoctlLogicalInoArgs::BtrfsInodeOffsetRootSpan::operator vector<BtrfsInodeOffsetRoot>() const
|
||||||
|
{
|
||||||
|
return vector<BtrfsInodeOffsetRoot>(m_begin, m_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BtrfsIoctlLogicalInoArgs::BtrfsInodeOffsetRootSpan::clear()
|
||||||
|
{
|
||||||
|
m_end = m_begin = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BtrfsIoctlLogicalInoArgs::set_flags(uint64_t new_flags)
|
||||||
|
{
|
||||||
|
// We are still supporting building with old headers that don't have .flags yet
|
||||||
|
reserved[3] = new_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
BtrfsIoctlLogicalInoArgs::get_flags() const
|
||||||
|
{
|
||||||
|
// We are still supporting building with old headers that don't have .flags yet
|
||||||
|
return reserved[3];
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BtrfsIoctlLogicalInoArgs::do_ioctl_nothrow(int fd)
|
BtrfsIoctlLogicalInoArgs::do_ioctl_nothrow(int fd)
|
||||||
{
|
{
|
||||||
btrfs_ioctl_logical_ino_args *p = static_cast<btrfs_ioctl_logical_ino_args *>(this);
|
btrfs_ioctl_logical_ino_args *p = static_cast<btrfs_ioctl_logical_ino_args *>(this);
|
||||||
inodes = reinterpret_cast<uint64_t>(m_container.prepare());
|
thread_local BtrfsDataContainer container;
|
||||||
size = m_container.get_size();
|
inodes = reinterpret_cast<uint64_t>(container.prepare(m_container_size));
|
||||||
|
size = container.get_size();
|
||||||
|
|
||||||
m_iors.clear();
|
m_iors.clear();
|
||||||
|
|
||||||
if (ioctl(fd, BTRFS_IOC_LOGICAL_INO, p)) {
|
static unsigned long bili_version = 0;
|
||||||
return false;
|
|
||||||
|
if (get_flags() == 0) {
|
||||||
|
// Could use either V1 or V2
|
||||||
|
if (bili_version) {
|
||||||
|
// We tested both versions and came to a decision
|
||||||
|
if (ioctl(fd, bili_version, p)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Try V2
|
||||||
|
if (ioctl(fd, BTRFS_IOC_LOGICAL_INO_V2, p)) {
|
||||||
|
// V2 failed, try again with V1
|
||||||
|
if (ioctl(fd, BTRFS_IOC_LOGICAL_INO, p)) {
|
||||||
|
// both V1 and V2 failed, doesn't tell us which one to choose
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// V1 and V2 both tested with same arguments, V1 OK, and V2 failed
|
||||||
|
bili_version = BTRFS_IOC_LOGICAL_INO;
|
||||||
|
} else {
|
||||||
|
// V2 succeeded, don't use V1 any more
|
||||||
|
bili_version = BTRFS_IOC_LOGICAL_INO_V2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Flags/size require a V2 feature, no fallback to V1 possible
|
||||||
|
if (ioctl(fd, BTRFS_IOC_LOGICAL_INO_V2, p)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// V2 succeeded so we don't need to probe any more
|
||||||
|
bili_version = BTRFS_IOC_LOGICAL_INO_V2;
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_data_container *bdc = reinterpret_cast<btrfs_data_container *>(p->inodes);
|
btrfs_data_container *bdc = reinterpret_cast<btrfs_data_container *>(p->inodes);
|
||||||
BtrfsInodeOffsetRoot *input_iter = reinterpret_cast<BtrfsInodeOffsetRoot *>(bdc->val);
|
BtrfsInodeOffsetRoot *input_iter = reinterpret_cast<BtrfsInodeOffsetRoot *>(bdc->val);
|
||||||
m_iors.reserve(bdc->elem_cnt);
|
|
||||||
|
|
||||||
for (auto count = bdc->elem_cnt; count > 2; count -= 3) {
|
|
||||||
m_iors.push_back(*input_iter++);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// elem_cnt counts uint64_t, but BtrfsInodeOffsetRoot is 3x uint64_t
|
||||||
|
THROW_CHECK1(runtime_error, bdc->elem_cnt, bdc->elem_cnt % 3 == 0);
|
||||||
|
m_iors.m_begin = input_iter;
|
||||||
|
m_iors.m_end = input_iter + bdc->elem_cnt / 3;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,7 +442,7 @@ namespace crucible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BtrfsIoctlInoPathArgs::BtrfsIoctlInoPathArgs(uint64_t inode, size_t new_size) :
|
BtrfsIoctlInoPathArgs::BtrfsIoctlInoPathArgs(uint64_t inode, size_t new_size) :
|
||||||
m_container(new_size)
|
m_container_size(new_size)
|
||||||
{
|
{
|
||||||
memset_zero<btrfs_ioctl_ino_path_args>(this);
|
memset_zero<btrfs_ioctl_ino_path_args>(this);
|
||||||
inum = inode;
|
inum = inode;
|
||||||
@ -360,8 +452,9 @@ namespace crucible {
|
|||||||
BtrfsIoctlInoPathArgs::do_ioctl_nothrow(int fd)
|
BtrfsIoctlInoPathArgs::do_ioctl_nothrow(int fd)
|
||||||
{
|
{
|
||||||
btrfs_ioctl_ino_path_args *p = static_cast<btrfs_ioctl_ino_path_args *>(this);
|
btrfs_ioctl_ino_path_args *p = static_cast<btrfs_ioctl_ino_path_args *>(this);
|
||||||
fspath = reinterpret_cast<uint64_t>(m_container.prepare());
|
thread_local BtrfsDataContainer container;
|
||||||
size = m_container.get_size();
|
fspath = reinterpret_cast<uint64_t>(container.prepare(m_container_size));
|
||||||
|
size = m_container_size;
|
||||||
|
|
||||||
m_paths.clear();
|
m_paths.clear();
|
||||||
|
|
||||||
@ -377,8 +470,8 @@ namespace crucible {
|
|||||||
|
|
||||||
for (auto count = bdc->elem_cnt; count > 0; --count) {
|
for (auto count = bdc->elem_cnt; count > 0; --count) {
|
||||||
const char *path = cp + *up++;
|
const char *path = cp + *up++;
|
||||||
if (static_cast<size_t>(path - cp) > m_container.get_size()) {
|
if (static_cast<size_t>(path - cp) > container.get_size()) {
|
||||||
THROW_ERROR(out_of_range, "offset " << (path - cp) << " > size " << m_container.get_size() << " in " << __PRETTY_FUNCTION__);
|
THROW_ERROR(out_of_range, "offset " << (path - cp) << " > size " << container.get_size() << " in " << __PRETTY_FUNCTION__);
|
||||||
}
|
}
|
||||||
m_paths.push_back(string(path));
|
m_paths.push_back(string(path));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user