]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
- added experimental bcachefs support
authorArvin Schnell <aschnell@suse.de>
Wed, 14 Feb 2024 08:15:40 +0000 (09:15 +0100)
committerArvin Schnell <aschnell@suse.de>
Wed, 14 Feb 2024 08:15:40 +0000 (09:15 +0100)
14 files changed:
LIBVERSION
configure.ac
dists/debian/rules
doc/bcachefs.txt [new file with mode: 0644]
package/snapper.changes
server/Client.cc
snapper.spec.in
snapper/Bcachefs.cc [new file with mode: 0644]
snapper/Bcachefs.h [new file with mode: 0644]
snapper/BcachefsUtils.cc [new file with mode: 0644]
snapper/BcachefsUtils.h [new file with mode: 0644]
snapper/Filesystem.cc
snapper/Makefile.am
snapper/Snapper.cc

index ba7f754d0c33efc277ab296ee7d1cf6b084ba36b..815da58b7a9ed1179ad6dd58c1ecac25e86fd77e 100644 (file)
@@ -1 +1 @@
-7.4.0
+7.4.1
index fbb0e103f1c869792a66140574f0956a89b5b009..b5fe5f4d23f810e2a7b86718ecfd2da6b965d2e8 100644 (file)
@@ -77,6 +77,14 @@ if test "x$with_btrfs" = "xyes"; then
        AC_DEFINE(ENABLE_BTRFS, 1, [Enable Btrfs internal snapshots support])
 fi
 
+AC_ARG_ENABLE([bcachefs], AS_HELP_STRING([--disable-bcachefs], [Disable Bcachefs internal snapshots support]),
+               [with_bcachefs=$enableval], [with_bcachefs=yes])
+AM_CONDITIONAL(ENABLE_BCACHEFS, [test "x$with_bcachefs" = "xyes"])
+
+if test "x$with_bcachefs" = "xyes"; then
+       AC_DEFINE(ENABLE_BCACHEFS, 1, [Enable Bcachefs internal snapshots support])
+fi
+
 AC_ARG_ENABLE([ext4], AS_HELP_STRING([--disable-ext4], [Disable ext4 snapshots support]),
                [with_ext4=$enableval], [with_ext4=yes])
 AM_CONDITIONAL(ENABLE_EXT4, [test "x$with_ext4" = "xyes"])
index 8b3f08436a59526e124325f9e68e805a214b8fd2..a58f42eac952111eb01f592c6e636fa9add51e50 100644 (file)
@@ -16,8 +16,8 @@ endif
 
 override_dh_auto_configure:
        dh_auto_configure -- --docdir=/usr/share/doc/packages/snapper --disable-silent-rules    \
-         --disable-ext4 --enable-xattrs --disable-rollback --disable-btrfs-quota               \
-         --with-pam-security=/lib/security
+         --disable-bcachefs --disable-ext4 --enable-xattrs --disable-rollback                  \
+         --disable-btrfs-quota --with-pam-security=/lib/security
 
 override_dh_auto_install:
        dh_auto_install
