1
0
mirror of https://github.com/Zygo/bees.git synced 2025-05-17 13:25:45 +02:00
Zygo Blaxell 180bb60cde fs: add support and workarounds for btrfs fs_info v2
Define a local copy of the header that has fields for the csum type
and length, so we can build in places that haven't caught up to kernel
5.5 headers yet.

The reason why the csum type and length are not unconditionally filled
in eludes me.  csum_length is necessarily non-zero, and the cost of
the conditional is worse than the cost of the copy, so the whole flags
dance is a WTF...but it's part of the kernel API now, so it's too late
to NAK it.

Signed-off-by: Zygo Blaxell <bees@furryterror.org>
2020-12-17 18:07:36 -05:00

273 lines
7.9 KiB
C++

#ifndef CRUCIBLE_FS_H
#define CRUCIBLE_FS_H
#include "crucible/error.h"
// Terribly Linux-specific FS-wrangling functions
// BTRFS
#include "crucible/btrfs.h"
// FIEMAP_* structs and flags
#include <linux/fiemap.h>
#include <cstdint>
#include <iosfwd>
#include <set>
#include <vector>
#include <fcntl.h>
#include <sys/statvfs.h>
namespace crucible {
using namespace std;
// wrapper around fallocate(...FALLOC_FL_PUNCH_HOLE...)
void punch_hole(int fd, off_t offset, off_t len);
struct BtrfsExtentInfo : public btrfs_ioctl_same_extent_info {
BtrfsExtentInfo(int dst_fd, off_t dst_offset);
};
struct BtrfsExtentSame : public btrfs_ioctl_same_args {
virtual ~BtrfsExtentSame();
BtrfsExtentSame(int src_fd, off_t src_offset, off_t src_length);
void add(int fd, off_t offset);
virtual void do_ioctl();
int m_fd;
vector<BtrfsExtentInfo> m_info;
};
ostream & operator<<(ostream &os, const btrfs_ioctl_same_extent_info *info);
ostream & operator<<(ostream &os, const btrfs_ioctl_same_args *info);
ostream & operator<<(ostream &os, const BtrfsExtentSame &bes);
struct BtrfsInodeOffsetRoot {
uint64_t m_inum;
uint64_t m_offset;
uint64_t m_root;
};
ostream & operator<<(ostream &os, const BtrfsInodeOffsetRoot &p);
struct BtrfsDataContainer : public btrfs_data_container {
BtrfsDataContainer(size_t size = 64 * 1024);
void *prepare(size_t size);
size_t get_size() const;
decltype(bytes_left) get_bytes_left() const;
decltype(bytes_missing) get_bytes_missing() const;
decltype(elem_cnt) get_elem_cnt() const;
decltype(elem_missed) get_elem_missed() const;
vector<char> m_data;
};
struct BtrfsIoctlLogicalInoArgs : public btrfs_ioctl_logical_ino_args {
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 bool do_ioctl_nothrow(int fd);
size_t m_container_size;
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;
BtrfsDataContainer m_container;
};
ostream & operator<<(ostream &os, const BtrfsIoctlLogicalInoArgs &p);
struct BtrfsIoctlInoPathArgs : public btrfs_ioctl_ino_path_args {
BtrfsIoctlInoPathArgs(uint64_t inode, size_t buf_size = 64 * 1024);
virtual void do_ioctl(int fd);
virtual bool do_ioctl_nothrow(int fd);
size_t m_container_size;
vector<string> m_paths;
};
ostream & operator<<(ostream &os, const BtrfsIoctlInoPathArgs &p);
struct BtrfsIoctlInoLookupArgs : public btrfs_ioctl_ino_lookup_args {
BtrfsIoctlInoLookupArgs(uint64_t objectid);
virtual void do_ioctl(int fd);
virtual bool do_ioctl_nothrow(int fd);
// use objectid = BTRFS_FIRST_FREE_OBJECTID
// this->treeid is the rootid for the path (we get the path too)
};
struct BtrfsIoctlDefragRangeArgs : public btrfs_ioctl_defrag_range_args {
BtrfsIoctlDefragRangeArgs();
virtual void do_ioctl(int fd);
virtual bool do_ioctl_nothrow(int fd);
};
ostream & operator<<(ostream &os, const BtrfsIoctlDefragRangeArgs *p);
// in btrfs/ctree.h, but that's a nightmare to #include here
typedef enum {
BTRFS_COMPRESS_NONE = 0,
BTRFS_COMPRESS_ZLIB = 1,
BTRFS_COMPRESS_LZO = 2,
BTRFS_COMPRESS_ZSTD = 3,
BTRFS_COMPRESS_TYPES = 3
} btrfs_compression_type;
struct FiemapExtent : public fiemap_extent {
FiemapExtent();
FiemapExtent(const fiemap_extent &that);
operator bool() const;
off_t begin() const;
off_t end() const;
};
struct Fiemap : public fiemap {
// Get entire file
Fiemap(uint64_t start = 0, uint64_t length = FIEMAP_MAX_OFFSET);
void do_ioctl(int fd);
vector<FiemapExtent> m_extents;
uint64_t m_min_count = (4096 - sizeof(fiemap)) / sizeof(fiemap_extent);
uint64_t m_max_count = 16 * 1024 * 1024 / sizeof(fiemap_extent);
};
ostream & operator<<(ostream &os, const fiemap_extent *info);
ostream & operator<<(ostream &os, const FiemapExtent &info);
ostream & operator<<(ostream &os, const fiemap *info);
ostream & operator<<(ostream &os, const Fiemap &info);
string fiemap_extent_flags_ntoa(unsigned long flags);
// Helper functions
void btrfs_clone_range(int src_fd, off_t src_offset, off_t src_length, int dst_fd, off_t dst_offset);
bool btrfs_extent_same(int src_fd, off_t src_offset, off_t src_length, int dst_fd, off_t dst_offset);
struct BtrfsIoctlSearchHeader : public btrfs_ioctl_search_header {
BtrfsIoctlSearchHeader();
vector<char> m_data;
size_t set_data(const vector<char> &v, size_t offset);
bool operator<(const BtrfsIoctlSearchHeader &that) const;
};
// Perf blames this function for a few percent overhead; move it here so it can be inline
inline bool BtrfsIoctlSearchHeader::operator<(const BtrfsIoctlSearchHeader &that) const
{
return tie(objectid, type, offset, len, transid) < tie(that.objectid, that.type, that.offset, that.len, that.transid);
}
ostream & operator<<(ostream &os, const btrfs_ioctl_search_header &hdr);
ostream & operator<<(ostream &os, const BtrfsIoctlSearchHeader &hdr);
struct BtrfsIoctlSearchKey : public btrfs_ioctl_search_key {
BtrfsIoctlSearchKey(size_t buf_size = 4096);
virtual bool do_ioctl_nothrow(int fd);
virtual void do_ioctl(int fd);
// Copy objectid/type/offset so we move forward
void next_min(const BtrfsIoctlSearchHeader& ref);
size_t m_buf_size;
set<BtrfsIoctlSearchHeader> m_result;
};
ostream & operator<<(ostream &os, const btrfs_ioctl_search_key &key);
ostream & operator<<(ostream &os, const BtrfsIoctlSearchKey &key);
string btrfs_search_type_ntoa(unsigned type);
string btrfs_search_objectid_ntoa(uint64_t objectid);
uint64_t btrfs_get_root_id(int fd);
uint64_t btrfs_get_root_transid(int fd);
template<class T>
const T*
get_struct_ptr(vector<char> &v, size_t offset = 0)
{
// OK so sometimes btrfs overshoots a little
if (offset + sizeof(T) > v.size()) {
v.resize(offset + sizeof(T), 0);
}
THROW_CHECK2(invalid_argument, v.size(), offset + sizeof(T), offset + sizeof(T) <= v.size());
return reinterpret_cast<const T*>(v.data() + offset);
}
template<class A, class R>
R
call_btrfs_get(R (*func)(const A*), vector<char> &v, size_t offset = 0)
{
return func(get_struct_ptr<A>(v, offset));
}
template <class T> struct btrfs_get_le;
template<> struct btrfs_get_le<__le64> {
uint64_t operator()(const void *p) { return get_unaligned_le64(p); }
};
template<> struct btrfs_get_le<__le32> {
uint32_t operator()(const void *p) { return get_unaligned_le32(p); }
};
template<> struct btrfs_get_le<__le16> {
uint16_t operator()(const void *p) { return get_unaligned_le16(p); }
};
template<> struct btrfs_get_le<__le8> {
uint8_t operator()(const void *p) { return get_unaligned_le8(p); }
};
template<class S, class T>
T
btrfs_get_member(T S::* member, vector<char> &v, size_t offset = 0)
{
const S *sp = reinterpret_cast<const S*>(NULL);
const T *spm = &(sp->*member);
auto member_offset = reinterpret_cast<const char *>(spm) - reinterpret_cast<const char *>(sp);
return btrfs_get_le<T>()(get_struct_ptr<S>(v, offset + member_offset));
}
struct Statvfs : public statvfs {
Statvfs();
Statvfs(string path);
Statvfs(int fd);
unsigned long size() const;
unsigned long free() const;
unsigned long available() const;
};
ostream &hexdump(ostream &os, const vector<char> &v);
struct BtrfsIoctlFsInfoArgs : public btrfs_ioctl_fs_info_args_v2 {
BtrfsIoctlFsInfoArgs();
void do_ioctl(int fd);
string uuid() const;
uint16_t csum_type() const;
uint16_t csum_size() const;
};
ostream & operator<<(ostream &os, const BtrfsIoctlFsInfoArgs &a);
};
#endif // CRUCIBLE_FS_H