1
0
mirror of https://github.com/Zygo/bees.git synced 2025-07-12 13:12:26 +02:00

workarounds: add workaround for btrfs send

Introduce --workaround options which trade performance or effectiveness to
avoid triggering kernel bugs.

The first such option is --workaround-btrfs-send, which avoids making any
modification to read-only subvols to avoid btrfs send bugs.

Clean up usage message:  no tabs for formatting, split options into
sections by theme.

Make scan mode a non-static data member like all (most?) other options.

Signed-off-by: Zygo Blaxell <bees@furryterror.org>
This commit is contained in:
Zygo Blaxell
2018-11-17 00:46:58 -05:00
parent 6c68e81da7
commit 23f3e4ec42
4 changed files with 159 additions and 38 deletions

View File

@ -11,8 +11,6 @@
using namespace crucible;
using namespace std;
BeesRoots::ScanMode BeesRoots::s_scan_mode = BeesRoots::SCAN_MODE_ZERO;
string
format_time(time_t t)
{
@ -67,10 +65,21 @@ void
BeesRoots::set_scan_mode(ScanMode mode)
{
THROW_CHECK1(invalid_argument, mode, mode < SCAN_MODE_COUNT);
s_scan_mode = mode;
m_scan_mode = mode;
BEESLOGINFO("Scan mode set to " << mode << " (" << scan_mode_ntoa(mode) << ")");
}
void
BeesRoots::set_workaround_btrfs_send(bool do_avoid)
{
m_workaround_btrfs_send = do_avoid;
if (m_workaround_btrfs_send) {
BEESLOGINFO("WORKAROUND: btrfs send workaround enabled");
} else {
BEESLOGINFO("btrfs send workaround disabled");
}
}
string
BeesRoots::crawl_state_filename() const
{
@ -281,7 +290,7 @@ BeesRoots::crawl_roots()
BEESLOGINFO("idle: crawl map is empty!");
}
switch (s_scan_mode) {
switch (m_scan_mode) {
case SCAN_MODE_ZERO: {
// Scan the same inode/offset tuple in each subvol (good for snapshots)
@ -366,6 +375,13 @@ BeesRoots::crawl_roots()
return false;
}
void
BeesRoots::clear_caches()
{
m_ctx->fd_cache()->clear();
m_root_ro_cache.clear();
}
void
BeesRoots::crawl_thread()
{
@ -408,7 +424,7 @@ BeesRoots::crawl_thread()
// Even open files are a problem if they're big enough.
auto new_count = m_transid_re.count();
if (new_count != last_count) {
m_ctx->fd_cache()->clear();
clear_caches();
}
last_count = new_count;
@ -541,6 +557,12 @@ BeesRoots::BeesRoots(shared_ptr<BeesContext> ctx) :
m_writeback_thread("crawl_writeback"),
m_task_running(false)
{
m_root_ro_cache.func([&](uint64_t root) -> bool {
return is_root_ro_nocache(root);
});
m_root_ro_cache.max_size(BEES_ROOT_FD_CACHE_SIZE);
m_crawl_thread.exec([&]() {
// Measure current transid before creating any crawlers
catch_all([&]() {
@ -646,6 +668,7 @@ BeesRoots::open_root_nocache(uint64_t rootid)
Stat st(rv);
THROW_CHECK1(runtime_error, st.st_ino, st.st_ino == BTRFS_FIRST_FREE_OBJECTID);
// BEESLOGDEBUG("open_root_nocache " << rootid << ": " << name_fd(rv));
BEESCOUNT(root_ok);
return rv;
}
@ -667,6 +690,32 @@ BeesRoots::open_root(uint64_t rootid)
return m_ctx->fd_cache()->open_root(m_ctx, rootid);
}
bool
BeesRoots::is_root_ro_nocache(uint64_t root)
{
Fd root_fd = open_root(root);
BEESTRACE("checking subvol flags on root " << root << " path " << name_fd(root_fd));
uint64_t flags = 0;
DIE_IF_NON_ZERO(ioctl(root_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags));
if (flags & BTRFS_SUBVOL_RDONLY) {
BEESLOGDEBUG("WORKAROUND: Avoiding RO subvol " << root);
BEESCOUNT(root_workaround_btrfs_send);
return true;
}
return false;
}
bool
BeesRoots::is_root_ro(uint64_t root)
{
// If we are not implementing the workaround there is no need for cache
if (!m_workaround_btrfs_send) {
return false;
}
return m_root_ro_cache(root);
}
uint64_t
BeesRoots::next_root(uint64_t root)
@ -889,6 +938,20 @@ BeesCrawl::fetch_extents()
return next_transid();
}
// Check for btrfs send workaround: don't scan RO roots at all, pretend
// they are just empty. We can't free any space there, and we
// don't have the necessary analysis logic to be able to use
// them as dedup src extents (yet).
//
// This will keep the max_transid up to date so if the root
// is ever switched back to read-write, it won't trigger big
// expensive in-kernel searches for ancient transids.
if (m_ctx->is_root_ro(old_state.m_root)) {
BEESLOGDEBUG("WORKAROUND: RO root " << old_state.m_root);
BEESCOUNT(root_workaround_btrfs_send);
return next_transid();
}
BEESNOTE("crawling " << get_state_end());
Timer crawl_timer;