diff --git a/doc/bcachefs.txt b/doc/bcachefs.txt
new file mode 100644 (file)
index 0000000..b1538f2
--- /dev/null
@@ -0,0 +1,14 @@
+
+bcachefs support is experimental
+
+TODOs (at least):
+
+- ioctl for snapshot creation takes path instead of fd
+
+- read-only snapshots not supported by bcachefs
+  - background comparison started anyway
+
+- check if a directory is a snapshot
+
+- get ioctl defines from a header file or use a library
+
index 3d727e352fd4a24ffb234c7144ce68de6f7f946b..03a848c4a7fb55ba01efab8c57743488c4347c81 100644 (file)
@@ -1,3 +1,8 @@
+-------------------------------------------------------------------
+Wed Feb 14 09:14:32 CET 2024 - aschnell@suse.com
+
+- added experimental bcachefs support (gh#openSUSE/snapper#858)
+
 -------------------------------------------------------------------
 Wed Feb 07 11:16:40 CET 2024 - aschnell@suse.com
 
index 15cba3ee306baaab0befc5a1d7ef0f291a9ea1d1..539d914534f81e1914e61743a17f640d7d858c0c 100644 (file)
@@ -1081,7 +1081,11 @@ Client::create_post_snapshot(DBus::Connection& conn, DBus::Message& msg)
     bool background_comparison = true;
     it->getConfigInfo().get_value("BACKGROUND_COMPARISON", background_comparison);
     if (background_comparison)
-       clients.backgrounds().add_task(it, snap1, snap2);
+    {
+       // TODO isReadOnly is wrong if read-only is not supported by file system
+       if (snap1->isReadOnly() && snap2->isReadOnly())
+           clients.backgrounds().add_task(it, snap1, snap2);
+    }
 
     DBus::MessageMethodReturn reply(msg);
 
index be79b21914cfd4cdaa7483db4209df778d2e5a40..7a787edeb133d73265d1bc9c41d341f316e05811 100644 (file)
@@ -143,7 +143,7 @@ autoreconf -fvi
        --disable-btrfs-quota                                                   \
 %endif
        %{?with_selinux:--enable-selinux}                                       \
-       --disable-silent-rules --disable-ext4
+       --disable-silent-rules --disable-bcachefs --disable-ext4
 make %{?_smp_mflags}
 
 %install
diff --git a/snapper/Bcachefs.cc b/snapper/Bcachefs.cc
new file mode 100644 (file)
index 0000000..19e5bf3
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2024 SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+
+#include "config.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "snapper/Log.h"
+#include "snapper/Bcachefs.h"
+#include "snapper/BcachefsUtils.h"
+#include "snapper/File.h"
+#include "snapper/Snapper.h"
+#include "snapper/SnapperTmpl.h"
+
+#include "snapper/Acls.h"
+#include "snapper/Exception.h"
+#ifdef ENABLE_SELINUX
+#include "snapper/Selinux.h"
+#endif
+
+
+namespace snapper
+{
+    using namespace std;
+
+    using namespace BcachefsUtils;
+
+
+    Filesystem*
+    Bcachefs::create(const string& fstype, const string& subvolume, const string& root_prefix)
+    {
+       if (fstype == "bcachefs")
+           return new Bcachefs(subvolume, root_prefix);
+
+       return nullptr;
+    }
+
+
+    Bcachefs::Bcachefs(const string& subvolume, const string& root_prefix)
+       : Filesystem(subvolume, root_prefix)
+    {
+    }
+
+
+    void
+    Bcachefs::createConfig() const
+    {
+       SDir subvolume_dir = openSubvolumeDir();
+
+       try
+       {
+           create_subvolume(subvolume_dir.fd(), ".snapshots");
+       }
+       catch (const runtime_error_with_errno& e)
+       {
+           y2err("create subvolume failed, " << e.what());
+
+           switch (e.error_number)
+           {
+               case EEXIST:
+                   SN_THROW(CreateConfigFailedException("creating bcachefs subvolume .snapshots failed "
+                                                        "since it already exists"));
+                   break;
+
+               default:
+                   SN_THROW(CreateConfigFailedException("creating bcachefs subvolume .snapshots failed"));
+           }
+       }
+
+       SFile x(subvolume_dir, ".snapshots");
+
+#ifdef ENABLE_SELINUX
+       try
+       {
+           SnapperContexts scontexts;
+
+           x.fsetfilecon(scontexts.subvolume_context());
+       }
+       catch (const SelinuxException& e)
+       {
+           SN_CAUGHT(e);
+           // fall through intentional
+       }
+#endif
+
+       struct stat stat;
+       if (x.stat(&stat, 0) == 0)
+           x.chmod(stat.st_mode & ~0027, 0);
+    }
+
+
+    void
+    Bcachefs::deleteConfig() const
+    {
+       SDir subvolume_dir = openSubvolumeDir();
+
+       try
+       {
+           delete_subvolume(subvolume_dir.fd(), ".snapshots");
+       }
+       catch (const runtime_error& e)
+       {
+           y2err("delete subvolume failed, " << e.what());
+           SN_THROW(DeleteConfigFailedException("deleting bcachefs snapshot failed"));
+       }
+    }
+
+
+    string
+    Bcachefs::snapshotDir(unsigned int num) const
+    {
+       return (subvolume == "/" ? "" : subvolume) + "/.snapshots/" + decString(num) +
+           "/snapshot";
+    }
+
+
+    SDir
+    Bcachefs::openSubvolumeDir() const
+    {
+       SDir subvolume_dir = Filesystem::openSubvolumeDir();
+
+       struct stat stat;
+       if (subvolume_dir.stat(&stat) != 0)
+       {
+           SN_THROW(IOErrorException("stat on subvolume directory failed"));
+       }
+
+       if (!is_subvolume(stat))
+       {
+           SN_THROW(IOErrorException("subvolume is not a bcachefs subvolume"));
+       }
+
+       return subvolume_dir;
+    }
+
+
+    SDir
+    Bcachefs::openInfosDir() const
+    {
+       SDir subvolume_dir = openSubvolumeDir();
+       SDir infos_dir(subvolume_dir, ".snapshots");
+
+       struct stat stat;
+       if (infos_dir.stat(&stat) != 0)
+       {
+           SN_THROW(IOErrorException("stat on info directory failed"));
+       }
+
+       if (!is_subvolume(stat))
+       {
+           SN_THROW(IOErrorException(".snapshots is not a bcachefs subvolume"));
+       }
+
+       if (stat.st_uid != 0)
+       {
+           y2err(".snapshots must have owner root");
+           SN_THROW(IOErrorException(".snapshots must have owner root"));
+       }
+
+       if (stat.st_gid != 0 && stat.st_mode & S_IWGRP)
+       {
+           y2err(".snapshots must have group root or must not be group-writable");
+           SN_THROW(IOErrorException(".snapshots must have group root or must not be group-writable"));
+       }
+
+       if (stat.st_mode & S_IWOTH)
+       {
+           y2err(".snapshots must not be world-writable");
+           SN_THROW(IOErrorException(".snapshots must not be world-writable"));
+       }
+
+       return infos_dir;
+    }
+
+
+    SDir
+    Bcachefs::openSnapshotDir(unsigned int num) const
+    {
+       SDir info_dir = openInfoDir(num);
+       SDir snapshot_dir(info_dir, "snapshot");
+
+       return snapshot_dir;
+    }
+
+
+    void
+    Bcachefs::createSnapshot(unsigned int num, unsigned int num_parent, bool read_only, bool quota,
+                            bool empty) const
+    {
+       if (num_parent == 0)
+       {
+           SDir subvolume_dir = openSubvolumeDir();
+           SDir info_dir = openInfoDir(num);
+
+           try
+           {
+               if (empty)
+                   create_subvolume(info_dir.fd(), "snapshot");
+               else
+                   create_snapshot(subvolume_dir.fd(), subvolume, info_dir.fd(), "snapshot", read_only);
+           }
+           catch (const runtime_error& e)
+           {
+               y2err("create snapshot failed, " << e.what());
+               SN_THROW(CreateSnapshotFailedException());
+           }
+       }
+       else
+       {
+           SDir snapshot_dir = openSnapshotDir(num_parent);
+           SDir info_dir = openInfoDir(num);
+
+           try
+           {
+               create_snapshot(snapshot_dir.fd(), subvolume, info_dir.fd(), "snapshot", read_only);
+           }
+           catch (const runtime_error& e)
+           {
+               y2err("create snapshot failed, " << e.what());
+               SN_THROW(CreateSnapshotFailedException());
+           }
+       }
+    }
+
+
+    void
+    Bcachefs::deleteSnapshot(unsigned int num) const
+    {
+       SDir info_dir = openInfoDir(num);
+
+       try
+       {
+           delete_subvolume(info_dir.fd(), "snapshot");
+       }
+       catch (const runtime_error& e)
+       {
+           y2err("delete snapshot failed, " << e.what());
+           SN_THROW(DeleteSnapshotFailedException());
+       }
+    }
+
+
+    bool
+    Bcachefs::isSnapshotMounted(unsigned int num) const
+    {
+       return true;
+    }
+
+
+    void
+    Bcachefs::mountSnapshot(unsigned int num) const
+    {
+    }
+
+
+    void
+    Bcachefs::umountSnapshot(unsigned int num) const
+    {
+    }
+
+
+    bool
+    Bcachefs::isSnapshotReadOnly(unsigned int num) const
+    {
+       SDir snapshot_dir = openSnapshotDir(num);
+       return is_subvolume_read_only(snapshot_dir.fd());
+    }
+
+
+    void
+    Bcachefs::setSnapshotReadOnly(unsigned int num, bool read_only) const
+    {
+       SDir snapshot_dir = openSnapshotDir(num);
+       set_subvolume_read_only(snapshot_dir.fd(), read_only);
+    }
+
+
+    bool
+    Bcachefs::checkSnapshot(unsigned int num) const
+    {
+       try
+       {
+           SDir info_dir = openInfoDir(num);
+
+           struct stat stat;
+           int r = info_dir.stat("snapshot", &stat, AT_SYMLINK_NOFOLLOW);
+           return r == 0 && is_subvolume(stat);
+       }
+       catch (const IOErrorException& e)
+       {
+           SN_CAUGHT(e);
+
+           // TODO the openInfoDir above logs an error although when this
+           // function is used from nextNumber the failure is ok
+
+           return false;
+       }
+    }
+
+}
diff --git a/snapper/Bcachefs.h b/snapper/Bcachefs.h
new file mode 100644 (file)
index 0000000..17be882
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2024 SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+
+#ifndef SNAPPER_BCACHEFS_H
+#define SNAPPER_BCACHEFS_H
+
+
+#include "snapper/Filesystem.h"
+
+
+namespace snapper
+{
+
+    class Bcachefs : public Filesystem
+    {
+    public:
+
+       static Filesystem* create(const string& fstype, const string& subvolume,
+                                 const string& root_prefix);
+
+       Bcachefs(const string& subvolume, const string& root_prefix);
+
+       virtual string fstype() const override { return "bcachefs"; }
+
+       virtual void createConfig() const override;
+       virtual void deleteConfig() const override;
+
+       virtual string snapshotDir(unsigned int num) const override;
+
+       virtual SDir openSubvolumeDir() const override;
+       virtual SDir openInfosDir() const override;
+       virtual SDir openSnapshotDir(unsigned int num) const override;
+
+       virtual void createSnapshot(unsigned int num, unsigned int num_parent, bool read_only,
+                                   bool quota, bool empty) const override;
+       virtual void deleteSnapshot(unsigned int num) const override;
+
+       virtual bool isSnapshotMounted(unsigned int num) const override;
+       virtual void mountSnapshot(unsigned int num) const override;
+       virtual void umountSnapshot(unsigned int num) const override;
+
+       virtual bool isSnapshotReadOnly(unsigned int num) const override;
+       virtual void setSnapshotReadOnly(unsigned int num, bool read_only) const override;
+
+       virtual bool checkSnapshot(unsigned int num) const override;
+
+    };
+
+}
+
+
+#endif
diff --git a/snapper/BcachefsUtils.cc b/snapper/BcachefsUtils.cc
new file mode 100644 (file)
index 0000000..2150b36
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2024 SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+
+#include "config.h"
+
+#include <cerrno>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include "snapper/Log.h"
+#include "snapper/AppUtil.h"
+#include "snapper/BcachefsUtils.h"
+
+
+struct bch_ioctl_subvolume {
+       __u32                   flags;
+       __u32                   dirfd;
+       __u16                   mode;
+       __u16                   pad[3];
+       __u64                   dst_ptr;
+       __u64                   src_ptr;
+};
+
+#define BCH_IOCTL_SUBVOLUME_CREATE     _IOW(0xbc, 16, struct bch_ioctl_subvolume)
+#define BCH_IOCTL_SUBVOLUME_DESTROY    _IOW(0xbc, 17, struct bch_ioctl_subvolume)
+
+#define BCH_SUBVOL_SNAPSHOT_CREATE     (1U << 0)
+#define BCH_SUBVOL_SNAPSHOT_RO         (1U << 1)
+
+
+namespace snapper
+{
+
+    namespace BcachefsUtils
+    {
+
+       bool
+        is_subvolume(const struct stat& stat)
+        {
+            return true;       // TODO
+        }
+
+
+       bool
+       is_subvolume_read_only(int fd)
+       {
+           return false;       // TODO
+       }
+
+
+       void
+       set_subvolume_read_only(int fd, bool read_only)
+       {
+           throw std::runtime_error("set_subvolume_read_only not implemented");        // TODO
+       }
+
+
+       void
+       create_subvolume(int fddst, const string& name)
+       {
+           struct bch_ioctl_subvolume args = {
+               .flags          = 0,
+               .dirfd          = (__u32) fddst,
+               .mode           = 0777,
+               .dst_ptr        = (__u64) name.c_str(),
+               .src_ptr        = 0,
+           };
+
+           if (ioctl(fddst, BCH_IOCTL_SUBVOLUME_CREATE, &args) < 0)
+               throw runtime_error_with_errno("ioctl(BCH_IOCTL_SUBVOLUME_CREATE) failed", errno);
+       }
+
+
+       void
+       create_snapshot(int fd, const string& subvolume, int fddst, const string& name, bool read_only)
+       {
+           __u32 flags = BCH_SUBVOL_SNAPSHOT_CREATE;
+           if (read_only)
+               flags |= BCH_SUBVOL_SNAPSHOT_RO;        // TODO does not work
+
+           struct bch_ioctl_subvolume args = {
+               .flags          = flags,
+               .dirfd          = (__u32) fddst,
+               .mode           = 0777,
+               .dst_ptr        = (__u64) name.c_str(),
+               .src_ptr        = (__u64) subvolume.c_str(),    // TODO use fd instead of subvolume
+           };
+
+           if (ioctl(fddst, BCH_IOCTL_SUBVOLUME_CREATE, &args) < 0)
+               throw runtime_error_with_errno("ioctl(BCH_IOCTL_SUBVOLUME_CREATE) failed", errno);
+       }
+
+
+       void
+       delete_subvolume(int fd, const string& name)
+       {
+           struct bch_ioctl_subvolume args = {
+               .flags          = 0,
+               .dirfd          = (__u32) fd,
+               .mode           = 0777,
+               .dst_ptr        = (__u64) name.c_str(),
+               .src_ptr        = 0,
+           };
+
+           if (ioctl(fd, BCH_IOCTL_SUBVOLUME_DESTROY, &args) < 0)
+               throw runtime_error_with_errno("ioctl(BCH_IOCTL_SUBVOLUME_DESTROY) failed", errno);
+       }
+
+    }
+
+}
diff --git a/snapper/BcachefsUtils.h b/snapper/BcachefsUtils.h
new file mode 100644 (file)
index 0000000..39981aa
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2024 SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+
+#ifndef SNAPPER_BCACHEFS_UTILS_H
+#define SNAPPER_BCACHEFS_UTILS_H
+
+
+#include <string>
+
+
+namespace snapper
+{
+    using std::string;
+
+
+    namespace BcachefsUtils
+    {
+
+       bool is_subvolume(const struct stat& stat);
+
+       bool is_subvolume_read_only(int fd);
+       void set_subvolume_read_only(int fd, bool read_only);
+
+       void create_subvolume(int fddst, const string& name);
+       void create_snapshot(int fd, const string& subvolume, int fddst, const string& name, bool read_only);
+       void delete_subvolume(int fd, const string& name);
+
+    }
+
+}
+
+
+#endif
index 38916d3de1f673f0412264a6d7bd3ab5b5dea4c8..7f4d27cbfa0518c11cb28b961f7b97191c3b04bf 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) [2011-2015] Novell, Inc.
- * Copyright (c) [2016-2023] SUSE LLC
+ * Copyright (c) [2016-2024] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -39,6 +39,9 @@
 #ifdef ENABLE_BTRFS
 #include "snapper/Btrfs.h"
 #endif
