mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 02:49:02 -04:00
Add Bcachefs support
This commit is contained in:
parent
b1ec61ccb4
commit
e242426ded
15 changed files with 387 additions and 129 deletions
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
|
@ -23,7 +23,7 @@ jobs:
|
|||
- uses: actions/checkout@v5
|
||||
- run: autoreconf -i
|
||||
- run: ./configure --enable-warning-as-error
|
||||
- run: make all btrfscheck
|
||||
- run: make all snapcheck
|
||||
- run: make distcheck
|
||||
build-win:
|
||||
runs-on: windows-latest
|
||||
|
|
|
|||
2
HISTORY
2
HISTORY
|
|
@ -7,7 +7,7 @@ SnapRAID HISTORY
|
|||
consistency and improve recovery reliability. When the 'snapshot'
|
||||
option is enabled, SnapRAID manages a 'pending' snapshot at the start
|
||||
of a sync and promotes it to a 'stable' state upon successful
|
||||
completion (currently supported on Btrfs).
|
||||
completion (currently supported on Btrfs and Bcachefs).
|
||||
This ensures that 'scrub', 'check', and 'fix' operations utilize a
|
||||
frozen point-in-time reference for data disks, eliminating
|
||||
mismatches caused by concurrent live filesystem modifications.
|
||||
|
|
|
|||
112
Makefile.am
112
Makefile.am
|
|
@ -154,7 +154,7 @@ EXTRA_DIST = \
|
|||
$(LIST_D) \
|
||||
$(LIST_MAN) \
|
||||
$(LIST_TXT) \
|
||||
test/test-btrfs.conf \
|
||||
test/test-snap.conf \
|
||||
test/test-par1.conf \
|
||||
test/test-par2.conf \
|
||||
test/test-par3.conf \
|
||||
|
|
@ -269,8 +269,8 @@ CHECKFLAGS_VERBOSE = $(CHECKFLAGS_ALPHA) -v --gui
|
|||
# Quiet options
|
||||
CHECKFLAGS = $(CHECKFLAGS_ALPHA) -q -q -q
|
||||
|
||||
# Btrfs with no parity limit
|
||||
CHECKFLAGS_BTRFS = --test-skip-device --test-skip-self --test-io-advise-none --test-force-order-alpha -q -q -q
|
||||
# Snapshots with no parity limit
|
||||
CHECKFLAGS_SNAP = --test-skip-device --test-skip-self --test-io-advise-none --test-force-order-alpha -q -q -q
|
||||
|
||||
# Number of files to create
|
||||
if !HAVE_MEMORY_CHECKER
|
||||
|
|
@ -302,7 +302,7 @@ PARZ = $(srcdir)/test/test-parz.conf
|
|||
PAR4 = $(srcdir)/test/test-par4.conf
|
||||
PAR5 = $(srcdir)/test/test-par5.conf
|
||||
PAR6 = $(srcdir)/test/test-par6.conf
|
||||
BTRFS = $(srcdir)/test/test-btrfs.conf
|
||||
SNAP = $(srcdir)/test/test-snap.conf
|
||||
MSG = @echo =====
|
||||
SNAPRAID = ./checker$(EXEEXT)
|
||||
|
||||
|
|
@ -312,89 +312,89 @@ setupcheck:
|
|||
mkdir bench
|
||||
|
||||
# Not included in main check because it requires root permissions
|
||||
btrfscheck: mktest checker setupcheck
|
||||
sudo $(MAKE) btrfscheck_run; \
|
||||
snapcheck: mktest checker setupcheck
|
||||
sudo $(MAKE) snapcheck_run; \
|
||||
status=$$?; \
|
||||
sudo $(MAKE) btrfscheck_cleanup; \
|
||||
sudo $(MAKE) snapcheck_cleanup; \
|
||||
exit $$status
|
||||
|
||||
btrfscheck_run:
|
||||
mkdir bench/btrfs1
|
||||
mkdir bench/btrfs2
|
||||
mkdir bench/btrfs3
|
||||
snapcheck_run:
|
||||
mkdir bench/snap1
|
||||
mkdir bench/snap2
|
||||
mkdir bench/snap3
|
||||
$(MSG) Create storages
|
||||
dd bs=1048576 count=32 if=/dev/zero of=bench/btrfs1.img
|
||||
dd bs=1048576 count=32 if=/dev/zero of=bench/btrfs2.img
|
||||
dd bs=1048576 count=32 if=/dev/zero of=bench/btrfs3.img
|
||||
/sbin/mkfs.btrfs --mixed bench/btrfs1.img
|
||||
/sbin/mkfs.btrfs --mixed bench/btrfs2.img
|
||||
/sbin/mkfs.btrfs --mixed bench/btrfs3.img
|
||||
mount -o loop bench/btrfs1.img bench/btrfs1
|
||||
mount -o loop bench/btrfs2.img bench/btrfs2
|
||||
mount -o loop bench/btrfs3.img bench/btrfs3
|
||||
dd bs=1048576 count=32 if=/dev/zero of=bench/snap1.img
|
||||
dd bs=1048576 count=32 if=/dev/zero of=bench/snap2.img
|
||||
dd bs=1048576 count=32 if=/dev/zero of=bench/snap3.img
|
||||
/sbin/mkfs.btrfs --mixed bench/snap1.img
|
||||
/sbin/mkfs.btrfs --mixed bench/snap2.img
|
||||
/sbin/mkfs.btrfs --mixed bench/snap3.img
|
||||
mount -o loop bench/snap1.img bench/snap1
|
||||
mount -o loop bench/snap2.img bench/snap2
|
||||
mount -o loop bench/snap3.img bench/snap3
|
||||
$(MSG) Create some files
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 1 btrfs 3 $(CHECKCOUNT) $(CHECKSIZE)
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 1 snap 3 $(CHECKCOUNT) $(CHECKSIZE)
|
||||
$(MSG) Basic
|
||||
# Setup
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) sync
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) scrub -p full
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) check -d btrfs1
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) sync
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) scrub -p full
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) check -d snap1
|
||||
# Recover test
|
||||
$(MSG) Recover with file deletions from two disk with ONLY one parity OUTSIDE SYNC
|
||||
rm -rf bench/btrfs1/a
|
||||
rm -rf bench/btrfs2/a
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) fix -d btrfs1 -l test.log
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) fix -d btrfs2 -l test.log
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) check
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) sync --force-full
|
||||
rm -rf bench/snap1/a
|
||||
rm -rf bench/snap2/a
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) fix -d snap1 -l test.log
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) fix -d snap2 -l test.log
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) check
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) sync --force-full
|
||||
# Recover test
|
||||
$(MSG) Recover with file deletions from two disk with ONLY one parity aborted BEFORE SYNC
|
||||
# Changes (including deletion) on disk1
|
||||
$(TESTENV) ./mktest$(EXEEXT) change 1 500 bench/btrfs1/a/* bench/btrfs1/b/*
|
||||
$(TESTENV) ./mktest$(EXEEXT) change 1 500 bench/snap1/a/* bench/snap1/b/*
|
||||
# Sync aborted BEFORE
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) sync --test-kill-before-sync
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) status
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) sync --test-kill-before-sync
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) status
|
||||
# Destroy disk2
|
||||
rm -rf bench/btrfs2/a bench/btrfs2/b
|
||||
rm -rf bench/snap2/a bench/snap2/b
|
||||
# Recover disk2 (disk1 is intentionally deleted, so nothing to recover)
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) fix -d btrfs2 -l test.log
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) check
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) sync --force-full
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) fix -d snap2 -l test.log
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) check
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) sync --force-full
|
||||
# Recover test
|
||||
$(MSG) Recover with file deletions from two disk with ONLY one parity aborted AFTER SYNC
|
||||
# Changes (including deletion) on disk1
|
||||
$(TESTENV) ./mktest$(EXEEXT) change 2 500 bench/btrfs1/a/* bench/btrfs1/b/*
|
||||
$(TESTENV) ./mktest$(EXEEXT) change 2 500 bench/snap1/a/* bench/snap1/b/*
|
||||
# Sync aborted AFTER
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) sync --test-kill-after-sync
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) status
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) sync --test-kill-after-sync
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) status
|
||||
# Destroy disk2
|
||||
rm -rf bench/btrfs2/a bench/btrfs2/b
|
||||
rm -rf bench/snap2/a bench/snap2/b
|
||||
# Recover disk2 (disk1 is intentionally deleted, so nothing to recover)
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) fix -d btrfs2 -l test.log
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) check
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) sync --force-full
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) fix -d snap2 -l test.log
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) check
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) sync --force-full
|
||||
# Sync recover
|
||||
$(MSG) Sync recover aborted AFTER
|
||||
# Change files in disk3
|
||||
$(TESTENV) ./mktest$(EXEEXT) change 1 500 bench/btrfs3/a/*
|
||||
$(TESTENV) ./mktest$(EXEEXT) change 1 500 bench/snap3/a/*
|
||||
# Sync abort and sync retry
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) sync --test-kill-after-sync
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) sync
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) check
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) sync --test-kill-after-sync
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) sync
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) check
|
||||
# Sync recover
|
||||
$(MSG) Sync recover aborted BEFORE
|
||||
# Change files in disk3
|
||||
$(TESTENV) ./mktest$(EXEEXT) change 1 500 bench/btrfs3/a/*
|
||||
$(TESTENV) ./mktest$(EXEEXT) change 1 500 bench/snap3/a/*
|
||||
# Sync abort and sync retry
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) sync --test-kill-before-sync
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) sync
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_BTRFS) -c $(BTRFS) check
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) sync --test-kill-before-sync
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) sync
|
||||
$(TESTENV) $(SNAPRAID) $(CHECKFLAGS_SNAP) -c $(SNAP) check
|
||||
|
||||
btrfscheck_cleanup:
|
||||
snapcheck_cleanup:
|
||||
$(MSG) Unmount storages
|
||||
umount bench/btrfs1
|
||||
umount bench/btrfs2
|
||||
umount bench/btrfs3
|
||||
umount bench/snap1
|
||||
umount bench/snap2
|
||||
umount bench/snap3
|
||||
|
||||
check-local: setupcheck
|
||||
mkdir bench/disk1
|
||||
|
|
|
|||
|
|
@ -812,6 +812,7 @@ struct snapraid_disk* disk_alloc(const char* name, const char* dir, uint64_t dev
|
|||
|
||||
/* no snapshot by default */
|
||||
disk->snapshot_root[0] = 0;
|
||||
disk->snapshot_magic = 0;
|
||||
pathcpy(disk->dir, sizeof(disk->dir), disk->mount_point);
|
||||
|
||||
#if HAVE_THREAD
|
||||
|
|
|
|||
|
|
@ -383,6 +383,7 @@ struct snapraid_disk {
|
|||
* It always terminates with /
|
||||
*/
|
||||
char snapshot_root[PATH_MAX];
|
||||
uint32_t snapshot_magic; /**< Magic number of the snapshot filesystem */
|
||||
|
||||
char smartctl[PATH_MAX]; /**< Custom command for smartctl. Empty means auto. */
|
||||
int smartignore[SMART_IGNORE_MAX]; /**< Smart attributes to ignore for this device. */
|
||||
|
|
|
|||
|
|
@ -2062,31 +2062,35 @@ int fsinfo(const char* path, int* has_persistent_inode, int* has_syncronized_har
|
|||
return 0;
|
||||
}
|
||||
|
||||
int fssnapshot(const char* path, char* root, size_t root_size)
|
||||
int fssnapshot(const char* path, char* root, size_t root_size, uint32_t* magic)
|
||||
{
|
||||
(void)path;
|
||||
(void)root;
|
||||
(void)root_size;
|
||||
(void)magic;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fssnapshot_create(const char* source, const char* parent_dir, const char* name)
|
||||
int fssnapshot_create(uint32_t magic, const char* source, const char* parent_dir, const char* name)
|
||||
{
|
||||
(void)magic;
|
||||
(void)source;
|
||||
(void)parent_dir;
|
||||
(void)name;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fssnapshot_delete(const char* parent_dir, const char* name)
|
||||
int fssnapshot_delete(uint32_t magic, const char* parent_dir, const char* name)
|
||||
{
|
||||
(void)magic;
|
||||
(void)parent_dir;
|
||||
(void)name;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fssnapshot_rename(const char* parent_dir, const char* old_name, const char* new_name)
|
||||
int fssnapshot_rename(uint32_t magic, const char* parent_dir, const char* old_name, const char* new_name)
|
||||
{
|
||||
(void)magic;
|
||||
(void)parent_dir;
|
||||
(void)old_name;
|
||||
(void)new_name;
|
||||
|
|
|
|||
|
|
@ -366,32 +366,36 @@ int fsinfo(const char* path, int* has_persistent_inode, int* has_syncronized_har
|
|||
/**
|
||||
* Get the subvolume directory if the underline filesystem support it
|
||||
* @param path Full path of the mount point to check. It must end with /
|
||||
* @param root The full path of the subvolume root that contains the specified path. It will end with /.
|
||||
* @param root Set the full path of the subvolume root that contains the specified path. It will end with /.
|
||||
* @param magic Set the magic number of the filesystem
|
||||
*/
|
||||
int fssnapshot(const char* path, char* root, size_t root_size);
|
||||
int fssnapshot(const char* path, char* root, size_t root_size, uint32_t* magic);
|
||||
|
||||
/**
|
||||
* Creates a snapshot of a subvolume.
|
||||
* Creates a snapshot of a subvolume
|
||||
* @param magic The magic number of the filesystem.
|
||||
* @param source Path to the source subvolume.
|
||||
* @param parent_dir Directory where the snapshot should be created.
|
||||
* @param name Name of snapshot.
|
||||
* @return 0 on success, -1 on failure.
|
||||
*/
|
||||
int fssnapshot_create(const char* source, const char* parent_dir, const char* name);
|
||||
int fssnapshot_create(uint32_t magic, const char* source, const char* parent_dir, const char* name);
|
||||
|
||||
/**
|
||||
* Deletes a subvolume/snapshot.
|
||||
* @param magic The magic number of the filesystem.
|
||||
* @param parent_dir Directory where the snapshot is.
|
||||
* @param name Name of snapshot.
|
||||
* @return 0 on success, -1 on failure.
|
||||
*/
|
||||
int fssnapshot_delete(const char* parent_dir, const char* name);
|
||||
int fssnapshot_delete(uint32_t magic, const char* parent_dir, const char* name);
|
||||
|
||||
/**
|
||||
* Renames a subvolume.
|
||||
* @param magic The magic number of the filesystem.
|
||||
* @return 0 on success, -1 on failure.
|
||||
*/
|
||||
int fssnapshot_rename(const char* parent_dir, const char* old_name, const char* new_name);
|
||||
int fssnapshot_rename(uint32_t magic, const char* parent_dir, const char* old_name, const char* new_name);
|
||||
|
||||
/*
|
||||
* Log file.
|
||||
|
|
|
|||
|
|
@ -5845,7 +5845,7 @@ int state_snapshot_new(struct snapraid_state* state)
|
|||
int ret;
|
||||
|
||||
/* check if it supports snapshot */
|
||||
if (fssnapshot(disk->mount_point, root, sizeof(root)) != 0)
|
||||
if (fssnapshot(disk->mount_point, root, sizeof(root), &disk->snapshot_magic) != 0)
|
||||
continue;
|
||||
|
||||
size_t root_len = strlen(root);
|
||||
|
|
@ -5861,13 +5861,13 @@ int state_snapshot_new(struct snapraid_state* state)
|
|||
}
|
||||
|
||||
/* delete a potential previous pending snapshot */
|
||||
if (fssnapshot_delete(container, SNAPSHOT_PENDING) != 0) {
|
||||
if (fssnapshot_delete(disk->snapshot_magic, container, SNAPSHOT_PENDING) != 0) {
|
||||
log_fatal(errno, "Failed to delete pending snapshot in '%s'. %s.\n", container, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* create a new snapshot */
|
||||
if (fssnapshot_create(root, container, SNAPSHOT_PENDING) != 0) {
|
||||
if (fssnapshot_create(disk->snapshot_magic, root, container, SNAPSHOT_PENDING) != 0) {
|
||||
log_fatal(errno, "Failed to create pending snapshot '%s'. %s.\n", container, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -5908,13 +5908,13 @@ int state_snapshot_commit(struct snapraid_state* state)
|
|||
pathcat(container, sizeof(container), SNAPSHOT_CONTAINER);
|
||||
|
||||
/* delete a potential previous stable snapshot */
|
||||
if (fssnapshot_delete(container, SNAPSHOT_STABLE) != 0) {
|
||||
if (fssnapshot_delete(disk->snapshot_magic, container, SNAPSHOT_STABLE) != 0) {
|
||||
log_fatal(errno, "Failed to delete stable snapshot in '%s'. %s.\n", container, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* rename pending to stable */
|
||||
if (fssnapshot_rename(container, SNAPSHOT_PENDING, SNAPSHOT_STABLE) != 0) {
|
||||
if (fssnapshot_rename(disk->snapshot_magic, container, SNAPSHOT_PENDING, SNAPSHOT_STABLE) != 0) {
|
||||
log_fatal(errno, "Failed to rename snapshot in '%s'. %s.\n", container, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -5937,7 +5937,7 @@ void state_snapshot_read(struct snapraid_state* state)
|
|||
char vol[PATH_MAX];
|
||||
|
||||
/* check if it supports snapshot */
|
||||
if (fssnapshot(disk->mount_point, root, sizeof(root)) != 0)
|
||||
if (fssnapshot(disk->mount_point, root, sizeof(root), &disk->snapshot_magic) != 0)
|
||||
continue;
|
||||
|
||||
size_t root_len = strlen(root);
|
||||
|
|
@ -5982,7 +5982,7 @@ void state_snapshot_write(struct snapraid_state* state, tommy_list* filterlist_d
|
|||
char vol[PATH_MAX];
|
||||
|
||||
/* check if it supports snapshot */
|
||||
if (fssnapshot(disk->mount_point, root, sizeof(root)) != 0)
|
||||
if (fssnapshot(disk->mount_point, root, sizeof(root), &disk->snapshot_magic) != 0)
|
||||
continue;
|
||||
|
||||
size_t root_len = strlen(root);
|
||||
|
|
|
|||
278
cmdline/unix.c
278
cmdline/unix.c
|
|
@ -29,6 +29,7 @@ int exit_failure = 1;
|
|||
int exit_sync_needed = 2;
|
||||
|
||||
#define BTRFS_SUPER_MAGIC 0x9123683E
|
||||
#define BCACHEFS_SUPER_MAGIC 0xCA451A4E
|
||||
|
||||
#if HAVE_POSIX_FADVISE
|
||||
/**
|
||||
|
|
@ -125,6 +126,7 @@ const char* stat_desc(struct stat* st)
|
|||
return "unknown";
|
||||
}
|
||||
|
||||
#if HAVE_LINUX_DEVICE
|
||||
static const char* smartctl_paths[] = {
|
||||
/* Linux & BSD */
|
||||
"/usr/sbin/smartctl",
|
||||
|
|
@ -132,22 +134,24 @@ static const char* smartctl_paths[] = {
|
|||
"/usr/local/sbin/smartctl",
|
||||
"/usr/bin/smartctl",
|
||||
"/usr/local/bin/smartctl",
|
||||
#ifdef __APPLE__
|
||||
/* macOS (Intel & Apple Silicon) */
|
||||
"/opt/homebrew/sbin/smartctl",
|
||||
#endif
|
||||
0
|
||||
};
|
||||
|
||||
const char* find_smartctl(void)
|
||||
static const char* find_smartctl(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; smartctl_paths[i]; ++i) {
|
||||
if (eaccess(smartctl_paths[i], X_OK) == 0)
|
||||
for (int i = 0; smartctl_paths[i]; ++i) {
|
||||
if (eaccess(smartctl_paths[i], X_OK) == 0) {
|
||||
return smartctl_paths[i];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Read a file from sys
|
||||
|
|
@ -986,6 +990,66 @@ static int devuuid_btrfs(uint64_t device, const char* dir, char* uuid, size_t uu
|
|||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_LINUX_DEVICE
|
||||
struct bch_ioctl_query_uuid {
|
||||
__u8 uuid[16];
|
||||
};
|
||||
|
||||
#define BCH_IOCTL_QUERY_UUID _IOR(0xbc, 1, struct bch_ioctl_query_uuid)
|
||||
|
||||
static int devuuid_bcachefs(uint64_t device, const char* dir, char* uuid, size_t uuid_size)
|
||||
{
|
||||
struct statfs sfs;
|
||||
|
||||
int fd = open(dir, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP*/
|
||||
}
|
||||
|
||||
if (fstatfs(fd, &sfs) != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
close(fd);
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
if (sfs.f_type != BCACHEFS_SUPER_MAGIC) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct bch_ioctl_query_uuid info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
if (ioctl(fd, BCH_IOCTL_QUERY_UUID, &info) < 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
close(fd);
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
snprintf(uuid, uuid_size,
|
||||
"%02x%02x%02x%02x-"
|
||||
"%02x%02x-"
|
||||
"%02x%02x-"
|
||||
"%02x%02x-"
|
||||
"%02x%02x%02x%02x%02x%02x",
|
||||
info.uuid[0], info.uuid[1], info.uuid[2], info.uuid[3],
|
||||
info.uuid[4], info.uuid[5],
|
||||
info.uuid[6], info.uuid[7],
|
||||
info.uuid[8], info.uuid[9],
|
||||
info.uuid[10], info.uuid[11], info.uuid[12], info.uuid[13], info.uuid[14], info.uuid[15]
|
||||
);
|
||||
|
||||
log_tag("uuid:by-bcachefs:%u:%u:%s: found %s\n", major(device), minor(device), uuid, dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int devuuid(uint64_t device_id, const char* device_path, char* uuid, size_t uuid_size)
|
||||
{
|
||||
(void)device_path;
|
||||
|
|
@ -1001,6 +1065,11 @@ int devuuid(uint64_t device_id, const char* device_path, char* uuid, size_t uuid
|
|||
return 0;
|
||||
#endif
|
||||
|
||||
#if HAVE_LINUX_DEVICE
|
||||
if (devuuid_bcachefs(device_id, device_path, uuid, uuid_size) == 0)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#if HAVE_LINUX_DEVICE
|
||||
if (devuuid_dev(device_id, uuid, uuid_size) == 0)
|
||||
return 0;
|
||||
|
|
@ -1142,7 +1211,6 @@ int filephy(const char* path, uint64_t size, uint64_t* physical)
|
|||
#define BEFS_SUPER_MAGIC 0x42465331
|
||||
#define BFS_MAGIC 0x1BADFACE
|
||||
#define BINFMTFS_MAGIC 0x42494e4d
|
||||
#define BTRFS_SUPER_MAGIC 0x9123683E
|
||||
#define CGROUP_SUPER_MAGIC 0x27e0eb
|
||||
#define CIFS_MAGIC_NUMBER 0xFF534D42
|
||||
#define CODA_SUPER_MAGIC 0x73757245
|
||||
|
|
@ -1246,6 +1314,7 @@ struct filesystem_entry {
|
|||
{ BFS_MAGIC, "bfs", 0 },
|
||||
{ BINFMTFS_MAGIC, "binfmt_misc", 0 },
|
||||
{ BTRFS_SUPER_MAGIC, "btrfs", 0 },
|
||||
{ BCACHEFS_SUPER_MAGIC, "bcachefs", 0 },
|
||||
{ CEPH_SUPER_MAGIC, "ceph", 1 },
|
||||
{ CGROUP_SUPER_MAGIC, "cgroupfs", 0 },
|
||||
{ CIFS_MAGIC_NUMBER, "cifs", 1 },
|
||||
|
|
@ -1465,12 +1534,40 @@ int fsinfo(const char* path, int* has_persistent_inode, int* has_syncronized_har
|
|||
return 0;
|
||||
}
|
||||
|
||||
int fssnapshot(const char* path, char* root, size_t root_size)
|
||||
#if HAVE_LINUX_DEVICE
|
||||
static const char* const bcachefs_paths[] = {
|
||||
"/usr/sbin/bcachefs",
|
||||
"/sbin/bcachefs",
|
||||
"/usr/local/sbin/bcachefs",
|
||||
"/usr/bin/bcachefs",
|
||||
"/bin/bcachefs",
|
||||
"/usr/local/bin/bcachefs",
|
||||
#ifdef __APPLE__
|
||||
/* macOS (Intel & Apple Silicon) */
|
||||
"/opt/homebrew/sbin/bcachefs",
|
||||
#endif
|
||||
0
|
||||
};
|
||||
|
||||
static const char* find_bcachefs(void)
|
||||
{
|
||||
for (int i = 0; bcachefs_paths[i]; ++i) {
|
||||
if (access(bcachefs_paths[i], X_OK) == 0) {
|
||||
return bcachefs_paths[i];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int fssnapshot(const char* path, char* root, size_t root_size, uint32_t* magic)
|
||||
{
|
||||
#if HAVE_LINUX_DEVICE
|
||||
struct statfs sfs;
|
||||
struct stat st;
|
||||
char current_path[PATH_MAX];
|
||||
uint64_t root_inode;
|
||||
|
||||
pathcpy(current_path, sizeof(current_path), path);
|
||||
|
||||
|
|
@ -1481,9 +1578,15 @@ int fssnapshot(const char* path, char* root, size_t root_size)
|
|||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
/* only btrfs */
|
||||
if (sfs.f_type != BTRFS_SUPER_MAGIC)
|
||||
if (sfs.f_type == BTRFS_SUPER_MAGIC) {
|
||||
/* btrfs reserved inode 256 for subvolume roots */
|
||||
root_inode = 256;
|
||||
} else if (sfs.f_type == BCACHEFS_SUPER_MAGIC) {
|
||||
/* Bcachefs reserves inode 4096 for each subvolume's root directory */
|
||||
root_inode = 4096;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* walk up the directory tree to find the subvolume root (Inode 256) */
|
||||
while (1) {
|
||||
|
|
@ -1494,10 +1597,10 @@ int fssnapshot(const char* path, char* root, size_t root_size)
|
|||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
/* btrfs reserved inode 256 for subvolume roots */
|
||||
if (st.st_ino == 256) {
|
||||
if (st.st_ino == root_inode) {
|
||||
/* copy the subvol root */
|
||||
pathcpy(root, root_size, current_path);
|
||||
*magic = sfs.f_type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1515,13 +1618,14 @@ int fssnapshot(const char* path, char* root, size_t root_size)
|
|||
(void)path;
|
||||
(void)root;
|
||||
(void)root_size;
|
||||
(void)magic;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int fssnapshot_create(const char* source, const char* parent_dir, const char* name)
|
||||
{
|
||||
#if HAVE_LINUX_DEVICE
|
||||
int fssnapshot_btrfs_create(const char* source, const char* parent_dir, const char* name)
|
||||
{
|
||||
struct btrfs_ioctl_vol_args_v2 args;
|
||||
int fd_source;
|
||||
int fd_dest_parent;
|
||||
|
|
@ -1562,7 +1666,53 @@ int fssnapshot_create(const char* source, const char* parent_dir, const char* na
|
|||
close(fd_dest_parent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_LINUX_DEVICE
|
||||
static int fssnapshot_bcachefs_create(const char* source, const char* parent_dir, const char* name)
|
||||
{
|
||||
char dst_path[PATH_MAX];
|
||||
char cmd[PATH_MAX * 3 + 64];
|
||||
const char* bcachefs;
|
||||
int ret;
|
||||
|
||||
bcachefs = find_bcachefs();
|
||||
if (!bcachefs) {
|
||||
/* LCOV_EXCL_START */
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
pathcpy(dst_path, sizeof(dst_path), parent_dir);
|
||||
pathcatc(dst_path, sizeof(dst_path), '/');
|
||||
pathcat(dst_path, sizeof(dst_path), name);
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "%s subvolume snapshot -r %s %s", bcachefs, source, dst_path);
|
||||
|
||||
ret = system(cmd);
|
||||
if (ret != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int fssnapshot_create(uint32_t magic, const char* source, const char* parent_dir, const char* name)
|
||||
{
|
||||
#if HAVE_LINUX_DEVICE
|
||||
if (magic == BTRFS_SUPER_MAGIC) {
|
||||
return fssnapshot_btrfs_create(source, parent_dir, name);
|
||||
} else if (magic == BCACHEFS_SUPER_MAGIC) {
|
||||
return fssnapshot_bcachefs_create(source, parent_dir, name);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
(void)magic;
|
||||
(void)source;
|
||||
(void)parent_dir;
|
||||
(void)name;
|
||||
|
|
@ -1570,9 +1720,9 @@ int fssnapshot_create(const char* source, const char* parent_dir, const char* na
|
|||
#endif
|
||||
}
|
||||
|
||||
int fssnapshot_delete(const char* parent_dir, const char* name)
|
||||
{
|
||||
#if HAVE_LINUX_DEVICE
|
||||
int fssnapshot_btrfs_delete(const char* parent_dir, const char* name)
|
||||
{
|
||||
struct btrfs_ioctl_vol_args args;
|
||||
int fd_parent;
|
||||
int ret;
|
||||
|
|
@ -1588,7 +1738,6 @@ int fssnapshot_delete(const char* parent_dir, const char* name)
|
|||
pathcpy(args.name, BTRFS_PATH_NAME_MAX, name);
|
||||
|
||||
ret = ioctl(fd_parent, BTRFS_IOC_SNAP_DESTROY, &args);
|
||||
|
||||
if (ret < 0 && errno != ENOENT) {
|
||||
/* LCOV_EXCL_START */
|
||||
close(fd_parent);
|
||||
|
|
@ -1598,16 +1747,70 @@ int fssnapshot_delete(const char* parent_dir, const char* name)
|
|||
|
||||
close(fd_parent);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_LINUX_DEVICE
|
||||
static int fssnapshot_bcachefs_delete(const char* parent_dir, const char* name)
|
||||
{
|
||||
char target_path[PATH_MAX];
|
||||
char cmd[PATH_MAX + 64];
|
||||
const char* bcachefs;
|
||||
int ret;
|
||||
|
||||
bcachefs = find_bcachefs();
|
||||
if (!bcachefs) {
|
||||
/* LCOV_EXCL_START */
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
pathcpy(target_path, sizeof(target_path), parent_dir);
|
||||
pathcatc(target_path, sizeof(target_path), '/');
|
||||
pathcat(target_path, sizeof(target_path), name);
|
||||
|
||||
if (access(target_path, F_OK) < 0) {
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
/* LCOV_EXCL_START */
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "%s subvolume delete %s", bcachefs, target_path);
|
||||
|
||||
ret = system(cmd);
|
||||
if (ret != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int fssnapshot_delete(uint32_t magic, const char* parent_dir, const char* name)
|
||||
{
|
||||
#if HAVE_LINUX_DEVICE
|
||||
if (magic == BTRFS_SUPER_MAGIC) {
|
||||
return fssnapshot_btrfs_delete(parent_dir, name);
|
||||
} else if (magic == BCACHEFS_SUPER_MAGIC) {
|
||||
return fssnapshot_bcachefs_delete(parent_dir, name);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
(void)magic;
|
||||
(void)parent_dir;
|
||||
(void)name;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int fssnapshot_rename(const char* parent_dir, const char* old_name, const char* new_name)
|
||||
{
|
||||
#if HAVE_LINUX_DEVICE
|
||||
static int fssnapshot_btrfs_rename(const char* parent_dir, const char* old_name, const char* new_name)
|
||||
{
|
||||
char old_path[PATH_MAX];
|
||||
char new_path[PATH_MAX];
|
||||
|
||||
|
|
@ -1625,7 +1828,46 @@ int fssnapshot_rename(const char* parent_dir, const char* old_name, const char*
|
|||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_LINUX_DEVICE
|
||||
static int fssnapshot_bcachefs_rename(const char* parent_dir, const char* old_name, const char* new_name)
|
||||
{
|
||||
char old_path[PATH_MAX];
|
||||
|
||||
pathcpy(old_path, sizeof(old_path), parent_dir);
|
||||
pathcatc(old_path, sizeof(old_path), '/');
|
||||
pathcat(old_path, sizeof(old_path), old_name);
|
||||
|
||||
if (fssnapshot_bcachefs_create(old_path, parent_dir, new_name) != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
if (fssnapshot_bcachefs_delete(parent_dir, old_name) != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int fssnapshot_rename(uint32_t magic, const char* parent_dir, const char* old_name, const char* new_name)
|
||||
{
|
||||
#if HAVE_LINUX_DEVICE
|
||||
if (magic == BTRFS_SUPER_MAGIC) {
|
||||
return fssnapshot_btrfs_rename(parent_dir, old_name, new_name);
|
||||
} else if (magic == BCACHEFS_SUPER_MAGIC) {
|
||||
return fssnapshot_bcachefs_rename(parent_dir, old_name, new_name);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
(void)magic;
|
||||
(void)parent_dir;
|
||||
(void)old_name;
|
||||
(void)new_name;
|
||||
|
|
|
|||
|
|
@ -1434,18 +1434,18 @@ When enabled, SnapRAID creates a read\-only snapshot of your data at the
|
|||
start of a \'sync\'. This ensures a consistent, point\-in\-time view of your
|
||||
files, preventing errors caused by concurrent file modifications.
|
||||
.PP
|
||||
This option applies exclusively to data disks formatted with the Btrfs
|
||||
filesystem. Parity disks, or data disks using other filesystems, will
|
||||
always use the live version of the filesystem.
|
||||
This option applies exclusively to data disks formatted with the
|
||||
Btrfs or Bcachefs filesystems. Parity disks, or data disks using
|
||||
other filesystems, will always use the live version of the filesystem.
|
||||
.PP
|
||||
This significantly improves recovery: if a file is deleted from the live
|
||||
filesystem, it remains preserved in the snapshot. This prevents the parity
|
||||
from becoming \[dq]broken\[dq] for that block, ensuring you can still successfully
|
||||
recover data if another disk fails.
|
||||
.PP
|
||||
Only Btrfs is supported. Snapshots are stored in a hidden \'.snapraid\'
|
||||
directory at the root of the Btrfs subvolume containing your data.
|
||||
SnapRAID will automatically detect the subvolume root for each data path.
|
||||
Snapshots are stored in a hidden \'.snapraid\' directory at the root
|
||||
of the subvolume containing your data. SnapRAID will automatically
|
||||
detect the subvolume root for each data path.
|
||||
.PP
|
||||
Snapshot creation and deletion require administrative privileges.
|
||||
Ensure SnapRAID is run with the necessary permissions (e.g., sudo) when
|
||||
|
|
@ -1833,7 +1833,9 @@ fix other failed disks.
|
|||
.PP
|
||||
Snapshots are created only for data disks and only if the underlying
|
||||
filesystem supports this functionality. Parity disks always use
|
||||
the live filesystem. At present, this is supported exclusively on Btrfs.
|
||||
the live filesystem.
|
||||
.PP
|
||||
At present, this is supported exclusively on Btrfs and Bcachefs.
|
||||
.PP
|
||||
You can mix data disks with different filesystems. Only those that
|
||||
support snapshots will utilize them, while other disks will continue
|
||||
|
|
|
|||
|
|
@ -1154,18 +1154,18 @@ Configuration
|
|||
start of a 'sync'. This ensures a consistent, point-in-time view of your
|
||||
files, preventing errors caused by concurrent file modifications.
|
||||
|
||||
This option applies exclusively to data disks formatted with the Btrfs
|
||||
filesystem. Parity disks, or data disks using other filesystems, will
|
||||
always use the live version of the filesystem.
|
||||
This option applies exclusively to data disks formatted with the
|
||||
Btrfs or Bcachefs filesystems. Parity disks, or data disks using
|
||||
other filesystems, will always use the live version of the filesystem.
|
||||
|
||||
This significantly improves recovery: if a file is deleted from the live
|
||||
filesystem, it remains preserved in the snapshot. This prevents the parity
|
||||
from becoming "broken" for that block, ensuring you can still successfully
|
||||
recover data if another disk fails.
|
||||
|
||||
Only Btrfs is supported. Snapshots are stored in a hidden '.snapraid'
|
||||
directory at the root of the Btrfs subvolume containing your data.
|
||||
SnapRAID will automatically detect the subvolume root for each data path.
|
||||
Snapshots are stored in a hidden '.snapraid' directory at the root
|
||||
of the subvolume containing your data. SnapRAID will automatically
|
||||
detect the subvolume root for each data path.
|
||||
|
||||
Snapshot creation and deletion require administrative privileges.
|
||||
Ensure SnapRAID is run with the necessary permissions (e.g., sudo) when
|
||||
|
|
@ -1445,7 +1445,9 @@ Snapshots
|
|||
|
||||
Snapshots are created only for data disks and only if the underlying
|
||||
filesystem supports this functionality. Parity disks always use
|
||||
the live filesystem. At present, this is supported exclusively on Btrfs.
|
||||
the live filesystem.
|
||||
|
||||
At present, this is supported exclusively on Btrfs and Bcachefs.
|
||||
|
||||
You can mix data disks with different filesystems. Only those that
|
||||
support snapshots will utilize them, while other disks will continue
|
||||
|
|
|
|||
|
|
@ -1232,18 +1232,18 @@ When enabled, SnapRAID creates a read-only snapshot of your data at the
|
|||
start of a 'sync'. This ensures a consistent, point-in-time view of your
|
||||
files, preventing errors caused by concurrent file modifications.
|
||||
|
||||
This option applies exclusively to data disks formatted with the Btrfs
|
||||
filesystem. Parity disks, or data disks using other filesystems, will
|
||||
always use the live version of the filesystem.
|
||||
This option applies exclusively to data disks formatted with the
|
||||
Btrfs or Bcachefs filesystems. Parity disks, or data disks using
|
||||
other filesystems, will always use the live version of the filesystem.
|
||||
|
||||
This significantly improves recovery: if a file is deleted from the live
|
||||
filesystem, it remains preserved in the snapshot. This prevents the parity
|
||||
from becoming "broken" for that block, ensuring you can still successfully
|
||||
recover data if another disk fails.
|
||||
|
||||
Only Btrfs is supported. Snapshots are stored in a hidden '.snapraid'
|
||||
directory at the root of the Btrfs subvolume containing your data.
|
||||
SnapRAID will automatically detect the subvolume root for each data path.
|
||||
Snapshots are stored in a hidden '.snapraid' directory at the root
|
||||
of the subvolume containing your data. SnapRAID will automatically
|
||||
detect the subvolume root for each data path.
|
||||
|
||||
Snapshot creation and deletion require administrative privileges.
|
||||
Ensure SnapRAID is run with the necessary permissions (e.g., sudo) when
|
||||
|
|
@ -1550,7 +1550,9 @@ Recovery - If a file is updated or deleted from the live filesystem,
|
|||
|
||||
Snapshots are created only for data disks and only if the underlying
|
||||
filesystem supports this functionality. Parity disks always use
|
||||
the live filesystem. At present, this is supported exclusively on Btrfs.
|
||||
the live filesystem.
|
||||
|
||||
At present, this is supported exclusively on Btrfs and Bcachefs.
|
||||
|
||||
You can mix data disks with different filesystems. Only those that
|
||||
support snapshots will utilize them, while other disks will continue
|
||||
|
|
|
|||
|
|
@ -50,18 +50,18 @@ extra boot /
|
|||
# start of a 'sync'. This ensures a consistent, point-in-time view of your
|
||||
# files, preventing errors caused by concurrent file modifications.
|
||||
#
|
||||
# This option applies exclusively to data disks formatted with the Btrfs
|
||||
# filesystem. Parity disks, or data disks using other filesystems, will
|
||||
# always use the live version of the filesystem.
|
||||
# This option applies exclusively to data disks formatted with the
|
||||
# Btrfs or Bcachefs filesystems. Parity disks, or data disks using
|
||||
# other filesystems, will always use the live version of the filesystem.
|
||||
#
|
||||
# This significantly improves recovery: if a file is deleted from the live
|
||||
# filesystem, it remains preserved in the snapshot. This prevents the parity
|
||||
# from becoming "broken" for that block, ensuring you can still successfully
|
||||
# recover data if another disk fails.
|
||||
#
|
||||
# Only Btrfs is supported. Snapshots are stored in a hidden '.snapraid'
|
||||
# directory at the root of the Btrfs subvolume containing your data.
|
||||
# SnapRAID will automatically detect the subvolume root for each data path.
|
||||
# Snapshots are stored in a hidden '.snapraid' directory at the root
|
||||
# of the subvolume containing your data. SnapRAID will automatically
|
||||
# detect the subvolume root for each data path.
|
||||
#
|
||||
# Snapshot creation and deletion require administrative privileges.
|
||||
# Ensure SnapRAID is run with the necessary permissions (e.g., sudo) when
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
blocksize 64
|
||||
parity bench/btrfs-parity
|
||||
content bench/btrfs-content
|
||||
content bench/btrfs-1-content
|
||||
disk btrfs1 bench/btrfs1/
|
||||
disk btrfs2 bench/btrfs2/
|
||||
disk btrfs3 bench/btrfs3/
|
||||
snapshot
|
||||
exclude .snapraid/
|
||||
9
test/test-snap.conf
Normal file
9
test/test-snap.conf
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
blocksize 64
|
||||
parity bench/snap-parity
|
||||
content bench/snap-content
|
||||
content bench/snap-1-content
|
||||
disk snap1 bench/snap1/
|
||||
disk snap2 bench/snap2/
|
||||
disk snap3 bench/snap3/
|
||||
snapshot
|
||||
exclude .snapraid/
|
||||
Loading…
Add table
Add a link
Reference in a new issue