+#ifdef ENABLE_BCACHEFS
+#include "snapper/Bcachefs.h"
+#endif
 #ifdef ENABLE_EXT4
 #include "snapper/Ext4.h"
 #endif
@@ -101,6 +104,9 @@ namespace snapper
 #ifdef ENABLE_BTRFS
                &Btrfs::create,
 #endif
+#ifdef ENABLE_BCACHEFS
+               &Bcachefs::create,
+#endif
 #ifdef ENABLE_EXT4
                &Ext4::create,
 #endif
index 2e994a6dafbcbb2dd8c2df436aa286603d5725f2..b0fe55c87fd98da8e6c5e56b108a58b4c3475968 100644 (file)
@@ -41,6 +41,12 @@ libsnapper_la_SOURCES +=                             \
        BtrfsUtils.cc           BtrfsUtils.h
 endif
 
+if ENABLE_BCACHEFS
+libsnapper_la_SOURCES +=                               \
+       Bcachefs.cc             Bcachefs.h              \
+       BcachefsUtils.cc        BcachefsUtils.h
+endif
+
 if ENABLE_EXT4
 libsnapper_la_SOURCES +=                               \
        Ext4.cc                 Ext4.h
index 8a761b5ddb020c7bc0fc78aa409b91dbe9577976..d5821c6a1bc6ab21284160d4d0848d5e76c88ba8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) [2011-2015] Novell, Inc.
- * Copyright (c) [2016-2023] SUSE LLC
+ * Copyright (c) [2016-2024] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -1194,6 +1194,11 @@ namespace snapper
 #endif
            "btrfs,"
 
+#ifndef ENABLE_BCACHEFS
+           "no-"
+#endif
+           "bcachefs,"
+
 #ifndef ENABLE_LVM
            "no-"
 #endif